| Well, I've gotten somewhere from the IXP angle. Here is what I have.
Now my major problem is that IXP doesn't seem to deal well with the
kind of negative number generated by calling $BINTIM with a delta time.
------
sample output:
time sample : 7-DEC-1984 14:01:20.92
value : 39779928809200000
delta time : 17-NOV-1858 00:10:00.00
value : 6000000000
result time : 7-DEC-1984 14:11:20.92
value : 39779934809200000
------
program listing:
[INHERIT ('SYS$LIBRARY:STARLET')]
{
The point of this program is to work out the details of using
ixp to add, subtract & compare vax-format dates & times.
So far it all works, except that the ixp representation of
a delta time doesn't come out right. It looks like a very
large number instead of a reasonably sized negative number.
The reason I'm doing this is to eventually develop a generalized
set of routines for adding, subtracting and comparing dates.
Eventually, I'd like to replace the IXP calls with calls to
macro routines that would use hardware instructions to add,
subtract and compare quadwords. Until then, I have to get
this working so I can go ahead with the program.
This is strictly a midnight hack.
-Jeff RDVAX:: Dickens
}
PROGRAM TESTIXP(input,output);
%INCLUDE 'SYS$LIBRARY:PASSTATUS.PAS/NOLIST'
TYPE
$BYTE = [BYTE] -128..127;
$WORD = [WORD] -32768..32767;
$QUAD = [QUAD,UNSAFE] RECORD
L0:UNSIGNED; L1:INTEGER; END;
$OCTA = [OCTA,UNSAFE] RECORD
L0,L1,L2:UNSIGNED; L3:INTEGER; END;
$UBYTE = [BYTE] 0..255;
$UWORD = [WORD] 0..65535;
$UQUAD = [QUAD,UNSAFE] RECORD
L0,L1:UNSIGNED; END;
$UOCTA = [OCTA,UNSAFE] RECORD
L0,L1,L2,L3:UNSIGNED; END;
timbuf_type = PACKED ARRAY [1..23] OF CHAR;
{String to buffer ascii time in}
VAX_DESC = [ALIGNED(2)] RECORD {for IXP arithmetic}
DSC$W_LENGTH : $WORD;
DSC$B_DTYPE : $BYTE;
DSC$B_CLASS : $BYTE;
DSC$A_POINTER: [UNSAFE] UNSIGNED;
END;
IXP_DESC = [ALIGNED(2)] RECORD {for IXP arithmetic}
LENGTH : $UWORD;
MBZ : [POS(16), BIT(15)] 0..32767;
SIGN : [POS(31), BIT] 0..1;
DATE : [POS(32)] $QUAD;
END;
VAR
length : $UWORD;
{length for IXP$CVTXA calls}
value_str : [volatile] PACKED ARRAY [1..80] OF CHAR;
{buffer for IXP$CVTXA calls}
time_sample, delta_time, result_time
,ixp_value :
[VOLATILE]VAX_DESC;
{ixp date descriptors}
time_sample_ixp, delta_time_ixp, result_time_ixp :
[VOLATILE]IXP_DESC;
{ixp dates themselves}
status : INTEGER;
{status return for external calls}
time_buffer : timbuf_type;
{String to buffer ascii time in}
[EXTERNAL, ASYNCHRONOUS] PROCEDURE LIB$SIGNAL
(%IMMED Condition : UNSIGNED;
%IMMED FAO_Params : [LIST, UNSAFE] INTEGER := %IMMED 0);
EXTERNAL;
{* The IXP package is used for date (quadword) arithmetic. Information and
objects for the package are available at AURORA::IXP.* *}
[EXTERNAL] FUNCTION IXP$MULXN
(MULR : VAX_DESC;
MULD : VAX_DESC;
PROD : VAX_DESC) :
INTEGER;
EXTERNAL;
[EXTERNAL] FUNCTION IXP$CVTLX
(FROM_INT : INTEGER;
TO_IXP : VAX_DESC) :
INTEGER;
EXTERNAL;
[EXTERNAL] FUNCTION IXP$CVTXA
(NUMBER_IXP : VAX_DESC;
BUFFER : VAX_DESC;
VAR LENGTH : $UWORD) :
INTEGER;
EXTERNAL;
[EXTERNAL] FUNCTION IXP$ADDXN
(ADD1 : VAX_DESC;
ADD2 : VAX_DESC;
SUM : VAX_DESC) :
INTEGER;
EXTERNAL;
[EXTERNAL] FUNCTION IXP$SUBXN
(ADD1 : VAX_DESC;
ADD2 : VAX_DESC;
SUM : VAX_DESC) :
INTEGER;
EXTERNAL;
BEGIN
ixp_value.DSC$W_LENGTH := 80;
ixp_value.DSC$A_POINTER := ADDRESS(value_str);
{set up descriptor for buffer for ixp$cvtxa calls}
time_sample.DSC$W_LENGTH := 12;
time_sample.DSC$A_POINTER := ADDRESS(time_sample_ixp);
time_sample_ixp.LENGTH := 8;
time_sample_ixp.MBZ := 0;
time_sample_ixp.SIGN := 0;
{init ixp & descriptor for time_sample}
delta_time.DSC$W_LENGTH := 12;
delta_time.DSC$A_POINTER := ADDRESS(delta_time_ixp);
delta_time_ixp.LENGTH := 8;
delta_time_ixp.MBZ := 0;
delta_time_ixp.SIGN := 0;
{init ixp & descriptor for delta_time}
result_time.DSC$W_LENGTH := 12;
result_time.DSC$A_POINTER := ADDRESS(result_time_ixp);
result_time_ixp.LENGTH := 8;
result_time_ixp.MBZ := 0;
result_time_ixp.SIGN := 0;
{init ixp & descriptor for result_time}
status := $GETTIM(time_sample_ixp.DATE); {get current time}
time_buffer := ' '; {clear buffer}
status := $ASCTIM(,time_buffer,time_sample_ixp.DATE); {convert to ascii}
WRITELN('time sample : ',time_buffer); {print ascii date}
status := IXP$CVTXA(time_sample,ixp_value,length); {convert ixp xn to ascii}
WRITELN('value : ',value_str:length); {print ixp value}
{
Note that here I found that I couldn't deal with IXP version
of a delta time, because it's twos complement negative and came
out looking like a very large number. Instead I cheated and
used an absolute time that translated into 10 minutes worth of
clicks.
I'd like to find out how to get a delta time to look like a
negative ixp number, so that I can deal with it with the IXP
routines.
}
status := $BINTIM('17-NOV-1858 00:10:00.0',delta_time_ixp.DATE); {same as above}
time_buffer := ' '; {...}
status := $ASCTIM(,time_buffer,delta_time_ixp.DATE);
WRITELN('delta time : ',time_buffer);
status := IXP$CVTXA(delta_time,ixp_value,length);
WRITELN('value : ',value_str:length);
status := IXP$ADDXN(time_sample,delta_time,result_time); {add the two}
IF NOT ODD(STATUS) THEN LIB$SIGNAL(STATUS);
time_buffer := ' ';
status := $ASCTIM(,time_buffer,result_time_ixp.DATE); {and print the result}
WRITELN('result time : ',time_buffer);
status := IXP$CVTXA(result_time,ixp_value,length);
WRITELN('value : ',value_str:length);
END.
------
here is the sample output again, for convenience:
time sample : 7-DEC-1984 14:01:20.92
value : 39779928809200000
delta time : 17-NOV-1858 00:10:00.00
value : 6000000000
result time : 7-DEC-1984 14:11:20.92
value : 39779934809200000
Thanks, everyone for your help, especially Richard Kittell.
-Jeff
|
| I made the following changes to a copy of my test program to illustrate
the problem. The ixp variable delta_time now gets a real delta time assigned
to it, and it can't handle it.
************
File SYS$SYSDEVICE:[DICKENS]TESTIXP.PAS;20
171 status := $BINTIM('17-NOV-1858 00:10:00.0',delta_time_ixp.DATE); {same as above}
172 time_buffer := ' '; {...}
******
File SYS$SYSDEVICE:[DICKENS]TESTIXP1.PAS;2
171 status := $BINTIM('0 00:10:00.00',delta_time_ixp.DATE); {same as above}
172 time_buffer := ' '; {...}
************
Number of difference sections found: 1
Number of difference records found: 1
DIFFERENCES /IGNORE=()/MERGED=1/OUTPUT=SYS$SYSDEVICE:[DICKENS]TESTIXP1.DIF;1-
SYS$SYSDEVICE:[DICKENS]TESTIXP.PAS;20-
SYS$SYSDEVICE:[DICKENS]TESTIXP1.PAS;2
Here is the output from the modified program:
time sample : 7-DEC-1984 16:45:51.92
value : 39780027519200000
delta time : 0 00:10:00.00
value : 18446744067709551616
----
At this point the program bombs out when IXP$ADDXN returns SS$INTOVF,
an integer overflow error trying to add the two values above inside
a quadword. I couldn't figure out how to redirect the error output,
but it didn't show much anyway.
The value of 'delta time` above should equal -600000000 or something
like that, not a 20 digit positive integer. Does anyone see what
I'm doing wrong ?
Thanks again,
-Jeff
|
| Problem solved. Thanks for all your help. :-)
I seems I was overlooking the obvious. I was reading the
run time library reference manual on the RTL routines LIB$ADDX and
LIB$SUBX and found that they take the longword address of an array
of longwords as arguments. The default length of the arrays is 2,
a quad. I took a lucky guess that the internal representation of
an array of two longwords is the same as the record definition for
$QUAD that I got from STARLET. It seems it was. Here's a demo
program:
************************************************************************
[INHERIT ('SYS$LIBRARY:STARLET')]
PROGRAM TEST_TIME(input,output);
TYPE
$QUAD = [QUAD,UNSAFE] RECORD
L0:UNSIGNED; L1:INTEGER; END;
timbuf_type = PACKED ARRAY [1..23] OF CHAR;
VAR
time_sample, time_sample1, sum : $QUAD;
status : INTEGER;
time_buffer : timbuf_type;
FUNCTION LIB$ADDX(a,b,s : $QUAD ):INTEGER;EXTERNAL;
FUNCTION LIB$SUBX(a,b,s : $QUAD ):INTEGER;EXTERNAL;
BEGIN
status := $GETTIM(time_sample);
status := $ASCTIM(,time_buffer,time_sample);
WRITELN(time_buffer);
status := $BINTIM('0 00:10:00.00',time_sample1);
time_buffer := ' ';
status := $ASCTIM(,time_buffer,time_sample1);
WRITELN(time_buffer);
status := LIB$SUBX(time_sample,time_sample1,sum);
status := $ASCTIM(,time_buffer,sum);
WRITELN(time_buffer);
END.
************************************************************************
Here's the output:
18-DEC-1984 22:06:56.30
0 00:10:00.00
18-DEC-1984 22:16:56.30
************************************************************************
|