summaryrefslogtreecommitdiff
path: root/v4.0/src/DOS/TIME.ASM
blob: 0d3895c028c801b8e5a7561fe36252bf33e1b888 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
;	SCCSID = @(#)time.asm	1.1 85/04/10
TITLE	TIME - time and date functions
NAME	TIME
;
; System Calls and low level routines for DATE and TIME
;
;   $GET_DATE
;   $SET_DATE
;   $GET_TIME
;   $SET_TIME
;   DATE16
;   READTIME
;   DSLIDE
;   SETYEAR
;   DODATE
;   DSUM
;
;   Modification history:
;
;	Created: ARR 30 March 1983
;

.xlist
;
; get the appropriate segment definitions
;
include dosseg.asm

CODE	    SEGMENT BYTE PUBLIC  'CODE'
	ASSUME	SS:DOSGROUP,CS:DOSGROUP

.xcref
INCLUDE DOSSYM.INC
INCLUDE DEVSYM.INC
.cref
.list


    i_need  DAY,BYTE
    i_need  MONTH,BYTE
    i_need  YEAR,WORD
    i_need  WEEKDAY,BYTE
    i_need  TIMEBUF,6
    i_need  BCLOCK,DWORD
    i_need  DAYCNT,WORD
    i_need  YRTAB,8
    i_need  MONTAB,12
    i_need  DATE_FLAG,WORD

    FOURYEARS = 3*365 + 366

SUBTTL DATE AND TIME - SYSTEM CALLS 42,43,44,45
PAGE
	procedure   $GET_DATE,NEAR
ASSUME	DS:NOTHING,ES:NOTHING

; Inputs:
;	None
; Function:
;	Return current date
; Returns:
;	Date in CX:DX

	Context DS
	CALL	READTIME		;Check for rollover to next day
	MOV	AX,[YEAR]
;
; WARNING!!!! DAY and MONTH must be adjacently allocated!
;
	MOV	BX,WORD PTR [DAY]	; fetch both day and month
	invoke	get_user_stack		;Get pointer to user registers
ASSUME	DS:NOTHING
	MOV	[SI.user_DX],BX 	;DH=month, DL=day
	ADD	AX,1980 		;Put bias back
	MOV	[SI.user_CX],AX 	;CX=year
	MOV	AL,BYTE PTR [WEEKDAY]
	return
EndProc $GET_DATE

	procedure   $SET_DATE,NEAR	;System call 43
ASSUME	DS:NOTHING,ES:NOTHING

; Inputs:
;	CX:DX valid date
; Function:
;	Set current date
; Returns:
;	AL = -1 date bad, = 0 OK

	MOV	AL,-1			;Be ready to flag error
	SUB	CX,1980 		;Fix bias in year
	retc				;Error if not big enough
	CMP	CX,119			;Year must be less than 2100
	JA	RET24
	OR	DH,DH
	retz
	OR	DL,DL
	retz				;Error if either month or day is 0
	CMP	DH,12			;Check against max. month
	JA	RET24
	Context DS
	invoke	DODATE
RET24:	return
EndProc $SET_DATE

	procedure   $GET_TIME,NEAR	;System call 44
ASSUME	DS:NOTHING,ES:NOTHING

; Inputs:
;	None
; Function:
;	Get current time
; Returns:
;	Time in CX:DX

	Context DS
	CALL	READTIME
	invoke	get_user_stack		;Get pointer to user registers
	MOV	[SI.user_DX],DX
	MOV	[SI.user_CX],CX
	XOR	AL,AL
RET26:	return
EndProc $GET_TIME

	procedure   $SET_TIME,NEAR	;System call 45
ASSUME	DS:NOTHING,ES:NOTHING

; Inputs:
;	CX:DX = Time
; Function:
;	Set time
; Returns:
;	AL = -1 time bad, = 0 OK

	MOV	AL,-1			;Flag in case of error
	CMP	CH,24			;Check hours
	JAE	RET26
	CMP	CL,60			;Check minutes
	JAE	RET26
	CMP	DH,60			;Check seconds
	JAE	RET26
	CMP	DL,100			;Check 1/100's
	JAE	RET26
	PUSH	CX
	PUSH	DX
	Context DS
	MOV	BX,OFFSET DOSGROUP:TIMEBUF
	MOV	CX,6
	XOR	DX,DX
	MOV	AX,DX
	PUSH	BX
	invoke	SETREAD
	DOSAssume   CS,<ES>,"TIME/SetRead"
	PUSH	DS
	LDS	SI,[BCLOCK]
ASSUME	DS:NOTHING
	invoke	DEVIOCALL2		;Get correct day count
	POP	DS
	DOSAssume   CS,<DS>,"TIME/DevIOCall2"
	POP	BX
	invoke	SETWRITE
	POP	WORD PTR [TIMEBUF+4]
	POP	WORD PTR [TIMEBUF+2]
	LDS	SI,[BCLOCK]
ASSUME	DS:NOTHING
	invoke	DEVIOCALL2		;Set the time
	XOR	AL,AL
	return
EndProc $SET_TIME

SUBTTL DATE16, READTIME, DODATE -- GUTS OF TIME AND DATE
PAGE

;
; Date16 returns the current date in AX, current time in DX
;   AX - YYYYYYYMMMMDDDDD  years months days
;   DX - HHHHHMMMMMMSSSSS  hours minutes seconds/2
;
; DS = DOSGROUP on output

procedure   DATE16,NEAR
	Context DS
	ASSUME	ES:NOTHING
	PUSH	CX
	PUSH	ES
	CALL	READTIME
	POP	ES
	SHL	CL,1			;Minutes to left part of byte
	SHL	CL,1
	SHL	CX,1			;Push hours and minutes to left end
	SHL	CX,1
	SHL	CX,1
	SHR	DH,1			;Count every two seconds
	OR	CL,DH			;Combine seconds with hours and minutes
	MOV	DX,CX
;
; WARNING!  MONTH and YEAR must be adjacently allocated
;
	MOV	AX,WORD PTR [MONTH]	;Fetch month and year
	MOV	CL,4
	SHL	AL,CL			;Push month to left to make room for day
	SHL	AX,1
	POP	CX
	OR	AL,[DAY]
	return
EndProc DATE16

;Gets time in CX:DX. Figures new date if it has changed.
;Uses AX, CX, DX.

	procedure   READTIME,NEAR
	DOSAssume   CS,<DS>,"ReadTime"
	ASSUME	ES:NOTHING

	MOV	[DATE_FLAG],0		; reset date flag for CPMIO
	PUSH	SI
	PUSH	BX
	MOV	BX,OFFSET DOSGROUP:TIMEBUF
	MOV	CX,6
	XOR	DX,DX
	MOV	AX,DX
	invoke	SETREAD
	PUSH	DS
	LDS	SI,[BCLOCK]
ASSUME	DS:NOTHING
	invoke	DEVIOCALL2		;Get correct date and time
	POP	DS
	DOSAssume   CS,<DS>,"ReadTime/DevIOCall2"
	POP	BX
	POP	SI
	MOV	AX,WORD PTR [TIMEBUF]
	MOV	CX,WORD PTR [TIMEBUF+2]
	MOV	DX,WORD PTR [TIMEBUF+4]
	CMP	AX,[DAYCNT]		;See if day count is the same
	retz
	CMP	AX,FOURYEARS*30 	;Number of days in 120 years
	JAE	RET22			;Ignore if too large
	MOV	[DAYCNT],AX
	PUSH	SI
	PUSH	CX
	PUSH	DX			;Save time
	XOR	DX,DX
	MOV	CX,FOURYEARS		;Number of days in 4 years
	DIV	CX			;Compute number of 4-year units
	SHL	AX,1
	SHL	AX,1
	SHL	AX,1			;Multiply by 8 (no. of half-years)
	MOV	CX,AX			;<240 implies AH=0
	MOV	SI,OFFSET DOSGROUP:YRTAB;Table of days in each year
	CALL	DSLIDE			;Find out which of four years we're in
	SHR	CX,1			;Convert half-years to whole years
	JNC	SK			;Extra half-year?
	ADD	DX,200
SK:
	CALL	SETYEAR
	MOV	CL,1			;At least at first month in year
	MOV	SI,OFFSET DOSGROUP:MONTAB   ;Table of days in each month
	CALL	DSLIDE			;Find out which month we're in
	MOV	[MONTH],CL
	INC	DX			;Remainder is day of month (start with one)
	MOV	[DAY],DL
	CALL	WKDAY			;Set day of week
	POP	DX
	POP	CX
	POP	SI
RET22:	return
EndProc READTIME

	procedure   DSLIDE,NEAR
	MOV	AH,0
DSLIDE1:
	LODSB				;Get count of days
	CMP	DX,AX			;See if it will fit
	retc				;If not, done
	SUB	DX,AX
	INC	CX			;Count one more month/year
	JMP	SHORT DSLIDE1
EndProc DSLIDE

	procedure   SETYEAR,NEAR
;Set year with value in CX. Adjust length of February for this year.
	MOV	BYTE PTR [YEAR],CL

CHKYR:
	TEST	CL,3			;Check for leap year
	MOV	AL,28
	JNZ	SAVFEB			;28 days if no leap year
	INC	AL			;Add leap day
SAVFEB:
	MOV	[MONTAB+1],AL		;Store for February
RET23:	return
EndProc SETYEAR

	procedure   DODATE,NEAR
	DOSAssume   CS,<DS>,"DoDate"
	ASSUME	ES:NOTHING
	CALL	CHKYR			;Set Feb. up for new year
	MOV	AL,DH
	MOV	BX,OFFSET DOSGROUP:MONTAB-1
	XLAT				;Look up days in month
	CMP	AL,DL
	MOV	AL,-1			;Restore error flag, just in case
	retc				;Error if too many days
	CALL	SETYEAR
;
; WARNING!  DAY and MONTH must be adjacently allocated
;
	MOV	WORD PTR [DAY],DX	;Set both day and month
	SHR	CX,1
	SHR	CX,1
	MOV	AX,FOURYEARS
	MOV	BX,DX
	MUL	CX
	MOV	CL,BYTE PTR [YEAR]
	AND	CL,3
	MOV	SI,OFFSET DOSGROUP:YRTAB
	MOV	DX,AX
	SHL	CX,1			;Two entries per year, so double count
	CALL	DSUM			;Add up the days in each year
	MOV	CL,BH			;Month of year
	MOV	SI,OFFSET DOSGROUP:MONTAB
	DEC	CX			;Account for months starting with one
	CALL	DSUM			;Add up days in each month
	MOV	CL,BL			;Day of month
	DEC	CX			;Account for days starting with one
	ADD	DX,CX			;Add in to day total
	XCHG	AX,DX			;Get day count in AX
	MOV	[DAYCNT],AX
	PUSH	SI
	PUSH	BX
	PUSH	AX
	MOV	BX,OFFSET DOSGROUP:TIMEBUF
	MOV	CX,6
	XOR	DX,DX
	MOV	AX,DX
	PUSH	BX
	invoke	SETREAD
	DOSAssume   CS,<ES>,"DoDate/SetRead"
	PUSH	DS
	LDS	SI,[BCLOCK]
ASSUME	DS:NOTHING
	invoke	DEVIOCALL2		;Get correct date and time
	POP	DS
	POP	BX
	DOSAssume   CS,<DS>,"DoDate/DevIOCall2"
	invoke	SETWRITE
	POP	WORD PTR [TIMEBUF]
	PUSH	DS
	LDS	SI,[BCLOCK]
ASSUME	DS:NOTHING
	invoke	DEVIOCALL2		;Set the date
	POP	DS
	DOSAssume   CS,<DS>,"DoDate/DevIOCall2(second)"
	POP	BX
	POP	SI
WKDAY:
	MOV	AX,[DAYCNT]
	XOR	DX,DX
	MOV	CX,7
	INC	AX
	INC	AX			;First day was Tuesday
	DIV	CX			;Compute day of week
	MOV	[WEEKDAY],DL
	XOR	AL,AL			;Flag OK
Ret25:	return
EndProc DODATE

	procedure   DSUM,NEAR
	MOV	AH,0
	JCXZ	RET25
DSUM1:
	LODSB
	ADD	DX,AX
	LOOP	DSUM1
	return
EndProc DSUM

CODE	     ENDS
    END