; $Id: computus.asm,v 1.38 2011/03/02 05:40:06 al Exp $ ; Z-80 Computus ; Compute proleptic Gregorian/Anglican Easter, per the British ; Calendar Act, 24 Geo. II c. 23 (1751) and "Romani Calendarii a ; Gregorio XIII. P. M. Restituti Explicatio" (Clavius, 1603). ; Authored 2011 by Al Petrofsky . ; Implements an interface specified by Ian Taylor ; in an implementation dated January 2011 ; (which is included later in this file). ; Features: ; No self-modifying code (suitable for ROMming) ; No subroutines or data tables (completely relocatable code) ; No branching (just put one foot in front of the other) ; Measurements, as of rev. 1.38: ; clock ticks: 1043 ; code bytes: 237 ; opcode fetches: 202 ; stack words: 2 (plus return address) ; (those all exclude the call but include the return) ; On entry: ; HL is Gregorian year (0..65535) ; On exit: ; A is "Day of March" for Easter (22..56) ; B is day of month of Easter (1..31) ; C is month of year of Easter (3..4) ; F is trashed ; DE and HL are saved and restored. ; IX, IY, and the alternate registers are never touched ; (and therefore will be available during interrupts) ; Notation in comments: ; "/" means integer division, i.e. rounding down ; "%" means remainder (as in the C language) ; "<<", ">>", and "&" are also as in C, and everything ; has the same precedence as in C. JP Run_compare_test Org 200h Computus: ;;; Compute Year % 19 (Golden Number - 1) (full 16-bit numerator): ;;; Pertinent math facts: ;;; (1 << 6) % 19 = 7 ;;; (1 << 9) % 19 = 19 - 1 ;;; N * 27 / 512 is nearly N / 19 (near enough that computing ;;; approximately N * 27 / 512 will get you exactly N / 19, if N is ;;; in a particular range and you arrange for all the rounding in ;;; the approximation to work out just right) LD C, H ; Let A1 = 7 * (Year >> 6 & 7) XOR A ; Let A2 = A1 + 133 - (Year >> 9) + (Year & 63) RR C ; C = Year >> 9 LD B, A ; B = 0 RLA ; A = Year >> 8 & 1 PUSH DE ; Save DE LD E, L RL E RLA ; A = Year >> 7 & 3 RL E RLA LD D, A ; D = Year >> 6 & 7 ADD A, A ADD A, D ADD A, A ADD A, D ; A = A1 ADD A, 133 SUB C ; A = A1 + 133 - (Year >> 9) LD C, A LD A, L AND 63 ADD A, C LD E, A ; E = A2 (range 6 to 245) (A2 % 19 = Year % 19) RRA ; Let A3 = (((A2 >> 1) + A2 >> 2) + A2 >> 1) + A2 ADD A, E ; Let A4 = A3 >> 5 RRA ; (A4 is nearly A2 * 27 / 512, and exactly A2 / 19) OR A ; Let A5 = A4 * 16 = A3 >> 5 << 4 RRA ADD A, E RRA ADD A, E RRA ; A = A3 >> 1 AND 240 LD C, A ; C = A5 = A3 >> 5 << 4 = A3 >> 1 & 240 RRA ; Let A6 = ((A5 >> 1) + A5 >> 3) + A5 - A2 = A4 * 19 - A2 ADD A, C RRA RRA RRA ; A = (A5 >> 1) + A5 >> 3 ADD A, C SUB E ; A = A6 = - Year % 19 ADD A, 138 ; Let A7 = A6 + 138 LD D, A ; D = A7 ;;; B = 0 ;;; D = A7 = 138 - Year % 19 ;;; HL = Year ;;; Stack = saved DE ;;; Compute Year / 100 (Centuries) (14 bits in Year / 4): ;;; Pertinent math facts: ;;; N / 100 = N / 4 / 25 ;;; N * 41 / 1024 is nearly N / 25 LD A, H ; Let C1 = Year / 4 RRA ; Let C2 = C1 / 64 (= Year / 256 = H) PUSH HL ; Save Year RR L RRA RR L AND 63 ; AL = C1 RRA ; Let C3 = ((C2 >> 3) + C2 >> 2) + C2 << 1 ADD A, H ; C3 (10 bits) is nearly C1 * 41 / 1024 RRA ; and nearly C1 / 25 + 1. OR A RRA ; A = (C2 >> 3) + C2 >> 2 ADD A, H RL B ; BA = ((C2 >> 3) + C2 >> 2) + C2 RLA RL B LD C, A ; BC = C3 (quotient is approximately C3 - 1) ADD A, A ; Let C4 = C1 - (C3 - 1) * 25 ADD A, C ; C4 is the leftover that will ADD A, A ; need to be accurately divided by 25. ADD A, A ADD A, A ADD A, C ; A = C3 * 25 % 256 SUB L ; A = (C3 * 25 - C1) % 256 = C3 * 25 - C1 CPL ; A = C1 - C3 * 25 - 1 ADD A, 26 LD E, A ; E = C4 (range 11 to 136) RRA ; Let C5 = ((C4 >> 3) + C4 >> 2) + C4 RRA AND 63 RRA ADD A, E RRA OR A RRA ADD A, E ; A = C5 RLCA ; Let C6 = C5 / 32 (top 3 bits of C5) RLCA ; (C6 is nearly C4 * 41 / 1024, and exactly C4 / 25) RLCA AND 7 ; A = C6 = C5 / 32 = C4 / 25 ADD A, C ; Let C7 = C3 + C6 LD C, A ADC A, B SUB C LD B, A ; BC = C7 = C1 / 25 + 1 = Year / 100 + 1 ;;; BC = C7 = Year / 100 + 1 ;;; D = A7 = 138 - Year % 19 ;;; Stack = saved DE, Year ;;; Compute (Year / 100 * 8 + 13) / 25 (Lunar correction) ;;; (10 bits in Year / 100): ;;; Pertinent math facts: ;;; N * 5243 / (1 << 17) is nearly N / 25 LD H, B LD L, C ; HL = C7 = Year / 100 + 1 (range 1 to 656) ADD HL, HL ; Let E1 = C7 * 82 + 51 - C7 * 20 / 256 ADD HL, HL ADD HL, BC ADD HL, HL ADD HL, HL ; HL = C7 * 20, H = C7 * 20 / 256 LD A, 51 SUB H ; A = 256 = 51 - C7 * 5 / 64 ADD HL, HL ADD HL, BC ADD HL, HL ; HL = C7 * 82, HL + A = E1 ADD A, L ; Let E2 = E1 / 256 + 13 LD A, H ADC A, 11 ; A = E2 = (Year / 100 * 8 + 13) / 25 + 11 ;;; A = E2 = (Year / 100 * 8 + 13) / 25 + 11 ;;; BC = C7 = Year / 100 + 1 ;;; D = A7 = 138 - Year % 19 ;;; Stack = saved DE, Year LD H, B ; Let F1 = (C7 >> 1) + C7 >> 1 LD L, C SRL H RR L ; HL = C7 >> 1 ADD HL, BC SRL H RR L ; HL = F1 = Year / 100 - Year / 400 (Solar correction) SUB L ; Let F2 = E2 - F1 LD C, A SBC A, H SUB C LD B, A ; BC = F2 LD A, D ; A = A7 = 138 - Year % 19 ADD A, A ; Let F3 = A7 * 11 % 256 = 238 - Year % 19 * 11 ADD A, A ADD A, D ADD A, A ADD A, D ; A = F3 SUB C ; Let F4 = F3 - F2 LD C, A SBC A, B SUB C ; AC = F4 ;;; AC = F4 = 227 - Y % 19 * 11 + (Y / 100 * 8 + 13) / 25 - Y / 100 + Y / 400 ;;; D = A7 = 138 - Year % 19 ;;; HL = F1 = Year / 100 - Year / 400 ;;; Stack = saved DE, Year ;;; Compute (F4 - 2) % 30 (unadjusted epact) (9-bit numerator, range 27 to 507): ;;; Pertinent math facts: ;;; N / 30 = N / 2 / 15 ;;; N * 17 / 256 is nearly N / 15 RRA ; Let G1 = F4 >> 1 LD A, C RRA LD E, A ; E = G1 (range 14 to 254) LD B, 31 ; Let G2 = (G1 >> 4) + G1 >> 4 << 1 RRA RRA RRA AND B RRA ADD A, E RRA RRA RRA AND 30 ; A = G2 = (F4 - 2) / 30 * 2 ADD A, C ; Let G3 = G2 + F4 & 31 = F4 - (F4 - 2) / 30 * 30 AND B ; A = G3 = (F4 - 2) % 30 + 2 ;;; A = G3 = (F4 - 2) % 30 + 2 (unadjusted epact) ;;; B = 31 ;;; D = A7 = 138 - Year % 19 ;;; HL = F1 = Year / 100 - Year / 400 ;;; Stack = saved DE, Year LD C, A ; Let H1 = 19 + G3 - (G3 + Year % 19 / 11) / 31 SLA D ; Carry bit = 1 - Year % 19 / 11 POP DE ; DE = Year SBC A, 30 ; Carry bit = 1 - (G3 + Year % 19 / 11) / 31 LD A, -19 ; Let H2 = Year / 4 * 2 + 7936 - H1 + F1 SBC A, C LD C, A ; C = - H1 ADD HL, BC ; BC = 7936 - H1 (B was 31, and 31 * 256 = 7936) LD B, D ; HL = 7936 - H1 + F1 LD A, E ; BA = DE = Year RR B RRA AND 254 ; BA = Year / 4 * 2 ADD A, L LD L, A LD A, H ADC A, B ; AL = H2 ;;; AL = H2 = Year / 4 * 2 + Year / 100 - Year / 400 + 7 * 1134 - 2 - H1 ;;; C = - H1 (H1 = day-of-March of day after Paschal full moon) ;;; DE = Year ;;; Stack = saved DE ;;; No carry ;;; Let I1 = 3 - Year % 4 ;;; Let I2 = H2 + I1 ;;; Compute I2 % 7 (day-of-week of Paschal Full Moon) (16-bit numerator): ;;; Pertinent math facts: ;;; (1 << 3) % 7 = 1 (and (1 << 6) % 7 = 1, etc.) ;;; N * 73 / 512 is nearly N / 7 ; Let I3 = (I1 << 3) + (H2 >> 9) + (H2 >> 6 & 7) + (H2 & 63) RRA ; Carry bit = H2 >> 8 & 1 LD B, A ; B = H2 >> 9 LD A, E ; A = Year % 256 CPL ; A & 3 = I1 = 3 - Year % 4 RLA AND 7 ; A = (I1 << 1) + (H2 >> 8 & 1) LD H, A ; HL = (I1 << 9) + (H2 & 511) LD A, L ; A = H2 & 255 ADD HL, HL ADD HL, HL ; HL = (I1 << 11) + (H2 << 2 & 2047) EX DE, HL ; HL = Year, D = (I1 << 3) + (H2 >> 6 & 7) LD E, 63 AND E ; A = H2 & 63 ADD A, B ADD A, D LD B, A ; B = I3 (range 0 to 221) (I3 % 7 = I2 % 7) RRA ; Let I5 = ((I3 >> 3) + I3 + 4 >> 3) + I3 RRA ; (x + 4 >> 3 means x / 8 rounding to nearest) RRA AND E ADD A, B RRA RRA AND E RRA ; A = (I3 >> 3) + I3 >> 3 ADC A, B ; A = I5 (the ADC accomplishes the "+ 4" rounding) RRA ; Let I6 = (I5 >> 3) + I3 & 7 RRA RRA ADD A, B AND 7 ; A = I6 (= I3 % 7 = I2 % 7) SUB C ; A = I7 = I6 + H1 (C was H1 negated) ;;; A = I7 = Day of March of Easter ;;; HL = Year ;;; Stack = saved DE LD D, A ; D = I7 = Day-of-March CP 32 ; Let J1 = I7 + I7 / 32 SBC A, -1 LD B, A ; B = J1 SUB D ADD A, 3 LD C, A ; C = Month LD A, D ; A = Day-of-March POP DE ; Restore DE RES 5, B ; B = Day-of-month RET ;;;;;;;;;;;;;;;; ;; Here's some TRS-80 Model III BASIC code. It's been lightly tested ;; on real hardware (a Z80-A running at 2.02752 Mhz in a Tandy TRS-80 ;; Model 4D Microcomputer System). ;; At boot-time, answer 32000 (or less) to "Memory Size?". ;; 100 POKE 16526,1:POKE 16527,125 ;; 110 FOR X%=32001 TO 32264:READ I%:POKE X%,I%:NEXT ;; 120 DA%=0:X=VARPTR(DA%):POKE 32012,X AND 255:POKE 32013,X/256 ;; 130 MO%=0:X=VARPTR(MO%):POKE 32016,X AND 255:POKE 32017,X/256 ;; 140 INPUT "Year";YR ;; 150 IF YR>32767 THEN YR=YR-65536 ;; 160 DM=USR(YR) ;; 170 IF MO%=3 THEN MO$="March" ELSE MO$="April" ;; 180 PRINT "Easter Sunday is " MO$ DA% ;; 190 GOTO 140 ;; 200 REM Code to interface between BASIC and Computus ;; 210 DATA 205,127,10,205,21,125,111,175,103,120,50,0 ;; 220 DATA 0,121,50,0,0,195,154,10 ;; 230 REM Computus, from computus.asm rev 1.32. ;; 240 DATA 76,175,203,25,71,23,213,93,203,19,23,203 ;; 250 DATA 19,23,87,135,130,135,130,198,133,145,79,125 ;; 260 DATA 230,63,129,95,31,131,31,183,31,131,31,131 ;; 270 DATA 31,230,240,79,31,129,31,31,31,129,147,198 ;; 280 DATA 138,87,124,31,229,203,29,31,203,29,230,63 ;; 290 DATA 31,132,31,183,31,132,203,16,23,203,16,79 ;; 300 DATA 135,129,135,135,135,129,149,47,198,26,95,31 ;; 310 DATA 31,230,63,31,131,31,183,31,131,23,23,23 ;; 320 DATA 23,230,15,129,79,136,145,71,96,105,41,41 ;; 330 DATA 9,41,41,62,51,148,41,9,41,133,124,206 ;; 340 DATA 13,96,105,203,60,203,29,9,203,60,203,29 ;; 350 DATA 149,79,156,145,71,122,135,135,130,135,130,145 ;; 360 DATA 79,152,145,31,121,31,95,6,31,31,31,31 ;; 370 DATA 160,31,60,131,31,31,31,230,30,129,160,79 ;; 380 DATA 203,34,209,222,28,62,235,153,79,9,235,68 ;; 390 DATA 125,203,24,31,230,254,131,95,122,136,31,87 ;; 400 DATA 125,47,23,230,7,203,19,23,203,19,23,130 ;; 410 DATA 87,123,31,31,130,87,31,31,230,127,31,130 ;; 420 DATA 31,31,230,63,31,138,31,31,31,130,230,7 ;; 430 DATA 145,87,254,32,222,255,71,146,198,3,79,122 ;; 440 DATA 209,203,168,201 ;; Here's the interfacing code (the DATA in lines 210-220): ;; CD 7F 0A CALL Get_arg_to_HL ; a ROM routine ;; CD xx xx CALL Computus ; Call to wherever you poked it ;; 6F LD L, A ;; AF XOR A ;; 67 LD H, A ; HL = Day-of-March (22..56) ;; 78 LD A, B ;; 32 xx xx LD (nn), A ; Store to varptr for day-of-month (1..31) ;; 79 LD A, C ;; 32 xx xx LD (nn), A ; Store to varptr for month (3..4) ;; C3 9A 0A JP Return_HL ; a ROM routine ;;; Run_compare_test ;;; ;;; Compare results of two Computus functions, for all 16-bit years. Org 400h Run_compare_test: LD HL, 0 ; Starting year LD BC, 0 ; Negative number of iterations. (Counts up toward zero.) Loop: PUSH BC CALL Computus PUSH BC LD D, A CALL EasterZ80_Fast CP D JR Z, C1 HALT DEFM " Bad Day-of-March." C1: POP DE LD A, B CP D JR Z, C2 HALT DEFM " Bad Day." C2: LD A, C CP E JR Z, C3 HALT DEFM " Bad Month." C3: POP BC INC HL INC C JR NZ, Loop INC B JR NZ, Loop HALT DEFM " Success." Align 4 ;;; Make_table: Compute a large table of values in memory (with the ;;; assumption that you will then somehow get a dump of the memory ;;; transferred to some other computer and then compare the results to ;;; a known-good data set). Make_table: LD HL, 0 ; Starting year LD DE, 0x4000 ; Memory destination LD BC, 0x8000 ; Negative number of iterations M1: PUSH BC CALL Computus POP BC LD (DE), A INC DE INC HL INC C JR NZ, M1 INC B JR NZ, M1 HALT ; From on 2011-02-07 ; EasterZ80_Fast ; Compute Gregorian Easter according to ; Book of Common Prayer in Z80 assembly ; Ian Taylor, January 2011 ; On entry: ; HL is Gregorian year (0..65535) ; On exit: ; A is "Day of March" for Easter (22..56) ; B is day of month of Easter (1..31) ; C is month of year of Easter (3..4) ; All other registers preserved ; Constraints: ; No memory usage, except 4 stack words ; No use of IX, IY or shadow registers ; No self-modifying code ; No subroutine calls ; Computation time: 1799-1843 T-cycles ; Code bytes used: 355 EasterZ80_Fast: PUSH DE ; Save DE LD D, H ; Let T0 = Year >> 1 ... LD A, L SRL D RRA LD B, D LD C, A ; BC = T0 SRL D ; Let T1 = T0 >> 1 ... RRA LD E, A ; DE = T1 PUSH DE ; Push T1 PUSH HL ; Push Year LD H, D LD L, E ; HL = T1 SRL D ; Let T2 = T1 + (T1 >> 2) ... RRA SRL D RRA LD E, A ; DE = T1 >> 2 ADD HL, DE ; HL = T2 LD D, H ; Let T3 = (T0 + T2 + (T2 >> 4) + (T2 >> 5) + (T2 >> 10)) >> 4 ... LD A, L ADD HL, BC SRL D RRA SRL D RRA LD B, D SRL D RRA SRL D RRA LD E, A ; DE = T2 >> 4 ADD HL, DE SRL D RRA LD E, A ; DE = T2 >> 5 ADD HL, DE LD D, 0 LD E, B ; DE = T2 >> 10 ADD HL, DE LD A, L SRL H RRA SRL H RRA SRL H RRA SRL H RRA ; A = T3 LD B, A ; Let T4 = T3 & 255 ... ADD A, A ; Let T5 = (Year - T4 * 19) & 255 ... LD C, A ADD A, A ADD A, A ADD A, A ADD A, B ADD A, C ; A = (T4 * 19) & 255 NEG ; A = -(T4 * 19) & 255 POP HL ; Pop Year ADD A, L ; A = T5 CP 19 ; If T5 >= 19 Then Let T5 = T5 - 19 JR C, L1 SUB 19 L1: LD C, A ; C = T5 EX (SP), HL ; Let T6 = (T1 >> 1) + (T1 >> 3) ... PUSH HL ; Pop T1, Push Year, Push T1 LD B, L ; B = T1 & 255 LD A, L SRL H RRA LD D, H LD E, A SRL H RRA SRL H RRA LD L, A ADD HL, DE ; HL = T6 LD D, 0 ; Let T7 = (T6 + (T6 >> 6) + (T6 >> 7)) >> 4 ... LD E, H LD A, L ADD A, A EX DE, HL ADC HL, HL EX DE, HL ; DE = T6 >> 7 ADD HL, DE ADD A, A EX DE, HL ADC HL, HL ; HL = T6 >> 6 ADD HL, DE XOR A ADD HL, HL ADD HL, HL ADD HL, HL ADC A, A ADD HL, HL ADC A, A LD L, H LD H, A ; HL = T7 LD A, L ; Let T8 = (T7 * 25) & 255 ... ADD A, A ADD A, A ADD A, A LD D, A ADD A, A ADD A, D ADD A, L ; A = T8 SUB B ; Let T9 = (T1 - T8) & 255 ... NEG ; A = T9 CP 25 ; If T9 >= 25 Then Let T7 = T7 + 1 JR C, L2 INC HL L2: INC HL ; Let T7 = T7 + 1 ... LD D, H ; Let T10 = (T7 * 3) >> 2 ... LD E, L ADD HL, HL EX DE, HL ; DE = T7 * 2 ADD HL, DE ; HL = T7 * 3 LD A, L SRL H RRA SRL H RRA LD L, A ; HL = T10 PUSH HL ; Push T10 EX DE, HL ; DE = T10 INC HL ; Let T11 = (T7 * 8) + 5 ... ADD HL, HL ; HL = T11 >> 1 LD B, L ;; SLIA B ; Equivalent to SLA B : INC B SLA B INC B LD D, H ; Let T12 = (T11 >> 1) + (T11 >> 3) ... LD A, L SRL D RRA SRL D RRA LD E, A ADD HL, DE ; HL = T12 LD D, H ; Let T13 = (T12 + (T12 >> 6) + (T12 >> 7)) >> 4 ... LD E, L ADD HL, HL LD A, H ADD HL, HL ADD A, H LD L, A LD H, 0 ADD HL, DE ; HL >> 4 = T13 LD D, L ADD HL, HL ADD HL, HL ADD HL, HL ADD HL, HL ; H = T13 LD E, H ; Let T14 = T11 - (T13 * 25) ... LD A, H ADD A, A ADD A, A ADD A, A ADD A, H LD H, A ; H = (T13 * 9) & 255 LD A, D AND 240 ; A = (T13 * 16) & 255 ADD A, H SUB B ; (-A & 255) = T14 CP 232 ; If T14 >= 25 Then Let T13 = T13 + 1 JR NC, L3 INC E L3: LD A, C ; Let T15 = (T5 + 5) * 3 ... ADD A, A ; Let T16 = (T5 * 16) + T10 - T13 + T15 ... ADD A, A ADD A, A LD H, 0 LD L, A LD D, H ; DE = T13 ADD HL, HL ; HL = T5 << 4 LD A, 5 ADD A, C LD B, A ADD A, A ADD A, B ; A = T15 SBC HL, DE LD E, A ; DE = T15 ADD HL, DE POP DE ; Pop T10 ADD HL, DE ; HL = T16 LD A, H ; Let T17 = ((T16 >> 4) + (T16 >> 8)) & 254 ... LD B, L ADD HL, HL ADD HL, HL ADD HL, HL ADD HL, HL ADD A, H AND 254 ; A = T17 POP HL ; Pop T1 SBC HL, DE ; HL = T1 - T10 PUSH HL ; Push T1-T10 LD H, 0 ; Let T18 = T16 - (T17 * 15) ... LD L, A ; HL = T17 LD D, H LD E, L ; DE = T17 ADD HL, HL ADD HL, HL ADD HL, HL ADD HL, HL SBC HL, DE ; HL = T17 * 15 LD A, B SUB L ; A = T18 CP 30 ; If T18 >= 30 Then Let T18 = T18 - 30 JR C, L4 SUB 30 L4: LD B, A ; Let T19 = T18 * 16 + T5 + 53 ... ADD A, A ADD A, A ADD A, A LD H, D ; H = 0 ADD A, A RL H LD L, A ; HL = T18 * 16 LD A, 53 ADD A, C ; A = T5 + 53 LD E, A ; DE = T5 + 53 ADD HL, DE ; HL = T19 LD A, H ; If T19 >= 512 Then T20 = Let T18 + 27 Else Let T20 = T18 + 28 RRA CPL ADD A, 29 ADD A, B ; A = T20 LD B, D ; B = 0 POP DE ; Let T21 = (Year >> 15) + (Year & 32767) ... POP HL ; Pop Year PUSH HL ; Push Year BIT 7, H JR Z, L5 RES 7, H INC HL L5: LD C, H ; Let T21 = (T21 >> 9) + (T21 & 511) ... RR C LD H, B ; H = 0 RL H ADD HL, BC ; HL = T21 SCF ; Let T21 = T21 + T20 + T1 - T10 + 2 ... ADC HL, DE LD C, A ; BC = T20 SCF ADC HL, BC ; HL = T21 LD C, H ; Let T21 = (T21 >> 9) + (T21 & 511) ... RR C LD H, B RL H ADD HL, BC ; HL = T21 LD C, A ; BC = T20 LD A, L ; Let T21 = (T21 >> 6) + (T21 & 63) ... AND 63 ADD HL, HL ADD HL, HL ADD A, H ; A = T21 LD D, 7 ; Let T21 = (T21 >> 3) + (T21 & 7) ... LD L, A SRL L SRL L SRL L AND D ADD A, L ; A = T21 LD L, A ; Let T21 = (T21 >> 3) + (T21 & 7) ... SRL L SRL L SRL L AND D ADD A, L LD L, A ; A = T21 CP D ; If T21 != 7 Then Let T20 = T20 - T21 LD A, C JR Z, L6 SUB L L6: POP HL ; Pop Year POP DE ; Restore DE LD B, A ; B = T20 LD C, 3 ; C = March CP 32 RET C RES 5, B INC B ; B = T20 - 31 INC C ; C = April RET