.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