; $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