; DATE.SBR
; VER 1.0 8608.12
;
;
;
; PROPRIETARY PROGRAM MATERIAL
;
; THIS MATERIAL IS THE PROPERTY OF JEFF STUYVESANT,
; 12307 PACIFIC AVE, APT 2,MAR VISTA, CALIF. ,90066
; PERMISSION TO COPY AND USE IS GRANTED FOR
; NON-PROFIT USES ONLY.
;
; Copyright (c) 1986 JEFF STUYVESANT
START: ; A3 POINTS TO BASE OF ARG LIST
CMPW @A3,#1 ; ONLY ONE ARG
JNE SBR.ERROR
CMP A.SIZE(A3),#10. ; 10 BYTES IN SIZE
JLO SBR.ERROR
MOV A.ADDR(A3),A3 ; GET ADDR OF VARIBLE
MOVW V.MODE(A3),D5 ; MOV MODE INTO D5
BEQ SBR.ERROR ; ERROR IF ZERO
CMPW D5,#5. ; IS IT MODE 5
JEQ MODE.5 ; BR TRUE
BHI SBR.ERROR ; ERROR IF GREATER
; PROCESS MODE 1 TO 4
GET.D V.DATE,D6 ; GET DATE'SEP
BEQ DATE.ERROR ; CANT BE ZERO
CALL $DTO.I ; CALC DATE TO INTERNAL
BEQ DATE.ERROR ; INVALID DATE IF Z FLAG
MOVW D7,V.LEAP(A3) ; SAVE LEAP'YEAR FLAG
CMPW D5,#4. ; IS IT MODE 4?
BEQ MODE.4 ; BR IF YES
; DATE ENTERED AS INTERNAL IN D6
MOV D6,D3
CALL DOW ; CALC DAY OF WEEK SAVE IN D3
CMPW D5,#2.
BLO EXIT ; LOW IS ONLY MODE 1
BEQ MODE.2 ; BR IF = MODE 2
; MUST BE MODE 3
MODE.3: ; SECOND DATE IN DATE'BASE
TST V.BASE(A3) ; BASE CANT=0
BEQ DATE.ERROR ; BR IF =
SAV.I V.INTL,D6 ; SAVE DATE AS DAYS
GET.D V.BASE,D6 ; GET DATE'BASE(AS DATE)
BEQ DATE.ERROR ; CANT BE ZERO
CALL $DTO.I ; CALC DATE TO INTERNAL
BEQ DATE.ERROR ; INVALID DATE IF Z FLAG
GET.I V.INTL,D7 ; GET DATE'SEP(AS'DAYS)
XCH D6,D7 ; SET INTO PROPER ORDER
; D6= DATE(AS DAYS [LARGER])
; D7= DATE'BASE(AS DAYS [SMALLER])
SUB.01: CMP D7,D6 ; COMPARE THE TWO DATES(AS DAYS)
BHI DATE.ERROR ; BR IF BASE > SEP.
SUB D7,D6 ; SEP-BASE= DIFFERENCE
; END OF PROGRAM
EXIT: SAV.I V.INTL,D6 ; SAVE DAYS
EXIT$: SAV.I V.BASE,D3 ; SAVE DOW
RTN
;MODE OR ARG IN ERROR
SBR.ERROR: MOV #0,V.INTL(A3) ; USED WHEN PARAMETERS
MOV #0,V.BASE(A3) ; ARE IN ERROR
SETW V.MODE(A3) ; MODE/#OF ARG ETC.
RTN
; DATA IN ERROR
DATE.ERROR: SET V.INTL(A3) ; USED WHEN VARIBLES ARE
SET V.BASE(A3) ; IN ERROR
SETW V.MODE(A3) ; DATE NOT DATE/ ETC
RTN
MODE.2: ; D6=DATE(AS DAYS)
; SUB DATE'BASE(AS DAYS) AND FINISH
GET.I V.BASE,D7 ; GET DATE'BASE(AS DAYS)
; D7= DATE(AS DAYS [LARGER])
; D6= DATE'BASE(AS DAYS [SMALLER])
GET.I V.BASE,D7 ; GET DATE'BASE(AS DATE)
ADD D7,D6 ; CALC NEW DAYS
MOV D6,D4 ; CALL USES D4
BR CALC.INTL ; CALC NEW DATE
MODE.5:
; GET D4 AS DAYS
; RETURN DATE
MOVW #0,V.MODE(A3) ; CLEAR MODE
GET.I V.DATE,D4 ; GET DATE(AS DAYS)
BEQ DATE.ERROR ; BR IF = 0
CALC.INTL:
MOV D4,D3 ; SET UP FOR DOW
CALL DOW ; CALC DAY OF WEEK
CALL $ITO.D ; CONVERT TO DATE
BEQ DATE.ERROR ; DAYS IN ERROR
SAV.D V.DATE,D6 ; SAVE IT AND FINISH
BR EXIT$
$ITO.D: ; D4 CONTAINS DAYS TO BE CONVERTED
SAVE D0-D2,A5
SUB #2351425.,D4 ; CORRECT FROM AM FORMAT
CMP D4,#0. ; CMP TO 0
JLOS NO.GOOD ; NO GOOD IF 0 OR LESS
MOV #146097.,D6 ; SET DIVISOR INTO D6
SUB #12.,SP ; GRAB SOME WORKSPACE
LEA A6,(SP) ; A6 TO POINT TO IT
FLTOF D6,@A6 ; CONVERT D6 TO FLOAT .
ADD #6.,A6 ; POINT TO NEW LOCATION
MOV D4,D6 ; GET DAYS TO CONVERT
ADD #364.,D6 ; CORRECTION OF 1 YR-1
FLTOF D6,@A6 ; CNVT TO FLOAT .
MOV SP,A5 ; SAVE SP
FDIV A5,A6 ; DIV THE NUMBERS
MOV A6,A5 ; GET BASE OF NUMBERS
FFTOL @A5,D6 ; CNVT FROM FLOAT .->D6
ADD #12.,SP ; RESET SP
INC D6 ; ADD ONE TO ANSWER
MOV D4,D0 ; SAVE IT
ADD #364.,D0 ; ADD CORRECTION 1 YR-1
SUB D6,D0 ; CALC DIFERENCE
MOV D0,D1 ; SAVE IT
P2: ; CALCULATION PART TWO
DIV D0,#36524. ; DIVIDE D0
AND #177777,D0 ; ELIMINATE REMAINDER
INC D0 ; ADD 1
ADD D0,D1 ; ADD TO SAVED NUMBER
MOV D1,D0 ; AND SAVE A COPY
P3: ; CALCULATION PART THREE
DIV D0,#1461. ; DIVIDE D0
AND #177777,D0 ; ELIMINATE REMAINDER
SUB D0,D1 ; SUB FROM SAVED NUMBER
P4: ; CALCULATION PART FOUR
DIV D1,#365. ; DIVIDE BY DAYS IN YEAR
AND #177777,D1 ; ELIMINATE REMAINDER
; D1 = YEAR
;@SP = #OF DAYS ENTERED
MOV D1,D6 ; SAVE YEAR
CALL CALC.D ; CALC # OF DAYS TO 01/00/YEAR
MOV D4,D1 ; SAVE DAYS
; D0 = # OF DAYS FROM 01/01/01 TO 01/00/YEAR
; D1 = # OF DAYS FROM 01/01/01 TO MO/DAY/YEAR
; D4 = " " " " "
; D6 = YEAR
; D7 = 1 FOR LEAP YEAR/ 0 IF NOT
SUB D0,D1 ; CALC DAYS
; D1 = # OF DAYS FROM 01/00/YEAR TO MO/DAY/YEAR
; D6 = YEAR
; D7 = 1 FOR LEAP YEAR/ 0 IF NOT
; DETERMINE MO AND DAY
MOVW #1,D0 ; SET MO POINTER
CLR D2 ; PRE-CLEAR
10$: MOVB EOM[~D0],D2 ; GET DAYS IN MONTH (D0)
CMPW D0,#2 ; IS IF FEBUARY
BNE 15$ ; BR IF NOT
ADDB D7,D2 ; YES ADD D7= LEAP YEAR
15$: CMPW D1,D2 ; CMP DAYS TO DATE TO EOM
BLOS 20$ ; IF LESS WE FOUND IT
SUBW D2,D1 ; SUB DAYS IN MO FROM DAYS TO DATE
INCW D0 ; INC MO POINTER
BR 10$ ; TRY AGAIN
; DATE FOUND PACKIT WITH YEAR
20$:
; D0 = MONTH
; D1 = DAY
; D6 = YEAR
LSLW D1,#8. ; SHIFT LEFT EIGHT BITS
MOVB D0,D1 ; SET LOWER BYTE =MO
; D1.W = MO/DAY
MOV #16.,D2 ; SET COUNTER
ROL D6,D2 ; ROLL LEFT 16 BITS
MOVW D1,D6 ; SET LOW WORD=MO/DAY
ROR D6,D2 ; ROLL RIGHT 16 BITS
JMP FIN ; ALL DONE
; D6 = MO/DAY/YEAR
; LIST OF DAYS IN MONTH
EOM: BYTE 0,31.,28.,31.,30.,31.,30.,31.,31.,30.,31.,30.,31.
EVEN
$DTO.I: ; ENTER D6= DATE IN SEP FORMAT (NOT AM STANDARD)
SAVE D0-D2,A5 ; SAVE REGISTERS
CMPW D6,#10000. ; YEAR MAX IS 10,000 DECIMAL
BHI DATE.NO.GOOD ; BR IF NO GOOD
CALL CALC.D ; CALC DAYS TO 01/00/YEAR
; D0=NUMBER OF DAYS TO FIRST OF YEAR -1
; D7= LEAP YEAR 1=YES 0=NO
MO.VER: ; VERIFY MONTH
SWAP D6 ; GET MONTH IN LOWER BYTE
CMPB D6,#12. ; CHECK WITH 12 MONTHS
BHI DATE.NO.GOOD ; IF HI NO GOOD
; CALC UP TO MONTH
CLR D2 ; PRE-CLEAR
MOV #1,D1 ; SET MONTH POINTER
10$:
CMPB D1,D6 ; AT MONTH YET
BEQ DAY.VER ; BR IF YES
MOVB EOM[~D1],D2 ; NO GET DAYS IN MONTH PRIOR
ADD D2,D0 ; ADD TO CUMULATIVE
INCB D1 ; INC MO POINTER
BR 10$ ; BR AGAIN
DAY.VER: ; VERIFY DAY GIVEN
ROLW D6,#8. ; ROLL WORD LEFT 8 BITS
CMPB D6,EOM[~D1] ; CMP DAYS IN MO TO PASSED
BHI 20$ ; BR IF HI MAYBE NO GOOD
MOVB D6,D2 ; SET D2=PASSED VALUE
ADD D2,D0 ; ADDIT TO CUMLUATIVE
CMPB D7,#1 ; LEAP YEAR ?
BNE 10$ ; BR IF NOT
CMPB D1,#2 ; PAST FEBUARY
BLOS 10$ ; BR IF NOT
ADD #1,D0 ; INC CUMULATIVE
; ALL DONE
10$:
BR FINISH
; DAYS PAST MAY BE TOO HIGH
20$:
CMPB D1,#2 ; MO PASSED FEBUARY
BNE DATE.NO.GOOD ; BR IF NOT
CMPB D7,#1 ; THIS A LEAP YEAR
BNE DATE.NO.GOOD ; BR IF NOT
CMPB D6,#29. ; ONLY #29 ALLOWED
BNE DATE.NO.GOOD ; BR IF NOT
ADD #29.,D0 ; INC D0 BY 29 DAYS
; ALL DONE
FINISH:
MOV D0,D6 ; RESET D6
ADD #2351425.,D6 ; CORRECT TO AM FORMAT
REST D0-D2,A5 ; REST REGISTERS
RTN ; GO BACK
; CALC DAYS IN YEAR
; D6= YEAR PASSED
CALC.D: CLR D7 ; PRE-CLEAR
CLR D0 ; PRE-CLEAR
DECW D6 ; SUB 1 FROM YEAR PASSED
MOVW D6,D0 ; SAVE IT
MUL D0,#365. ; MUL BY 365 DAYS A YEAR
CLR D1 ; PRE-CLEAR
MOVW D6,D1 ; GET YEAR
DIV D1,#4. ; DIV BY 4 = # OF LEAP YEARS
AND #177777,D1 ; ELIMINATE REMAINDER
ADD D1,D0 ; ADD TO CUMULATIVE
MOVW D6,D1 ; GET YEAR
DIV D1,#100. ; CHECK FOR 100 YEAR EXCEPTIONS
AND #177777,D1 ; ELIMINATE REMAINDER
SUB D1,D0 ; SUB FROM CUMULATIVE
MOVW D6,D1 ; GET YEAR
DIV D1,#400. ; CHECK FOR 400 YEAR EXCEPTIONS
AND #177777,D1 ; ELIMINATE REMAINDER
ADD D1,D0 ; ADD TO CUMULATIVE
LEAP.YEAR: INCW D6 ; RESET TO ORIGINAL YEAR PASSED
CLR D1 ; PRE-CLEAR
MOVW D6,D1 ; GET YEAR
DIV D1,#4. ; DIV BY 4 (PER LEAP YEAR CYCLE)
SWAP D1 ; GET REMAINDER
TSTW D1 ; CHECK FOR ZERO
BNE 30$ ; BR IF NOT
MOVB #1,D7 ; SET LOW BYTE TO 1 - FLAG YES
10$: ; CHECK FOR 100 YEAR EXCEPTION
CLR D1 ; PRE-CLEAR
MOVW D6,D1 ; GET YEAR
DIV D1,#100. ; DIV BY 100 (CYCLE)
SWAP D1 ; GET REMAINDER
TSTW D1 ; IS IT ZERO
BNE 30$ ; BR IF NOT
CLRB D7 ; YES SO UN SET FLAG
20$: ; CHECK FOR 400 YEAR EXCEPTION
CLR D1 ; PRE-CLEAR
MOVW D6,D1 ; GET YEAR
DIV D1,#400. ; DIV BY 400 (CYCLE)
SWAP D1 ; GET REMAINDER
TSTW D1 ; IS IT ZERO
BNE 30$ ; BR IF NOT
MOVB #1,D7 ; YES SET FLAG
30$: RTN ; ALL DONE
;CALC DAY OF WEEK
; D3=DATE AS DAYS
DOW:
MOV D3,D2
; SAVE DAYS
; ADJUST DAYS DIV HAS MAX LIMIT
DIV D2,#343. ; DIV LARGE NUMBER DIV BY 7
AND #177777,D2 ; ELIMINATE REMAINDER
BEQ 10$ ; CONT IF NO QUO
MUL D2,#343. ; MUST ADJUST CALC D2*343.
SUB D2,D3 ; SUB FROM PASED NUMBER
10$:
DIV D3,#7. ; CALC MODULO 7
SWAP D3 ; GET REMAINDER
AND #177777,D3 ; STRIP QUO
RTN ; D3= DOW