head 1.38; access; symbols; locks; strict; comment @;; @; 1.38 date 2011.03.02.05.40.06; author al; state Exp; branches; next 1.37; 1.37 date 2011.02.25.21.53.43; author al; state Exp; branches; next 1.36; 1.36 date 2011.02.25.18.46.09; author al; state Exp; branches; next 1.35; 1.35 date 2011.02.24.23.05.16; author al; state Exp; branches; next 1.34; 1.34 date 2011.02.24.21.26.27; author al; state Exp; branches; next 1.33; 1.33 date 2011.02.22.19.45.33; author al; state Exp; branches; next 1.32; 1.32 date 2011.02.22.00.15.03; author al; state Exp; branches; next 1.31; 1.31 date 2011.02.21.07.00.13; author al; state Exp; branches; next 1.30; 1.30 date 2011.02.20.05.07.27; author al; state Exp; branches; next 1.29; 1.29 date 2011.02.20.02.39.19; author al; state Exp; branches; next 1.28; 1.28 date 2011.02.18.19.43.59; author al; state Exp; branches; next 1.27; 1.27 date 2011.02.17.20.15.02; author al; state Exp; branches; next 1.26; 1.26 date 2011.02.15.06.33.23; author al; state Exp; branches; next 1.25; 1.25 date 2011.02.15.02.23.14; author al; state Exp; branches; next 1.24; 1.24 date 2011.02.14.22.47.12; author al; state Exp; branches; next 1.23; 1.23 date 2011.02.14.06.49.26; author al; state Exp; branches; next 1.22; 1.22 date 2011.02.14.06.33.14; author al; state Exp; branches; next 1.21; 1.21 date 2011.02.14.05.50.35; author al; state Exp; branches; next 1.20; 1.20 date 2011.02.14.00.29.09; author al; state Exp; branches; next 1.19; 1.19 date 2011.02.13.05.26.13; author al; state Exp; branches; next 1.18; 1.18 date 2011.02.13.01.49.53; author al; state Exp; branches; next 1.17; 1.17 date 2011.02.11.06.14.18; author al; state Exp; branches; next 1.16; 1.16 date 2011.02.11.06.09.24; author al; state Exp; branches; next 1.15; 1.15 date 2011.02.11.05.51.03; author al; state Exp; branches; next 1.14; 1.14 date 2011.02.11.02.01.26; author al; state Exp; branches; next 1.13; 1.13 date 2011.02.09.23.18.39; author al; state Exp; branches; next 1.12; 1.12 date 2011.02.09.21.05.53; author al; state Exp; branches; next 1.11; 1.11 date 2011.02.09.07.34.21; author al; state Exp; branches; next 1.10; 1.10 date 2011.02.09.03.46.55; author al; state Exp; branches; next 1.9; 1.9 date 2011.02.09.03.41.57; author al; state Exp; branches; next 1.8; 1.8 date 2011.02.09.02.06.07; author al; state Exp; branches; next 1.7; 1.7 date 2011.02.09.01.14.49; author al; state Exp; branches; next 1.6; 1.6 date 2011.02.08.21.57.07; author al; state Exp; branches; next 1.5; 1.5 date 2011.02.08.18.02.07; author al; state Exp; branches; next 1.4; 1.4 date 2011.02.08.09.40.33; author al; state Exp; branches; next 1.3; 1.3 date 2011.02.08.07.58.35; author al; state Exp; branches; next 1.2; 1.2 date 2011.02.08.06.55.31; author al; state Exp; branches; next 1.1; 1.1 date 2011.02.08.04.38.07; author al; state Exp; branches; next ; desc @@ 1.38 log @Doc fixes @ text @; $Id: computus.asm,v 1.37 2011/02/25 21:53:43 al Exp al $ ; 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 @ 1.37 log @In /100, corrected comment about C5 being 9 bits (it actually fits in 8 bits). Because it fits in 8 bits, the four RLAs could be replaced with three RLCAs, saving four clock cycles. Ticks/bytes/ops/stack: 1043/237/202/2 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.36 2011/02/25 18:46:09 al Exp al $ d20 1 a20 1 ; Measurements, as of rev. 1.37: d89 1 a89 1 ADD A, E ; A = A3 d336 1 a336 1 ;; Model 4D). @ 1.36 log @Doc fix (corrected definition of A3 in %19) @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.35 2011/02/24 23:05:16 al Exp al $ d20 4 a23 4 ; Measurements, as of rev. 1.36: ; clock ticks: 1047 ; code bytes: 238 ; opcode fetches: 203 d149 5 a153 6 ADD A, E ; 9-bit result (in carry flag and A) is C5 RLA ; Let C6 = C5 / 32 (top 4 bits of C5) RLA ; (C6 is nearly C4 * 41 / 1024, and exactly C4 / 25) RLA RLA AND 15 ; A = C6 = C5 / 32 = C4 / 25 @ 1.35 log @In %7, replaced two RRAs with an AND 63. Saved 1 tick. Then moved the constant 63 into a register and reused it twice, saving two more ticks. Ticks/bytes/ops/stack: 1047/238/203/2 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.34 2011/02/24 21:26:27 al Exp al $ d20 1 a20 1 ; Measurements, as of rev. 1.35: d82 1 a82 1 RRA ; Let A3 = (((A2 >> 1) + A2 >> 2) + A2 >> 1) + A2 >> 5 d89 1 a89 1 ADD A, E @ 1.34 log @In %7, replaced four 8-bit left shifts with two 16-bit adds. Saved 2 ticks. (Required some register re-allocation to get the values into HL.) Ticks/bytes/ops/stack: 1050/239/203/2 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.33 2011/02/22 19:45:33 al Exp al $ d20 3 a22 3 ; Measurements, as of rev. 1.34: ; clock ticks: 1050 ; code bytes: 239 d290 1 d294 3 a296 3 LD A, E ; A = H2 << 2 & 255 RRA RRA ; A = H2 & 63 a297 1 ADD A, B a300 1 AND 127 d302 1 d306 1 a306 1 AND 63 @ 1.33 log @In %30, eliminated an INC by increasing the offset added at the end of calculating /25. Saved 4 ticks. Ticks/bytes/ops/stack: 1052/243/205/2 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.32 2011/02/22 00:15:03 al Exp al $ d20 4 a23 4 ; Measurements, as of rev. 1.33: ; clock ticks: 1052 ; code bytes: 243 ; opcode fetches: 205 d63 1 a63 1 RLA d67 1 a67 1 RLA d254 1 a254 1 LD A, -19 a256 1 ; Let H2 = Year / 4 * 2 + 7936 - H1 + F1 d258 2 a259 3 EX DE, HL ; DE = 7936 - H1 + F1 LD B, H LD A, L ; BA = HL = Year d263 4 a266 4 ADD A, E LD E, A LD A, D ADC A, B ; AE = H2 d268 1 a268 1 ;;; AE = H2 = Year / 4 * 2 + Year / 100 - Year / 400 + 7 * 1134 - 2 - H1 d270 1 a270 1 ;;; HL = Year d282 1 a282 1 ; Let I3 = (I1 << 3) + (H2 >> 9 & 127) + (H2 >> 6 & 7) + (H2 & 63) d284 2 a285 2 LD D, A ; D = H2 >> 9 & 127 LD A, L ; A = Year % 256 d289 5 a293 7 RL E RLA RL E ; E = (H2 & 63) << 2 RLA ; A = (I1 << 3) + (H2 >> 6 & 7) ADD A, D LD D, A ; D = (I1 << 3) + (H2 >> 6 & 7) + (H2 >> 9 & 127) LD A, E d297 2 a298 1 LD D, A ; D = I3 (range 0 to 221) (I3 % 7 = I2 % 7) d303 1 a303 1 ADD A, D d308 1 a308 1 ADC A, D ; A = I5 (the ADC accomplishes the "+ 4" rounding) d312 1 a312 1 ADD A, D @ 1.32 log @Added Model III BASIC version (tested on real hardware) @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.31 2011/02/21 07:00:13 al Exp al $ d20 4 a23 4 ; Measurements, as of rev. 1.32: ; clock ticks: 1056 ; code bytes: 244 ; opcode fetches: 206 d185 1 a185 1 ADC A, 13 ; A = E2 = (Year / 100 * 8 + 13) / 25 + 13 d187 1 a187 1 ;;; A = E2 = (Year / 100 * 8 + 13) / 25 + 13 d215 1 a215 1 ;;; AC = F4 = 225 - Y % 19 * 11 + (Y / 100 * 8 + 13) / 25 - Y / 100 + Y / 400 d220 1 a220 1 ;;; Compute F4 % 30 (unadjusted epact) (9-bit numerator, range 27 to 507): d229 2 a230 2 LD E, A ; E = G1 LD B, 31 ; Let G2 = (G1 >> 4) + G1 + 1 >> 4 << 1 a235 1 INC A d239 4 a242 4 RRA ; A = G2 = F4 / 30 * 2 AND 30 ADD A, C ; Let G3 = G2 + F4 & 31 AND B ; A = G3 = F4 % 30 d244 1 a244 1 ;;; A = G3 = F4 % 30 (unadjusted epact) d250 1 a250 1 LD C, A ; Let H1 = 22 + G3 - (G3 + Year % 19 / 11) / 29 d253 2 a254 2 SBC A, 28 ; Carry bit = 1 - (G3 + Year % 19 / 11) / 29 LD A, -21 @ 1.31 log @In / 25 (Lunar correction), added an extra 16-bit shift so as to simplify the ending (>> 8 rather than >> 7). Saved 2 ticks. Thanks to that change, it's free to add an offset to the Lunar correction. Doing so removes the need to subtract a constant in the preparation of the numerator for %30. Saved 7 ticks. Ticks/bytes/ops/stack: 1056/244/206/2 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.30 2011/02/20 05:07:27 al Exp al $ d20 1 a20 1 ; Measurements, as of rev. 1.31: d337 56 @ 1.30 log @Documentation changes only. Added "pertinent math facts" at the start of each major division. Added some other comments throughout. @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.29 2011/02/20 02:39:19 al Exp al $ d20 4 a23 4 ; Measurements, as of rev. 1.30: ; clock ticks: 1065 ; code bytes: 248 ; opcode fetches: 209 d142 2 a143 2 RRA ; (C5 / 32 is nearly C4 * 41 / 1024, AND 63 ; and exactly C4 / 25) d173 1 a173 1 ADD HL, HL ; Let E1 = C7 * 41 - C7 * 10 / 256 + 25 a175 3 ADD HL, HL ; HL = C7 * 10 LD A, 25 SUB H ; A = 25 - C7 * 10 / 256 d177 3 d181 5 a185 7 ADD HL, BC ; HL = C7 * 41 ADD A, L LD L, A ADC A, H SUB L ; AL = E1 RL L ; Let E2 = E1 >> 7 RLA ; A = E2 = (Year / 100 * 8 + 13) / 25 d187 1 a187 1 ;;; A = E2 = (Year / 100 * 8 + 13) / 25 d205 1 a205 1 ADD A, A ; Let F3 = 225 - Year % 19 * 11 d209 1 a209 2 ADD A, D ; A = (138 - Year % 19) * 11 % 256 = 238 - Year % 19 * 11 SUB 13 ; A = F3 @ 1.29 log @Removed an unnecessary addition to ~(Year % 4) at the start of %7. Saved 7 ticks. Removed a 16-bit add in the preparation of the %7 numerator. Saved 4 ticks. Changed Year % 19 offset, so that RL would put the opposite value in the carry bit. Saved 4 ticks (a CPL) in the epact adjustment. Minimized time of each stack word's usage. That is, push as late as possible and pop as soon as possible. Reallocated some registers to accomplish this, as well as just to reduce the occurrence of 16-bit values split across two registers that are not a pair. Renamed all values for consistency. Dumped Tn and Un series (T1, U1, etc.) and added An through Jn, where A through J represent the 10 program sections: one for each major division and one for each section after a major division (B and D are currently unused). Increased the arithmetic documentation, especially in /100 (which hardly had any). Ticks/bytes/ops/stack: 1065/248/209/2 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.28 2011/02/18 19:43:59 al Exp al $ d20 1 a20 1 ; Measurements, as of rev. 1.29: d38 6 d51 8 d82 4 a85 6 RRA ; Let A3 = (((A2 >> 1) + A2 >> 2) + A2 >> 1) + A2 >> 5 << 4 ADD A, E RRA OR A RRA ADD A, E d89 2 d92 2 a93 2 LD C, A ; C = A3 RRA ; Let A4 = ((A3 >> 1) + A3 >> 3) + A3 - A2 d97 1 a97 1 RRA ; A = (A3 >> 1) + A3 >> 3 d99 3 a101 3 SUB E ; A = A4 = - Year % 19 ADD A, 138 ; Let A5 = A4 + 138 LD D, A ; D = A5 d104 1 a105 1 ;;; D = A5 = 138 - Year % 19 d110 4 d122 2 a123 2 ADD A, H ; C3 (10 bits) is approximately C1 / 25 + 1. RRA d142 2 a143 2 RRA ; (C5 / 32 = C4 / 25) AND 63 d151 1 a151 1 RLA d162 1 a162 1 ;;; D = A5 = 138 - Year % 19 d168 3 d191 1 a191 1 ;;; D = A5 = 138 - Year % 19 d206 1 a206 1 LD A, D ; A = A5 = 138 - Year % 19 d219 1 a219 1 ;;; D = A5 = 138 - Year % 19 d225 4 d248 1 a248 1 ;;; A = G3 = result of modulo 30 operation (unadjusted epact) d250 1 a250 1 ;;; D = A5 = 138 - Year % 19 d284 5 a288 1 ; Let I3 = (I1 << 3) + (H2 >> 9 & 127) + (H2 >> 6 & 7) + (H2 & 63) @ 1.28 log @For solar correction, changed (X >> 2) - X (where X is Year / 100 + 4) to (Z >> 1) + Z >> 1 (where Z is Year / 100 + 1). Saved 9 clock ticks. Several sign changes in %7 and the preparation of the numerator for %7, (necessary to accommodate the change of sign in the solar correction). Altogether saves 1 clock cycle, and makes math clearer. No longer use any 16-bit subtractions. Ticks/bytes/ops/stack: 1080/250/208/2 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.27 2011/02/17 20:15:02 al Exp al $ d5 3 a7 4 ; 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). d11 3 a13 6 ; Derived from a version by Ian Taylor ; dated January 2011. I rewrote and sped up the code for ; the five major division/modulo operations (divisors 19, ; 100, 25, 30, and 7). I also removed all branching. Some ; of the miscellaneous values named by Taylor have names ; starting with "T". Names I added start with U. d20 4 a23 4 ; Measurements, as of rev. 1.28: ; clock ticks: 1080 ; code bytes: 250 ; opcode fetches: 208 a41 2 PUSH DE ; Save DE PUSH HL ; Save Year d45 3 a47 3 LD C, H ; Let U1 = 7 * (Year >> 6 & 7) LD E, L ; Let U3 = U1 + 133 - (Year >> 9) + (Year & 63) XOR A a48 1 RR H ; H = Year >> 9 d50 3 a52 1 RL L d54 1 a54 1 RL L d60 1 a60 1 ADD A, D ; A = U1 d62 3 a64 3 SUB H ; A = U1 + 133 - (Year >> 9) LD H, A LD A, E d66 4 a69 4 ADD A, H LD L, A ; L = U3 (range 6 to 245) (U3 % 19 == Year % 19) RRA ; Let U6 = (((U3 >> 1) + U3 >> 2) + U3 >> 1) + U3 >> 5 << 4 ADD A, L d73 1 a73 1 ADD A, L d75 1 a75 1 ADD A, L d78 3 a80 3 LD H, A ; H = U6 RRA ; Let U7 = ((U6 >> 1) + U6 >> 3) + U6 - U3 + 10 ADD A, H d83 5 a87 5 RRA ; A = (U6 >> 1) + U6 >> 3 ADD A, H SUB L ; A = - Year % 19 ADD A, 10 LD D, A ; D = U7 d90 3 a92 3 ;;; CE = Year ;;; D = U7 = 10 - Year % 19 ;;; Stack = saved DE, Year d96 4 a99 7 LD A, C ; Let T1 = Year / 4 RRA RR E RRA RR E ; AE = T1 AND 63 d101 4 a104 1 ADD A, C d107 3 a109 3 RRA ADD A, C RL B d112 4 a115 3 LD C, A ; BC (10 bits) is approximately Year / 100. ADD A, A ; (The approximation can be high or low.) ADD A, C d118 3 a120 4 ADD A, A ADD A, C SUB E CPL d122 3 a124 4 LD E, A ; E = T1 - BC*25 + 25 (range 11 to 136) ; (Remainder, plus 25 to ensure nonnegativity) RRA RRA d131 2 a132 2 ADD A, E RLA d136 3 a138 3 AND 15 ; A = E / 25 ADD A, C ; Let U9 = A + BC LD L, A d140 2 a141 2 SUB L LD H, A ; HL = U9 = Year / 100 + 1 d143 2 a144 2 ;;; D = U7 = 10 - Year % 19 ;;; HL = U9 = Year / 100 + 1 d150 3 a152 4 LD B, H LD C, L ; BC = U9 ADD HL, HL ; Let U10 = (U9 << 2) + U9 << 1 d155 3 a157 3 ADD HL, HL ; HL = U10 LD A, 25 ; Let U11 = (U10 << 2) - (U10 >> 8) + U9 + 25 SUB H ; A = 25 - (U10 >> 8) d160 1 a160 1 ADD HL, BC ; HL = (U10 << 2) + U9 d164 7 a170 7 SUB L ; AL = U11 RL L ; Let U12 = U11 >> 7 RLA ; A = U12 = (Year / 100 * 8 + 13) / 25 ;;; A = U12 = (Year / 100 * 8 + 13) / 25 ;;; BC = U9 = Year / 100 + 1 ;;; D = U7 = 10 - Year % 19 d173 1 a173 1 LD H, B ; Let T10 = (U9 >> 1) + U9 >> 1 d176 1 a176 1 RR L ; HL = U9 >> 2 d179 2 a180 3 RR L ; HL = T10 = Year / 100 - Year / 400 (Solar correction) SUB L ; Let U14 = U12 - T10 d184 3 a186 3 LD B, A ; BC = U14 LD A, D ; Let T16 = 115 + U7 * 11 - U14 ADD A, A d190 3 a192 3 ADD A, D ; A = U7 * 11 (= 110 - Year % 19 * 11) ADD A, 115 ; A = 115 + U7 * 11 SUB C d195 1 a195 1 SUB C ; AC = T16 d197 3 a199 3 ;;; AC = T16 = 225 - Y % 19 * 11 + (Y / 100 * 8 + 13) / 25 - Y / 100 + Y / 400 ;;; D = U7 = 10 - Year % 19 ;;; HL = T10 = Year / 100 - Year / 400 d202 1 a202 1 ;;; Compute T16 % 30 (unadjusted epact) (9-bit numerator, range 27 to 507): d204 1 a204 1 RRA ; Let U16 = T16 >> 1 d207 2 a208 2 LD E, A ; E = U16 LD B, 30 ; Let U17 = (U16 >> 4) + U16 + 1 >> 4 << 1 d218 9 a226 9 RRA ; A = U17 = T16 / 30 * 2 AND B ADD A, C ; Let T18 = U17 + T16 & 31 AND 31 ; A = T18 = T16 % 30 ;;; A = T18 = result of modulo 30 operation (unadjusted epact) ;;; B = 30 ;;; D = U7 = 10 - Year % 19 ;;; HL = T10 = Year / 100 - Year / 400 d229 2 a230 11 LD E, A ; Let U18 = 22 + T18 - (T18 + Year % 19 / 11) / 29 RL D ; Carry bit = Year % 19 / 11 ADC A, 227 ; Carry bit = (T18 + Year % 19 / 11) / 29 LD A, E SBC A, 235 ; A = 21 + T18 - (T18 + Year % 19 / 11) / 29 CPL ; A = - U18 ; Let U19 = Year / 4 * 2 + 7680 + U18 + T10 ; B = 30 (30 * 256 = 7680) (7680 % 7 = 1) LD C, A ; BC = 7680 + U18 ADD HL, BC ; HL = 7680 + U18 + T10 d232 16 a247 12 LD B, D LD C, E ; BC = Year SRL B RR C RES 0, C ; BC = Year / 4 * 2 ADD HL, BC ; HL = U19 LD C, A ; C = - U18 LD A, E ; Let U20 = 8 - Year % 4 AND 3 CPL ADD A, 8 ; A = U20 d249 3 a251 4 ;;; A = U20 = 8 - Year % 4 ;;; C = - U18 (U18 = day-of-March of day after Paschal full moon) ;;; DE = Year ;;; HL = U19 = Year / 4 * 2 + Year / 100 - Year / 400 + 7680 - U18 d253 1 d255 9 a263 5 ;;; Compute (U19 + U20) % 7 (Dominical Letter) (16-bit numerator): ; Let U21 = (U20 << 3) + (U19 >> 6 & 7) ; Let U22 = U21 + (U19 & 63) + (U19 >> 9 & 127) SRL H ; H = U19 >> 9 & 127 d265 2 a266 1 RL L d268 5 a272 5 RL L RLA ; A = U21 ADD A, H LD H, A ; H = U21 + (U19 >> 9 & 127) LD A, L d274 6 a279 4 RRA ; A = U20 & 63 ADD A, H LD H, A ; H = U22 (range 0 to 221) (U22 % 7 = (U19 + U20) % 7) RRA ; Let U23 = ((U22 >> 3) + U22 + 4 >> 3) + U22 d281 1 a281 3 AND 63 RRA ADD A, H d285 3 a288 2 ADC A, H ; A = U23 RRA ; Let U24 = (U23 >> 3) + U22 & 7 d290 3 a292 3 RRA ADD A, H AND 7 ; A = U24 (= U22 % 7 = (U19 + U20) % 7) d294 2 a295 4 SUB C ; A = U26 = U24 + U18 (C was U18 negated) ;;; A = U26 = Day of March of Easter ;;; DE = Year d298 5 a302 5 LD H, A ; H = U26 = Day-of-March CP 32 SBC A, 255 LD B, A ; B = U26 + U26 / 32 SUB H d305 1 a305 4 RES 5, B ; B = Day LD A, H ; A = Day-of-March EX DE, HL ; HL = Year d307 1 d450 2 a451 2 LD B, A ; Let T4 = T3 & 255 ... ADD A, A ; Let T5 = (Year - T4 * 19) & 255 ... d457 2 a458 2 ADD A, C ; A = (T4 * 19) & 255 NEG ; A = -(T4 * 19) & 255 d467 1 a467 1 LD B, L ; B = T1 & 255 d500 1 a500 1 LD A, L ; Let T8 = (T7 * 25) & 255 ... d508 1 a508 1 SUB B ; Let T9 = (T1 - T8) & 255 ... d564 1 a564 1 LD H, A ; H = (T13 * 9) & 255 d566 1 a566 1 AND 240 ; A = (T13 * 16) & 255 d568 1 a568 1 SUB B ; (-A & 255) = T14 d590 1 a590 1 LD A, H ; Let T17 = ((T16 >> 4) + (T16 >> 8)) & 254 ... d633 1 a633 1 POP DE ; Let T21 = (Year >> 15) + (Year & 32767) ... d640 1 a640 1 L5: LD C, H ; Let T21 = (T21 >> 9) + (T21 & 511) ... d650 1 a650 1 LD C, H ; Let T21 = (T21 >> 9) + (T21 & 511) ... d656 1 a656 1 LD A, L ; Let T21 = (T21 >> 6) + (T21 & 63) ... d661 1 a661 1 LD D, 7 ; Let T21 = (T21 >> 3) + (T21 & 7) ... d668 1 a668 1 LD L, A ; Let T21 = (T21 >> 3) + (T21 & 7) ... @ 1.27 log @Save a couple ops when computing epact adjustment by earlier storing 10 - Year % 19, rather than - Year % 19. Saved an op in /100 by computing Year / 100 + 4. (Users of the result were adjusted without increasing time.) Replaced a 16-bit add in /100, to which one operand was only 8 bits, with all 8-bit operations. Replaced two 16-bit ops in /25, one an 8-bit + 16-bit add, and the other a shift that worked out to be simpler and faster with all 8-bit operations. Replaced two 16-bit ops in computation of the %30 numerator. which saved time because it reduced the need to move values around in registers. In %7, changed numerator from Year + Year / 4 + foo (a 17-bit quantity) to large-multiple-of-7 - Year / 4 * 2 + Year % 4 + foo (a 16-bit quantity). Ticks/bytes/ops/stack: 1090/254/214/2 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.26 2011/02/15 06:33:23 al Exp al $ d24 4 a27 4 ; Measurements, as of rev. 1.27: ; clock ticks: 1090 ; code bytes: 254 ; opcode fetches: 214 d117 1 a117 1 LD C, A ; BC (10 bits) is approximately the quotient. d126 3 a128 3 ADD A, 101 LD E, A ; E = T1 - BC*25 + 100 (range 86 to 211) ; (Remainder, plus 100) d143 1 a143 2 ; (A + BC - 4 is the correct total quotient.) ADD A, C d147 1 a147 1 LD H, A ; HL = U9 = Year / 100 + 4 d150 1 a150 1 ;;; HL = U9 = Year / 100 + 4 d163 2 a164 2 LD A, 30 ; Let U11 = (U10 << 2) - (U10 >> 8) + U9 + 30 SUB H ; A = 30 - (U10 >> 8) d173 1 a173 2 RLA LD L, A ; L = U12 d175 2 a176 1 ;;; BC = U9 = Year / 100 + 4 a177 1 ;;; L = U12 = (Year / 100 * 8 + 13) / 25 + 1 d180 2 a181 2 LD H, B ; Let T10 = U9 - (U9 >> 2) = Year / 100 - Year / 400 + 3 LD A, C ; HA = BC = U9 d183 2 a184 1 RRA d186 5 a190 1 RRA ; HA = U9 >> 2 d192 2 a193 12 LD C, A LD A, H SBC A, B LD B, A ; BC = - T10 (Solar correction) LD A, L ; Let U14 = T10 - U12 ADD A, C LD L, A ADC A, B SUB L LD H, A ; HL = U12 + (- T10) = - U14 LD A, D ; Let T16 = 113 - U7 * 11 + U14 d198 6 a203 6 ADD A, D ; A = - U7 * 11 ADD A, 113 ; A = 113 - U7 * 11 SUB L LD L, A SBC A, H SUB L ; AL = T16 d205 1 a205 2 ;;; A = High bit of T16 ;;; BC = - T10 = - (Year / 100 - Year / 400 + 3) d207 1 a207 1 ;;; L = Low eight bits of T16 d213 1 a213 1 LD A, L d216 1 a216 2 LD H, 240 ; Let U17 = (U16 >> 4) + U16 + 1 >> 4 << 1 AND H d220 1 a223 1 AND H d227 2 a228 1 ADD A, L ; Let T18 = U17 + T16 & 31 d232 1 a232 1 ;;; BC = - T10 = - (Year / 100 - Year / 400 + 3) d234 1 d237 1 a237 1 LD E, A ; Let U18 = T18 - (T18 + Year % 19 / 11) / 29 + 29 d239 1 a239 1 ADC A, 227 ; Carry bit = (T18 + U7 / 11) / 29 d241 6 a246 1 SBC A, 227 ; A = U18 a247 4 ; Let U19 = 61184 - Year / 4 * 2 + T10 + U18 DEC H ; H = 239 (239 * 256 = 61184) (61184 % 7 = 4) LD L, A ; HL = U18 + 61184 ADD HL, BC ; HL = 61184 + T10 + U18 d254 7 a260 3 OR A SBC HL, BC ; HL = U19 LD C, A ; C = U18 d262 2 a263 1 ;;; C = U18 (= day-of-March of eight days after Paschal full moon) d265 1 a265 1 ;;; HL = U19 d268 1 a268 1 ;;; Compute (U19 + Year % 4) % 7 (Dominical Letter) (16-bit numerator): d270 3 a272 5 ; Let U20 = U19 + Year % 4 ; Let U21 = (Year % 4 << 3) + (U19 >> 6 & 7) LD A, E ; Let U22 = U21 + (U19 & 63) + (U19 >> 9 & 127) AND 3 ; A = Year % 4 RR H ; H = U19 >> 9 & 127 d284 1 a284 1 LD H, A ; H = U22 (range 0 to 221) (U22 % 7 == U20 % 7) d299 3 a301 3 AND 7 ; A = U24 (= U22 % 7 = U20 % 7) SUB C ; Let U26 = U18 - U24 - 1 CPL ; A = U26 @ 1.26 log @Used even better plan for epact adjustment, switching from T18 * 16 + 53 + U7 >> 9 to (T18 + U7 / 11) / 29. This should have been the most obvious choice in the beginning, but the initial design had minimized the number of divisions, even though some divisions are trivially easy. (If it's known the quotient is one or zero, then a simple subtraction will put the quotient in the carry bit). Ticks/bytes/ops/stack: 1128/253/210/2 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.25 2011/02/15 02:23:14 al Exp al $ d24 4 a27 4 ; Measurements, as of rev. 1.26: ; clock ticks: 1128 ; code bytes: 253 ; opcode fetches: 210 d51 1 a51 1 LD D, H ; Let U1 = 7 * (Year >> 6 & 7) d61 1 a61 1 LD C, A ; C = Year >> 6 & 7 d63 1 a63 1 ADD A, C d65 1 a65 1 ADD A, C ; A = U1 d84 1 a84 1 RRA ; Let U7 = U3 - (((U6 >> 1) + U6 >> 3) + U6) d90 3 a92 2 SUB L LD L, A ; L = -U7 (Golden Number) d95 2 a96 2 ;;; DE = Year ;;; L = -U7 = - Year % 19 d101 1 a101 1 LD A, D ; Let T1 = Year / 4 d109 1 a109 1 ADD A, D d113 1 a113 2 ADD A, D LD H, B ; H = 0 d117 1 a117 1 LD C, A ; BC is approximately the quotient. d126 3 a128 3 ADD A, 26 LD E, A ; E = T1 - BC*25 + 25 (range 13 to 184) ; (Remainder, plus 25 to ensure nonnegativity) d143 2 a144 2 ; (A + BC - 1 is the correct total quotient.) LD D, L ; D = - U7 d146 3 a148 2 ADD HL, BC DEC HL ; HL = U9 = Year / 100 d150 2 a151 2 ;;; D = -U7 = - Year % 19 ;;; HL = U9 = Year / 100 d159 1 d164 3 a166 5 LD A, 66 ; Let U11 = (U10 << 2) - (U10 >> 8) + U9 + 66 SUB H LD E, A ; DE = 66 - (U10 >> 8) LD A, D ; A = - U7 LD D, 0 d168 12 a179 9 ADD HL, HL ; HL = U10 << 2 ADD HL, DE ADD HL, BC ; HL = U11 ADD HL, HL ; Let U12 = U11 >> 7 LD E, H ; DE = U12 ;;; A = -U7 = - Year % 19 ;;; BC = U9 = Year / 100 ;;; DE = U12 = (Year / 100 * 8 + 13) / 25 d182 2 a183 2 LD H, B ; Let T10 = U9 - (U9 >> 2) = Year / 100 - Year / 400 LD L, C ; HL = BC = U9 d185 1 a185 1 RR L d187 15 a201 7 RR L OR A SBC HL, BC ; Let U14 = T10 - U12 EX DE, HL ; DE = - T10 (Solar correction), HL = U12 ADD HL, DE ; HL = - U14 LD C, A ; C = - U7 ADD A, A ; Let T16 = 225 - U7 * 11 + U14 d203 1 a203 1 ADD A, C d205 2 a206 2 ADD A, C ; A = - U7 * 11 ADD A, 225 ; A = 225 - U7 * 11 d213 2 a214 2 ;;; C = - U7 = - Year % 19 ;;; DE = - T10 = - (Year / 100 - Year / 400) d223 4 a226 2 LD H, A ; H = U16 RRA ; Let U17 = (U16 >> 4) + U16 + 1 >> 4 << 1 a228 1 AND 31 d231 2 a232 1 ADD A, H d235 1 a235 2 RRA AND 30 ; A = U17 = T16 / 30 * 2 d240 2 a241 2 ;;; C = - U7 = 256 - Year % 19 ;;; DE = - T10 = - (Year / 100 - Year / 400) d244 2 a245 5 LD H, A ; Let U18 = T18 - (T18 + U7 / 11) / 29 + 29 LD A, C ; A = U7 = 256 - Year % 19 DEC A SUB 245 ; Carry bit = U7 / 11 LD A, H d247 2 a248 2 LD A, H SBC A, 226 ; A = U18 + 1 d250 4 a253 5 LD H, 0 LD L, A ; HL = U18 + 1 DEC A ; A = U18 ; Let U19 = Year / 4 - T10 + U18 + 1 ADD HL, DE ; HL = - T10 + U18 + 1 d255 1 a255 1 LD B, D ; d259 4 a262 3 SRL B RR C ; BC = Year / 4 ADD HL, BC ; HL = U19 d264 1 a264 1 ;;; A = U18 (= day-of-March of eight days after Paschal full moon) d266 1 a266 1 ;;; HL = U19 (a 14-bit quantity) d269 1 a269 1 ;;; Compute (U19 + Year) % 7 (Dominical Letter) (17-bit numerator): d271 5 a275 6 LD C, A ; C = U18 XOR A ; Let U20 = U19 + Year ADD HL, DE ; Let U21 = (U20 >> 16 << 4) + (U20 >> 6 & 7) RLA ; AHL = U20 RLA ; Let U22 = U21 + (U20 & 63) + (U20 >> 9 & 127) RR H ; H = U20 >> 9 & 63 d282 1 a282 1 LD H, A d287 1 a287 1 LD H, A ; H = U22 (range 0 to 213) (U22 % 7 == U20 % 7) d302 1 a302 1 AND 7 ; A = U24 (= U21 % 7) @ 1.25 log @Removed push/pop of Year % 19 (Golden Number). This saves a push/pop and reduces maximum stack depth from 3 words to 2 words. Ticks/bytes/ops/stack: 1141/256/213/2 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.24 2011/02/14 22:47:12 al Exp al $ d24 4 a27 4 ; Measurements, as of rev. 1.25: ; clock ticks: 1141 ; code bytes: 256 ; opcode fetches: 213 d232 6 a237 9 LD H, A ; Let U18 = T18 - (T18 * 8 + (53 + U7) / 2 >> 8) + 29 ADD A, A ADD A, A ADD A, A LD L, A ; L = T18 * 8 LD A, 53 SUB C ; A = 53 + U7 (C was U7 negated) SRL A ADD A, L ; Carry bit = T18 * 8 + (53 + U7) / 2 >> 8 a243 1 d262 1 a262 1 LD C, A @ 1.24 log @Used better plan for epact adjustment: T18 * 8 + (53 + U7) / 2 >> 8 instead of T18 * 16 + 53 + U7 >> 9. This fits much better in 8-bit registers. Removed push/pop of T10 (Solar correction), which required swapping BC/DE usage for a stretch. Ticks/bytes/ops/stack: 1150/255/212/3 @ text @d1 1 a1 1 ; $Id$ d24 5 a28 5 ; Measurements, as of rev. 1.24: ; clock ticks: 1150 ; code bytes: 255 ; opcode fetches: 212 ; stack words: 3 (plus return address) d91 1 a91 1 PUSH AF ; Push -U7 (Golden Number) d95 2 a96 1 ;;; Stack = saved DE, Year, 256 * (256 - Year % 19) + 8 bits of trash d144 1 d149 1 d151 1 a151 1 ;;; Stack = saved DE, Year, 256 * (256 - Year % 19) + 8 bits of trash d164 2 a166 1 LD E, A ; DE = 66 - (U10 >> 8) d174 1 d177 1 a177 1 ;;; Stack = saved DE, Year, 256 * (256 - Year % 19) + 8 bits of trash d185 3 a187 4 XOR A SBC HL, BC ; HL = - T10 POP AF ; Let U14 = T10 - U12 EX DE, HL ; DE = - T10 (Solar correction) d202 1 a202 1 ;;; C = - U7 = 256 - Year % 19 d205 1 a205 1 ;;; Stack = saved DE, Year, d230 1 a230 1 ;;; Stack = saved DE, Year, - T10 = - (Year / 100 - Year / 400) @ 1.23 log @Change in %19 to save one tick. Ticks/bytes/ops/stack: 1195/261/219/3 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.22 2011/02/14 06:33:14 al Exp al $ d24 4 a27 4 ; Measurements, as of rev. 1.23: ; clock ticks: 1195 ; code bytes: 261 ; opcode fetches: 219 d153 2 a154 2 LD D, H LD E, L ; DE = U9 d157 1 a157 1 ADD HL, DE d161 2 a162 2 LD B, 0 LD C, A ; BC = 66 - (U10 >> 8) d165 2 a166 2 ADD HL, BC ADD HL, DE ; HL = U11 d168 1 a168 1 LD C, H ; BC = U12 d170 2 a171 2 ;;; BC = U12 = (Year / 100 * 8 + 13) / 25 ;;; DE = U9 = Year / 100 d174 2 a175 2 LD H, D ; Let T10 = U9 - (U9 >> 2) = Year / 100 - Year / 400 LD L, E ; HL = DE = U9 d181 1 a181 1 SBC HL, DE ; HL = - T10 d183 3 a185 3 PUSH HL ; Push - T10 ADD HL, BC ; HL = - U14 LD E, A ; E = - U7 d188 1 a188 1 ADD A, E d190 1 a190 1 ADD A, E ; A = - U7 * 11 d198 2 a199 2 ;;; B = 0 ;;; E = - U7 = 256 - Year % 19 d201 1 a201 1 ;;; Stack = saved DE, Year, - T10 = - (Year / 100 - Year / 400) d208 1 a208 1 LD D, A ; D = U16 d215 1 a215 1 ADD A, D d224 2 a225 2 ;;; B = 0 ;;; E = - U7 = 256 - Year % 19 d228 1 a228 2 LD C, A ; Let T19 = T18 * 16 + 53 - U7 ... ADD A, A d232 1 a232 3 LD H, B RL H LD L, A ; HL = T18 * 16 d234 8 a241 10 SUB E ; A = 53 - U7 (E was U7 negated) LD D, B LD E, A ; DE = 53 - U7 ADD HL, DE ; HL = T19 LD A, H ; Let U18 = T18 - (T19 >> 9) + 29 RRA SUB C CPL ADD A, 31 ; A = U18 + 1 LD E, A ; DE = U18 + 1 d243 2 a244 1 POP HL ; Let U19 = Year / 4 - T10 + U18 + 1 @ 1.22 log @In %19, used a better plan for reducing numerator from 16 bits to 8 bits. Ticks/bytes/ops/stack: 1196/261/220/3 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.21 2011/02/14 05:50:35 al Exp al $ d24 2 a25 2 ; Measurements, as of rev. 1.22: ; clock ticks: 1196 d27 1 a27 1 ; opcode fetches: 220 d69 2 a70 3 LD A, L RRA RRA d260 1 d262 1 a262 1 ;;; Stack = saved DE, Year @ 1.21 log @Golden number is now pushed directly from AF (rather than from BC) Year / 4 (T1) is now computed just before %7, rather than being computed early and save on the stack. This saves a push/pop and reduces maximum stack depth from 4 words to 3 words. Removed the last push and pop of the year. Ticks/bytes/ops/stack: 1218/262/221/3 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.20 2011/02/14 00:29:09 al Exp al $ d24 4 a27 4 ; Measurements, as of rev. 1.21: ; clock ticks: 1218 ; code bytes: 262 ; opcode fetches: 221 d51 19 a69 6 LD D, H ; DE = Year LD E, L LD A, 1 ; Let U2 = (Year & 511) + 133 - (Year >> 9) AND H LD H, A ; HL = Year & 511 LD A, D d71 4 a74 18 CPL ADD A, 134 ; A = 133 - (Year >> 9) LD C, A LD B, 0 ADD HL, BC ; HL = U2 (range 6 to 644) (U2 % 19 == Year % 19) LD A, 63 ; Let U5 = 7 * (U2 >> 6) + (U2 & 63) AND L ; A = U2 & 63 ADD HL, HL ADD HL, HL ; H = U2 >> 6 LD L, A LD A, H RLCA RLCA RLCA SUB H ; A = 7 * (U2 >> 6) ADD A, L LD L, A ; L = U5 (range 6 to 126) (U5 % 19 == Year % 19) RRA ; Let U6 = (((U5 >> 1) + U5 >> 2) + U5 >> 1) + U5 >> 5 << 4 d85 1 a85 1 RRA ; Let U7 = U5 - (((U6 >> 1) + U6 >> 3) + U6) d268 1 a268 1 ADD HL, DE ; Let U21 = (U20 >> 16 << 4) + ((U20 >> 6) & 7) d270 2 a271 2 RLA ; Let U22 = U21 + (U20 & 63) + ((U20 >> 9) & 127) RR H ; H = (U20 >> 9) & 63 @ 1.20 log @In %7, removed two 16-bit ops, and used a better plan for reducing numerator from 17 bits to 8 bits. Removed the last push and pop of the year. Doc fixes to %30. Ticks/bytes/ops/stack: 1228/261/223/4 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.19 2011/02/13 05:26:13 al Exp al $ d24 5 a28 5 ; Measurements, as of rev. 1.20: ; clock ticks: 1228 ; code bytes: 261 ; opcode fetches: 223 ; stack words: 4 (plus return address) d93 1 a93 1 LD C, A ; C = - U7 a95 1 ;;; C = - U7 = - (Year % 19) d97 1 a97 1 ;;; Stack = saved DE, Year d101 5 a105 8 LD H, D ; Let T1 = Year / 4 LD L, E SRL H RR L SRL H RR L PUSH HL ; Push T1 = Year / 4 PUSH BC ; Push -U7 (Golden Number) d107 1 a107 3 LD A, H LD H, B ; H = 0 OR A d114 1 d125 1 a125 1 SUB L a148 1 d150 1 a150 1 ;;; Stack = saved DE, Year, Year / 4, - Year % 19 d174 1 a174 1 ;;; Stack = saved DE, Year, Year / 4, - Year % 19 d183 3 a185 10 SBC HL, DE EX DE, HL ; DE = - T10 POP HL ; Let U13 = T1 - T10 LD A, L ; (move -U7 to A) POP HL ; Pop T1 ADD HL, DE PUSH HL ; Push U13 EX DE, HL ; Let U14 = T10 - U12 d187 1 a187 2 LD E, A ; (save -U7 to E) d201 1 a201 1 ;;; E = - U7 = - (Year % 19) d203 1 a203 1 ;;; Stack = saved DE, Year, U13 = Year / 4 - (Year / 100 - Year / 400) d227 2 a228 2 ;;; E = - U7 = - Year % 19 ;;; Stack = saved DE, Year, U13 = Year / 4 - (Year / 100 - Year / 400) d230 1 a230 1 LD C, A ; Let T19 = T18 * 16 + 53 + U7 ... d243 1 a243 1 LD A, H ; Let U18 = T18 + 28 + (T19 >> 9) d245 1 d247 1 a247 4 ADD A, 30 ADD A, C LD C, A ; C = U18 INC A ; Let U19 = U13 + U18 + 1 d249 11 a259 2 POP HL ; Pop U13 ADD HL, DE ; HL = U19 d261 1 a261 2 ;;; B = 0 ;;; C = U18 (= day-of-March of one week after Paschal full moon) d267 1 a267 1 POP DE ; DE = Year @ 1.19 log @In %7, when computing remainder, instead of computing (n - n/7*7)&255, just compute (n + n/7)&7. Alos, some doc fixes. Ticks/bytes/ops/stack: 1276/266/230/4 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.18 2011/02/13 01:49:53 al Exp al $ d24 4 a27 4 ; Measurements, as of rev. 1.19: ; clock ticks: 1276 ; code bytes: 266 ; opcode fetches: 230 d221 1 a221 1 RRA d224 2 a225 2 LD D, A ; D = T16 >> 1 RRA ; Let U16 = (T16 >> 5) + 1 + (T16 >> 1) >> 4 << 1 d235 3 a237 3 AND 30 ; A = U16 ADD A, L ; Let T18 = U16 + T16 & 31 AND 31 ; A = T18 = U16 % 30 d253 1 a253 1 SUB E ; A = 53 - U7 (E was negative) d276 5 a280 6 PUSH DE ; Let U21 = U19 + Year XOR A ; Let U22 = (U21 & 63) + ((U21 >> 6) & 63) + (U21 >> 12) ADD HL, DE RLA ; AHL = U21 LD E, L ; E = U21 & 255 ADD HL, HL d282 1 a282 1 ADD HL, HL d284 9 a292 15 LD D, H ; D = (U21 >> 6) & 255 RL H RLA RL H RLA LD B, A ; B = U21 >> 12 LD A, D LD H, 63 AND H LD D, A ; D = (U21 >> 6) & 63 LD A, E AND H ADD A, D ADD A, B LD D, A ; D = U22 (range 0 to 157) (U22 % 7 == U21 % 7) d295 1 a295 1 AND H d297 1 a297 1 ADD A, D d300 1 a300 1 AND H d302 1 a302 1 ADC A, D ; A = U23 d306 1 a306 1 ADD A, D d312 2 a313 1 ;;; Stack = saved DE, Year d315 1 a315 1 LD D, A ; D = U26 = Day-of-March d319 1 a319 1 SUB D d323 1 a323 1 LD A, D ; A = Day-of-March d325 1 a325 1 POP HL ; Pop Year @ 1.18 log @Two changes in %30: (1) Don't bother with the shift and add to get a smaller numerator. Instead, directly divide by 30 (well, by 2 and then by 15). (2) When computing remainder, instead of computing (n - n/30*30)&255, just compute (n + n/30*2)&31. Ticks/bytes/ops/stack: 1284/268/232 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.17 2011/02/11 06:14:18 al Exp al $ d24 4 a27 4 ; Measurements, as of rev. 1.17: ; clock ticks: 1284xx ; code bytes: 268x ; opcode fetches: 232xx d244 1 a244 1 LD C, A ; Let T19 = T18 * 16 + 53 - U7 ... d253 1 a253 1 SUB E ; A = 53 - U7 d298 1 a298 1 ADD A, B ; A = U22 d300 1 a300 1 RRA ; Let U23 = ((U22 >> 3) + U22 + 4 >> 3) + U22 & 248 d309 2 a310 4 ADC A, D AND 248 LD E, A ; E = U23 (= U22 / 7 * 8) RRA ; Let U25 = U22 - (U24 - (U24 >> 3)) d313 3 a315 3 SUB E ; A = - (U24 - (U24 >> 3)) ADD A, D ; A = U25 (= U21 % 7) SUB C ; Let U26 = U18 - U25 - 1 @ 1.17 log @Minor doc changes. @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.16 2011/02/11 06:09:24 al Exp al $ d25 3 a27 3 ; clock ticks: 1323 ; code bytes: 278 ; opcode fetches: 241 d133 1 a133 1 LD E, A ; E = T1 - BC*25 + 25 d219 1 a219 1 ;;; Compute T16 % 30 (unadjusted epact) (9-bit numerator): d221 1 a221 1 RRA ; Let U15 = (T16 & 31) + (T16 >> 5 << 1) d224 2 d228 1 d230 2 a231 7 AND 30 LD H, A ; H = T16 >> 5 << 1 LD A, L AND 31 ; A = T16 & 31 ADD A, H LD D, A ; D = U15 RRA ; Let U16 = ((U15 + 8 >> 4) + U15) & 224 a233 1 AND 31 d235 3 a237 9 ADC A, D AND 224 ; A = U16 LD H, A ; Let U17 = U15 - (U16 - (U16 >> 4)) RLCA RLCA RLCA RLCA SUB H ; A = - (U16 - (U16 >> 4)) ADD A, D ; A = U17 d239 1 a239 1 ;;; A = U17 = T18 = result of modulo 30 operation (unadjusted epact) d324 2 a325 2 ADD A, 224 ADC A, 32 @ 1.16 log @Minor doc changes. @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.15 2011/02/11 05:51:03 al Exp al $ d20 1 a21 1 ; No self-modifying code (suitable for ROMming) d24 1 a24 1 ; Measurements, as of rev. 1.16: @ 1.15 log @Some documentation improvements. I think I now consistently follow a rule that all named values are always positive. Moved the main function to the top of the file and the testing framework at the end. @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.14 2011/02/11 02:01:26 al Exp al $ d24 1 a24 1 ; Measurements, as of rev. 1.15: d62 1 a62 1 ADD HL, BC ; HL = U2 (range 6 to 644) d74 1 a74 1 LD L, A ; L = U5 (range 6 to 126) d124 1 a124 1 ADD A, A d133 2 a134 2 LD E, A ; E = remainder = (T1 - BC*25)&256 + 25 d148 2 a149 2 AND 15 ; A + BC - 1 is the correct quotient. @ 1.14 log @Cleaned up section between /25 and %30. Removed more 16-bit ops from %30. Ticks/bytes/ops/stack: 1323/278/241 @ text @d1 1 a1 66 ; $Id: computus.asm,v 1.13 2011/02/09 23:18:39 al Exp al $ ;;; Compute a large table of values in memory (suitable for using an ;;; emulator to dump out and compare to a known-good data set). Compare: LD HL, 0 LD BC, 0 ; 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 (suitable ;;; for using an emulator to dump out and compare to a known-good data ;;; set). Make_table: LD HL, 0 LD DE, 0x4000 LD BC, 0x8000 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 Align 5 d20 1 a20 1 ; No subroutine calls (completely relocatable code) a21 1 ; No data tables (PC and SP are the only addresses ever fetched) d24 1 a24 1 ; Measurements, as of rev. 1.14: d41 4 d49 1 a49 1 ;;; Compute Year % 19 (full 16-bit numerator): d86 1 a86 1 RRA ; Let U7 = ((U6 >> 1) + U6 >> 3) + U6 - U5 d93 1 a93 1 LD C, A ; C = U7 d96 1 a96 1 ;;; C = U7 = - Year % 19 d100 1 a100 1 ;;; Compute Year / 100 (14 bits in Year / 4): d109 1 a109 1 PUSH BC ; Push U7 (Golden Number) d158 2 a159 1 ;;; Compute (Year / 100 * 8 + 13) / 25 (10 bits in Year / 100): d193 1 a193 1 LD A, L ; (move U7 to A) d200 1 a200 1 LD E, A ; (move U7 to E) d202 1 a202 1 ADD A, A ; Let T16 = 225 + U7 * 11 + U14 d206 2 a207 2 ADD A, E ADD A, 225 ; A = 225 + U7 * 11 d215 1 a215 1 ;;; E = U7 = - Year % 19 d219 1 a219 1 ;;; Compute T16 % 30 (9-bit numerator): d250 1 a250 1 ;;; E = U7 = - Year % 19 d282 1 a282 1 ;;; Compute (U19 + Year) % 7 (17-bit numerator): d345 69 @ 1.13 log @Tidied register allocations. Reduced constant loads. Saved 15 ticks. Ticks/bytes/ops/stack: 1344/276/237/4 @ text @d1 1 a1 1 ; $Id$ d90 4 a93 4 ; Measurements, as of rev. 1.13: ; clock ticks: 1344 ; code bytes: 276 ; opcode fetches: 237 d137 1 a137 1 RRA ; Let U6 = ((((U5 >> 1) + U5 >> 2) + U5 >> 1) + U5 >> 1) & 240 d146 1 a146 1 AND 240 ; d214 1 a214 1 DEC HL a248 1 EX DE, HL d250 5 a254 4 SBC HL, DE ; HL = T10 POP DE ; Let U13 = T1 - T10 LD A, E ; A = U7 EX DE, HL ; DE = T10 d256 1 a256 1 SBC HL, DE ; d258 1 d260 3 a262 2 SBC HL, BC ; HL = U14 LD E, A d269 4 a272 2 LD C, A ADD HL, BC ; HL = T16 d274 1 d277 1 a277 1 ;;; HL = T16 = numerator for modulo 30 operation d282 11 a292 7 LD A, L ; Let U15 = (T16 & 31) + (T16 >> 5 << 1) AND 31 ; A = T16 & 31 ADD HL, HL ADD HL, HL ADD HL, HL SLA H ; H = T16 >> 5 << 1 ADD A, H ; (no carry - fits in 7 bits) d294 1 a294 2 RRA ; Let U16 = ((U15 + 8 >> 4) + U15) & 224 d336 1 a336 2 ADD HL, DE EX DE, HL ; DE = U19 d340 1 a340 1 ;;; DE = U19 (a 14-bit quantity) d345 2 a346 2 POP HL ; HL = Year PUSH HL ; Let U21 = U19 + Year d349 1 a349 1 RLA @ 1.12 log @Rewrote division by 100 to do two divisions, using mostly 8-bit ops. Started making more use of the carry bit. First revision that uses 10% fewer ticks than rev 1.1 (whose stats were 1513/294/249/4) Ticks/bytes/ops/stack: 1359/281/237/4 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.11 2011/02/09 07:34:21 al Exp al $ d90 3 a92 3 ; Measurements, as of rev. 1.12: ; clock ticks: 1359 ; code bytes: 281 d174 1 a211 1 LD H, 0 d230 2 a231 2 LD C, A LD B, 0 ; BC = 66 - (U10 >> 8) a268 1 LD C, E ; C = U7 d270 2 a271 2 ;;; C = U7 = - Year % 19 ;;; DE = T10 = Year / 100 - Year / 400 d284 1 a284 1 LD B, A ; B = U15 d291 1 a291 1 ADC A, B d299 1 a299 1 ADD A, B ; A = U17 d302 2 a303 1 ;;; C = U7 = - Year % 19 d306 1 a306 1 LD B, A ; Let T19 = T18 * 16 + 53 - U7 ... d311 1 a311 2 LD H, 0 LD D, H d315 2 a316 1 SUB C ; A = 53 - U7 d323 1 a323 1 ADD A, B d331 1 d355 2 a356 1 AND 63 d359 1 a359 1 AND 63 d365 1 a365 1 AND 63 d370 1 a370 1 AND 63 @ 1.11 log @Improved comments. Now there is a comment block at the beginning and end of each of the five major division/modulo sections. Cleaned up stack usage. The fourth stack word is now only used by a single push/pop pair (and the value being saved is only 5 bits (the golden number)). Ticks/bytes/ops/stack: 1408/274/231/4 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.10 2011/02/09 03:46:55 al Exp al $ d82 1 a82 2 ; starting with "T". Names I added start with U. Lines ; with extra indentation are unchanged code by Taylor. d90 4 a93 4 ; Measurements, as of rev. 1.10: ; clock ticks: 1408 ; code bytes: 274 ; opcode fetches: 231 d113 1 a113 1 LD D, H ; Let U1 = Year >> 1 d115 1 a115 3 SRL D RR E ; DE = U1 LD A, 1 ; Let U2 = (Year & 511) + 133 - (U1 >> 8) d118 4 a121 2 LD A, 133 SUB D ; A = 133 - (U1 >> 8) d124 7 a130 8 ADD HL, BC ; HL = U2 LD A, 63 ; Let U3 = U2 & 63 AND L ; A = U3 ADD HL, HL ; Let U4 = U2 >> 6 ADD HL, HL ; H = U4 LD L, A ; L = U3 LD A, H ; Let U5 = U4 << 3 - U4 + U3 RLCA d133 2 a134 1 SUB H d136 1 a136 1 LD L, A ; L = U5 d157 4 a160 3 ;;; BC = U7 = - Year % 19 ;;; DE = U1 = Year / 2 ;;; Stack = saved DE, Year, - Year % 19 d162 1 a162 1 ;;; Compute (Year / 4) / 25 (14-bit numerator): d164 1 a164 1 LD H, D ; Let U8 = (U1 >> 2) + U1 d168 2 d172 10 a181 7 SRL H RR L ADD HL, DE ; (no carry) LD B, H LD C, L ; BC = U8 SUB A ; Let U9 = T7 = (U1 - (U8 >> 5) + 16 >> 5) + U8 >> 6, ADD HL, HL d183 23 a205 1 ADD HL, HL a206 1 ADD HL, HL a207 8 LD L, H LD H, A ; HL = U8 >> 5 EX DE, HL SBC HL, DE ; HL = U1 - (U8 >> 5) (carry was clear) LD DE, 16 ADD HL, DE ; HL = U1 - (U8 >> 5) + 16 SUB A ADD HL, HL d209 7 a215 14 ADD HL, HL RLA ADD HL, HL RLA LD L, H LD H, A ; HL = U1 - (U8 >> 5) + 16 >> 5 ADD HL, BC ; HL = (U1 - (U8 >> 5) + 16 >> 5) + U8 SUB A ADD HL, HL RLA ADD HL, HL RLA LD L, H LD H, A ; HL = U9 = Year / 100 d220 1 a220 1 ;;; Compute (Year / 100 * 8 + 13) / 25 (13-bit numerator): a259 6 ;;; A = U7 = - Year % 19 ;;; BC = U12 = (Year / 100 * 8 + 13) / 25 ;;; HL = U14 ;;; Stack = saved DE, Year, U13 = Year / 4 - (Year / 100 - Year / 400) d287 6 a292 7 RRCA ; Let U16 = ((U15 >> 4) + U15 + 1) & 224 RRCA RRCA RRCA AND 15 ; A = U15 >> 4 ADD A, B INC A @ 1.10 log @Fixed wrong comment about U1. @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.9 2011/02/09 03:41:57 al Exp al $ d91 4 a94 4 ; Measurements, as of rev. 1.8: ; clock ticks: 1417 ; code bytes: 273 ; opcode fetches: 230 d111 3 d158 1 a158 1 ;;; C = U7 = - Year % 19 d160 3 a162 1 ;;; Stack = saved DE, Year d169 1 a172 1 PUSH BC ; Push U7 (Golden Number) d206 2 a207 2 ;;; HL = Year / 100 ;;; Stack = saved DE, Year, Year / 4, - Year % 19 (with trash in the high byte) d209 2 d227 5 d241 8 a248 3 POP DE ; E = U7 PUSH HL SBC HL, BC ; HL = T10 - U12 d250 1 a250 1 ;;; A = 0 d252 2 a253 2 ;;; E = U7 = - Year % 19 ;;; Stack = saved DE, Year, Year / 4, T10 = Year / 100 - Year / 400 d255 2 a256 2 LD A, E ; Let T16 = 225 + U7 * 11 + T10 - U12 ADD A, A a264 1 POP DE d269 3 a271 1 ;;; Stack = saved DE, Year, T1 = Year / 4, a281 4 POP HL ; Pop T1 SBC HL, DE ; HL = T1 - T10 (carry was clear) PUSH HL ; Push T1-T10 d300 1 a300 1 ;;; Stack = saved DE, Year, T1 - T10 = Year / 4 - (Year / 100 - Year / 400), d321 1 a321 1 INC A d323 1 a323 1 POP HL ; HL = T1 - T10 d325 1 a325 1 EX DE, HL ; DE = U19 = T1 - T10 + U18 + 1 d330 2 a331 1 ;;; The sum of U19 and Year form a 17-bit numerator for the modulo 7 operation d355 3 a357 8 ADD A, B ; A = U22 ;;; A = U22 = 8-bit numerator (0 to 157) for modulo 7 operation ;;; C = U18 (= day-of-March of one week after Paschal full moon) ;;; Stack = saved DE, Year LD D, A ; D = U22 RRA ; Let U23 = ((U22 >> 3) + U22 + 4 >> 3) + U22 & 248 @ 1.9 log @In modulo 19 op, saved 8 ticks by using the trick of not bothering to shift the quotient before starting to use it. Ticks/bytes/ops/stack: 1417/273/230/4 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.8 2011/02/09 02:06:07 al Exp al $ d156 1 a156 1 ;;; DE = U1 = Year / 4 @ 1.8 log @Removed useless last shift and add in division by 7. Saved 21 ticks. Ticks/bytes/ops/stack: 1425/275/233/4 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.7 2011/02/09 01:14:49 al Exp al $ d92 3 a94 3 ; clock ticks: 1425 ; code bytes: 275 ; opcode fetches: 233 d112 1 a112 1 LD A, L d114 1 a114 2 RRA LD E, A ; DE = U1 d135 1 a135 1 RRA ; Let U6 = (((U5 >> 1) + U5 >> 2) + U5 >> 1) + U5 >> 5 d143 2 a144 4 RLCA RLCA RLCA AND 7 ; d146 1 a146 3 RLA ; Let U7 = ((U6 << 3) + U6 << 1) + U6 - U5 RLA RLA ; A = U6 << 3 d148 3 a150 1 RLA ; A = (U6 << 3) + U6 << 1 @ 1.7 log @Code at end to convert day of March to month and day improved from 52 to 49 ticks. This is still 10 ticks worse than the conditional return that Taylor uses. Ticks/bytes/ops/stack: 1446/280/239/4 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.6 2011/02/08 21:57:07 al Exp al $ d91 4 a94 4 ; Measurements, as of rev. 1.7: ; clock ticks: 1446 ; code bytes: 280 ; opcode fetches: 239 d350 1 a350 1 LD E, 63 ; Let U23 = (((U22 >> 3) + U22 + 4 >> 3) + U22 >> 3) + U22 & 248 d352 1 a352 2 RRA AND E d357 1 a357 1 AND E a359 5 RRA RRA AND E RRA ADD A, D @ 1.6 log @Ticks/bytes/ops/stack: 1449/281/240/4 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.5 2011/02/08 18:02:07 al Exp al $ d91 4 a94 4 ; Measurements, as of rev. 1.6: ; clock ticks: 1449 ; code bytes: 281 ; opcode fetches: 240 d379 6 a384 4 LD D, A ; D = Day of March SUB 32 SBC A, A ADD A, 4 d386 2 a387 5 SUB 3 ADD A, D AND 31 LD B, A ; B = Day of Month LD A, D ; A = Day of March @ 1.5 log @Removed both NEG ops. Replaced one with a CPL. Other one only required exchanging SUB and ADD ops. Ticks/bytes/ops/stack: 1464/285/243/4 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.4 2011/02/08 09:40:33 al Exp al $ d91 4 a94 4 ; Measurements, as of rev. 1.5: ; clock ticks: 1464 ; code bytes: 285 ; opcode fetches: 243 d221 2 a222 4 ADD HL, HL ; Let U12 (= T13) = U11 >> 7 POP BC LD B, H ; B = U12 d232 3 a234 2 PUSH HL ; Push T10 LD E, B ; E = U12 d237 2 a238 2 ;;; C = U7 = - Year % 19 ;;; E = U12 = T13 = (Year / 100 * 8 + 13) / 25 d241 1 a241 1 LD A, C ; Let T16 = 225 + U7 * 11 + T10 - T13 d244 1 a244 1 ADD A, C d246 1 a246 1 ADD A, C d248 4 a251 7 LD H, 0 LD L, A LD D, H ; DE = T13 XOR A SBC HL, DE POP DE ; Pop T10 ADD HL, DE ; HL = T16 @ 1.4 log @Ticks/bytes/ops/stack: 1479/289/244/4 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.3 2011/02/08 07:58:35 al Exp al $ d91 4 a94 4 ; Measurements, as of rev. 1.4: ; clock ticks: 1479 ; code bytes: 289 ; opcode fetches: 244 d106 2 a107 2 ; IX, IY, and the alternate registers are untouched ; (i.e., are free to be used by interrupt routines) d149 1 a149 1 RLA ; Let U7 (= T5) = U5 - (((U6 << 3) + U6 << 1) + U6) a155 1 NEG d158 1 a158 1 ;;; C = U7 = Year % 19 d205 1 a205 1 ;;; Stack = saved DE, Year, Year / 4, Year % 19 (with trash in the high byte) d238 1 a238 1 ;;; C = T5 = Year % 19 d242 1 a242 1 SUB C ; Let T16 = 225 - T5 * 11 + T10 - T13 d245 1 a245 1 SUB C d247 2 a248 2 SUB C ADD A, 225 ; A = 225 - T5 * 11 d257 1 a257 1 ;;; C = T5 = Year % 19 a289 1 LD D, 0 d292 1 a292 2 ;;; C = T5 = Year % 19 ;;; D = 0 d295 21 a315 21 LD B, A ; Let T19 = T18 * 16 + T5 + 53 ... ADD A, A ADD A, A ADD A, A ADD A, A LD H, D ; H = 0 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 Let T20 = T18 + 27 Else Let T20 = T18 + 28 RRA CPL ADD A, 29 ADD A, B ; A = T20 LD C, A ; C = T20 ADD A, 2 LD E, A ; DE = T20 + 2 d318 1 a318 1 EX DE, HL ; DE = U19 = T1 - T10 + T20 + 2 d320 1 a320 1 ;;; C = T20 (= day-of-March of eighth day after Paschal full moon) d350 1 a350 1 ;;; C = T20 (= day-of-March of eighth day after Paschal full moon) d377 2 a378 2 SUB C ; Let U26 = T20 - U25 NEG ; A = U26 @ 1.3 log @Added Taylor's version, and a Compare routine to pass all 64k years to both functions and check that all three results (month, day, and day-of-March) match for each year. @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.2 2011/02/08 06:55:31 al Exp al $ d91 4 a94 4 ; Measurements, as of rev. 1.2: ; clock ticks: 1509 ; code bytes: 293 ; opcode fetches: 248 d238 1 d243 14 a256 18 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 @ 1.2 log @Ticks/bytes/ops/stack: 1509/293/248/4 @ text @d1 1 a1 1 ; $Id: computus.asm,v 1.1 2011/02/08 04:38:07 al Exp al $ d3 2 a4 3 ;;; Simple framework to compute a large table of values in memory ;;; (suitable for using an emulator to dump out and ;;; compare to a known-good data set). d6 42 d51 1 a51 1 Loop: d59 1 a59 1 JR NZ, Loop d61 1 a61 1 JR NZ, Loop a64 3 Align 4 Y2010: DEFB 0 d66 1 a66 5 Align 4 Y2011: DEFB 0 Align 4 d68 1 a68 1 ; Z-80 Computus d70 38 a107 38 ; 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 . ; Derived from a version by Ian Taylor ; dated January 2011. I rewrote and sped up the code for ; the five major division/modulo operations (divisors 19, ; 100, 25, 30, and 7). I also removed all branching. Some ; of the miscellaneous values named by Taylor have names ; starting with "T". Names I added start with U. Lines ; with extra indentation are unchanged code by Taylor. ; Features: ; No subroutine calls (completely relocatable code) ; No self-modifying code (suitable for ROMming) ; No data tables (PC and SP are the only addresses ever fetched) ; No branching (just put one foot in front of the other) ; Measurements, as of rev. 1.2: ; clock ticks: 1509 ; code bytes: 293 ; opcode fetches: 248 ; stack words: 4 (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 untouched ; (i.e., are free to be used by interrupt routines) d402 311 @ 1.1 log @Initial revision @ text @d1 2 a2 2 ; $Id$ d34 1 a34 1 ; Z-80 Computus (ver. 1.0, February 7, 2011) d57 4 a60 4 ; Measurements (I went for speed over compactness): ; clock ticks: 1513 ; code bytes: 294 ; opcode fetches: 249 d326 1 a326 1 LD E, 31 ; Let U23 = (((U22 >> 3) + U22 + 4 >> 3) + U22 >> 3) + U22 & 248 d329 1 a330 1 AND E a333 2 INC A RRA a334 1 ADD A, D d336 1 d340 1 @