.TITLE JULIAN
.IDENT /MAC/
;SUBROUTINE TO CALCULATE JULIAN DATE FROM YEAR, MONTH, DAY
;
;WRITTEN BY: E. NICHOLAS CUPERY 03 FEBRUARY 1976
;SUBROUTINE JULIAN IS REENTRANT, AND PRESERVES ALL REGISTERS
;SUBROUTINE JULIAN REQUIRES FIVE WORDS OF STACK SPACE
;SUBROUTINE JULIAN OCCUPIES 76. WORDS OF MEMORY
;FORTRAN CALL: "CALL JULIAN(NYEAR,NMONTH,NDAY,NANSER,NSTAT)"
;
;THIS FORTRAN CALL WILL CAUSE A "JSR PC, JULIAN"
;WITH R5 POINTING AT A 6-WORD BLOCK DESCRIBED BELOW:
;
;
;1ST WORD CONTAINS THE NUMBER OF ARGUMENTS (MUST BE FIVE)
;IN THE LOW-BYTE, AND GARBAGE IN THE HIGH-BYTE.
;
;2ND WORD CONTAINS THE ADDRESS OF THE YEAR (SINCE 1900)
;INFORMATION ("NYEAR"), WHICH MUST BE A ONE-WORD INTEGER.
;
;3RD WORD CONTAINS THE ADDRESS OF THE MONTH
;INFORMATION ("NMONTH"), WHICH MUST BE A ONE-WORD INTEGER.
;
;4TH WORD CONTAINS THE ADDRESS OF THE DAY
;INFORMATION ("NDAY"), WHICH MUST BE A ONE-WORD INTEGER.
;
;5TH WORD CONTAINS THE ADDRESS OF THE ONE-WORD INTEGER LOCATION
;("NANSER") IN WHICH THE JULIAN DATE (ANSWER) IS TO BE PLACED.
;
;6TH WORD CONTAINS THE ADDRESS OF THE ONE-WORD INTEGER
;LOCATION ("NSTAT") IN WHICH THE RETURN STATUS IS TO BE PLACED.
;NOTES: ;THE NUMBER OF ARGUMENTS MUST BE FIVE.
;
;A RETURN STATUS OF +1 INDICATES SUCCESS.
;A RETURN STATUS OF -1 INDICATES FAILURE.
;
;THE YEAR MUST BE RELATIVE TO 1900 (EX: 5 FOR THE YEAR 1905)
;THE ALGORITHM USED TO LOOK FOR LEAP-YEARS WORKS
;ONLY FOR CALENDAR YEARS BETWEEN 1901 AND 2099 INCLUSIVE.
;(WHICH MEANS THE "YEAR" INPUT MUST BE BETWEEN 1 AND
;199. INCLUSIVE).
;
;THE MONTH MUST BE BETWEEN 1 AND 12. INCLUSIVE.
;
;THE DAY MUST BE BETWEEN 1 AND THE MAXIMUM
;NUMBER OF DAYS IN THE PARTICULAR MONTH INPUT.
;
;THE CURRENT MONTH, DAY, AND YEAR CAN BE GOTTEN FROM THE FORTRAN
;"IDATE" SUBROUTINE (SEE PAGE B-4 OF FORTRAN USER'S GUIDE).
;ASSEMBLY LANGUAGE CALL: ;CALLS TO SUBROUTINE JULIAN FROM ASSEMBLY
;LANGUAGE PROGRAMS MUST "LOOK LIKE" THE FORTRAN CALL
;DESCRIBED ABOVE. HOWEVER, THE ASSEMBLY LANGUAGE
;CALLER WILL PROBABLY WISH TO MAKE USE OF THE
;FACT THAT "JULIAN" WILL CLEAR THE C-BIT ON
;SUCCESSFUL RETURNS, AND SET THE C-BIT ON FAILURES.
;
;NOTE: THE CURRENT MONTH, DAY, AND YEAR CAN BE GOTTEN VIA THE
;"GTIM$" DIRECTIVE (SEE PAGE 2-23 OF EXEC REFERENCE MANUAL).
;THE GENERAL REGISTERS ARE USED WITHIN THIS SUBROUTINE AS FOLLOWS:
;
;R0 HOLDS DAY-OF-THE-MONTH INFORMATION
;R1 HOLDS THE MONTH-OF-THE-YEAR INFORMATION
;R2 HOLDS THE YEAR INFORMATION
;R3 IS NOT USED
;R4 IS NOT USED
;R5 IS USED AS A POINTER TO ARGUMENT ADDRESSES
;
;END OF GENERAL REGISTER USAGE DESCRIPTION
JULIAN::MOV R0,-(SP) ;SAVE R0
MOV R1,-(SP) ;SAVE R1
MOV R2,-(SP) ;SAVE R2
MOV R5,-(SP) ;SAVE R5
MOV #-1,@12(R5) ;ASSUME ERROR (STATUS=-1)
CMPB #5, (R5)+ ;EXACTLY FIVE ARGUMENTS?
BNE ERROR ;ANYTHING BUT FIVE IS AN ERROR
TSTB (R5)+ ;POINT PAST "GARBAGE" BYTE
MOV @(R5)+,R2 ;YEAR SINCE 1900
BLE ERROR ;ERROR IF YEAR 1900 OR PREVIOUS
CMP #200., R2 ;LESS THAN YEAR 2100?
BLE ERROR ;ERROR IF YEAR 2100 OR GREATER
;WILL NOW SEE IF YEAR IN R2 IS A LEAP-YEAR OR NOT
;NOTE THAT LEAP YEARS ARE INTEGRALLY DIVISIBLE BY 4, AND OTHERS AREN'T
MOV R2,R1 ;COPY THE YEAR
CLR R2 ;ASSUME IS NOT A LEAP-YEAR
BIT #3,R1 ;YEAR INTEGRALLY DIVISIBLE BY 4?
BNE 1$ ;BR IF NO (NOT LEAP-YEAR)
INC R2 ;NOTE 1 EXTRA DAY IN LEAP-YEAR
;WHEN GET HERE, R2 IS 1 FOR LEAP-YEAR OR 0 FOR NON-LEAP-YEAR
1$: MOV @(R5)+,R1 ;MONTH OF THE YEAR
BLE ERROR ;ERROR IF LESS THAN 1
CMP #13.,R1 ;MONTH 12. OR LESS?
BLE ERROR ;ERROR IF MONTH GREATER THAN 12.
MOV @(R5)+,R0 ;DAY OF THE MONTH
BLE ERROR ;ERROR IF LESS THAN 1
;WILL NOW SEE IF DAY-OF-MONTH LEGAL FOR THIS PARTICULAR MONTH
DEC R1 ;MAKE MONTH RELATIVE TO 0
CMPB DAYS(R1),R0 ;LEGAL DAY OF THIS MONTH?
BHIS OKAY ;BR IF YES
;IF GET HERE, DAY SPECIFIED SEEMS TO LARGE FOR THIS PARTICULAR MONTH
;HOWEVER, WILL BE LEGAL IF IS 29 FEBRUARY IN A LEAP YEAR
CMP #29.,R0 ;IS IT THE 29TH DAY?
BNE ERROR ;ERROR IF NOT
CMP #1,R1 ;IS THE MONTH FEBRUARY?
BNE ERROR ;ERROR IF NOT
TST R2 ;IS IT A LEAP YEAR?
BEQ ERROR ;ERROR IF NOT
;IF GET HERE, THE DAY, MONTH, AND YEAR ARE ALL LEGAL
;WILL NOW ADD DAYS IN PREVIOUS WHOLE MONTHS TO CURRENT DAY
OKAY: ASL R1 ;MAKE MONTHLY-TOTALS WORD INDEX
ADD TOTALS(R1),R0 ;ADD TO CURRENT DAY OF MONTH
;NOW HAVE THE ANSWER, UNLESS IS PAST FEBRUARY IN A LEAP YEAR
CMP R1, #2 ;PAST THE MONTH OF FEBRUARY?
BLE 1$ ;BR IF NO
ADD R2,R0 ;ADD 1 DAY IF LEAP YEAR
;NOW HAVE THE ANSWER IN R0, AND WILL RETURN IT TO CALLER
1$: MOV R0,@(R5)+ ;RETURN ANSWER TO CALLER
NEG @(R5)+ ;CHANGE STATUS TO +1
CLC ;CLEAR C-BIT TO INDICATE SUCCESS
;WILL NOW RESTORE REGISTERS AND RETURN TO CALLER
GOBACK: MOV (SP)+,R5 ;RESTORE R5
MOV (SP)+,R2 ;RESTORE R2
MOV (SP)+,R1 ;RESTORE R1
MOV (SP)+,R0 ;RESTORE R0
RTS PC ;RETURN TO CALLER
;IF GET HERE, AN ERROR WAS DETECTED IN INPUT INFORMATION
;WILL RETURN IMMEDIATELY TO CALLER, WITH A STATUS OF -1 AND C-BIT SET
;
ERROR: SEC ;SET C-BIT TO INDICATE FAILURE
BR GOBACK ;RESTORE REGISTERS AND RETURN
;TABLE OF NUMBER OF DAYS IN EACH MONTH
;NOTE THAT FEBRUARY ENTRY IS FOR NON-LEAP-YEAR
;
DAYS: .BYTE 31. ;31. DAYS IN JANUARY
.BYTE 28. ;28. DAYS IN FEBRUARY (USUALLY)
.BYTE 31. ;31. DAYS IN MARCH
.BYTE 30. ;30. DAYS IN APRIL
.BYTE 31. ;31. DAYS IN MAY
.BYTE 30. ;30. DAYS IN JUNE
.BYTE 31. ;31. DAYS IN JULY
.BYTE 31. ;31. DAYS IN AUGUST
.BYTE 30. ;30. DAYS IN SEPTEMBER
.BYTE 31. ;31. DAYS IN OCTOBER
.BYTE 30. ;30. DAYS IN NOVEMBER
.BYTE 31. ;31. DAYS IN DECEMBER
;
;END OF TABLE OF NUMBER OF DAYS IN EACH MONTH
;TABLE OF TOTAL DAYS IN YEAR PRIOR TO CURRENT MONTH
;NOTE THAT TABLE ENTRIES ARE FOR NON-LEAP-YEARS
;
TOTALS: .WORD 0 ;0. DAYS PRIOR TO JANUARY
.WORD 31. ;31. DAYS PRIOR TO FEBRUARY
.WORD 59. ;59. DAYS PRIOR TO MARCH
.WORD 90. ;90. DAYS PRIOR TO APRIL
.WORD 120. ;120. DAYS PRIOR TO MAY
.WORD 151. ;151. DAYS PRIOR TO JUNE
.WORD 181. ;181. DAYS PRIOR TO JULY
.WORD 212. ;212. DAYS PRIOR TO AUGUST
.WORD 243. ;243. DAYS PRIOR TO SEPTEMBER
.WORD 273. ;273. DAYS PRIOR TO OCTOBER
.WORD 304. ;304. DAYS PRIOR TO NOVEMBER
.WORD 334. ;334. DAYS PRIOR TO DECEMBER
;
;END OF TABLE OF TOTAL DAYS PRIOR TO CURRENT MONTH
.END