7 ; stack and control transfer
117 .org page0 * 0x100 + 0x88
185 page0_imm_xchg_stkst_w:
218 ; the non-immediate stack load/store is hardly ever used and only for symmetry
279 ; word arithmetic operations
280 ; top stack word cached in de
300 page1_imm_xchg_stkst_w:
400 page1_imm_xor_w: ; xor is less common than and/or, so save space for immediate
422 page1_imm_add_w: ; use also for page1_imm_sub_w with negated argument
440 page1_imm_xchg_sub_w: ; reversed, use with argument 0 for neg, -1 for cpl
499 page1_imm_sl_w: ; nonzero unsigned byte argument
507 page1_imm_sr_uw: ; nonzero unsigned byte argument
517 page1_imm_sr_sw: ; nonzero unsigned byte argument
550 page1_imm_mul_w: ; big endian argument
559 jp mul ; a shame it can't be jr
574 page1_lt_sw: ; put this at the end because it's the longest one
657 divpp: ; positive dividend, positive divisor
685 jp p,divp ; positive dividend
688 dec hl ; reduces remainder by 1 (we inc later)
692 jr nc,divnp ; a shame it can't be a fallthru
693 jr divnn ; negative dividend, negative divisor
695 mul_w: ; mul placed as soon as possible after all div entry points
744 divp: ; positive dividend
748 jr nc,divpp ; positive dividend, positive divisor
750 ; positive dividend, negative divisor
763 divnp: ; negative dividend, positive divisor
771 1$: inc hl ; get into range -divisor+1..0
777 divnn: ; negative dividend, negative divisor
784 1$: inc hl ; get into range divisor+1..0
790 ; non-restoring division routine
792 ; de = divisor, hl:a = dividend with hl = previous remainder, a = next byte
793 ; enter at div0 with positive remainder in hl, such that hl < de
794 ; enter at div1 with negative remainder in hl, such that hl >= -de
796 ; div0/1 return a = 8-bit quotient as an odd number interpreted as -ff..ff,
797 ; by summing positive/negative place values, e.g. -80 +40 +20 -10 +8 -4 -2 +1
799 ; if entered at div0, there is a -80 and so quotient is in range -ff..-1
800 ; if entered at div1, there is a +80 and so quotient is in range 1..ff
801 ; falls out of loop after div01 with positive remainder, div11 with negative,
802 ; depending on this we should re-enter at div0 or div1, signalled by cf return
804 ; the successive quotient bytes can be concatenated into a full quotient,
805 ; but negative bytes require the next higher quotient byte to be decremented,
806 ; we know in advance if this will happen because the implied sign of the
807 ; quotient byte depends only on whether we entered at div0 or div1, hence,
808 ; before the div11 return we'll decrement to compensate for next negative byte
810 ; the decrement can also be seen as compensating for the extra add hl,de that
811 ; may be needed to make negative remainder positive before return to caller,
812 ; thus leaving quotient in a consistent state regardless of which exit taken,
813 ; remainder needs the add hl,de if cf=1 returned (equiv. return byte is even)
815 ; in the following code each sbc hl,de gets an inc a and each add hl,de gets
816 ; a dec a, guaranteeing the integrity of the division, the initial scf/rla is
817 ; needed to make the result 100 + -ff..ff or 1..1ff, so that the decrements
818 ; cannot borrow into the upcoming dividend bits also held in a, and there must
819 ; be another shift between the scf/rla and increment/decrement so that the scf
820 ; is implicitly in the 100s place, making the code awkward though it's correct
822 ; now optimized to only inc/dec a when doing zero-crossing, fix above analysis
832 div11: ; bit 1, below
838 div02: ; bit 2, above
844 div13: ; bit 3, below
850 div04: ; bit 4, above
856 div15: ; bit 5, below
862 div06: ; bit 6, above
868 div17: ; bit 7, below
886 div01: ; bit 1, above
892 div12: ; bit 2, below
898 div03: ; bit 3, above
904 div14: ; bit 4, below
910 div05: ; bit 5, above
916 div16: ; bit 6, below
922 div07: ; bit 7, above
931 ;dec a ; compensation
935 ; divn0/1 are the same as div0/1 but carry reversed after add/subtract divisor
936 ; this is for negative divisors where we expect carry (means no zero crossing)
938 ; when divisor negated, remainder also negated, so we expect to do subtraction
939 ; when remainder negative and vice versa, need to clear carry after add hl,hl
942 divn0: ; bit 0, above
950 divn11: ; bit 1, below
956 divn02: ; bit 2, above
963 divn13: ; bit 3, below
969 divn04: ; bit 4, above
976 divn15: ; bit 5, below
982 divn06: ; bit 6, above
989 divn17: ; bit 7, below
995 divn08: ; done, above
1001 divn1: ; bit 0, below
1007 divn01: ; bit 1, above
1014 divn12: ; bit 2, below
1020 divn03: ; bit 3, above
1027 divn14: ; bit 4, below
1033 divn05: ; bit 5, above
1040 divn16: ; bit 6, below
1046 divn07: ; bit 7, above
1053 divn18: ; done, below
1056 ;dec a ; compensation
1134 .ascii '0123456789abcdef'
1148 ; create stack frame
1149 .db <page0_imm_stkadj
1156 ; push result pointer
1157 .db <page1_imm_stkptr
1160 ; call sm_factorial(argument)
1166 .db <page0_imm_stkld_w
1168 .db <page1_imm_div_sw
1170 .db <page1_imm_xchg_stkst_w
1180 .db <page0_imm_stkld_w
1182 .db <page1_imm_div_sw
1184 .db <page1_imm_xchg_stkst_w
1194 .db <page0_imm_stkld_w
1196 .db <page1_imm_div_sw
1198 .db <page1_imm_xchg_stkst_w
1208 .db <page0_imm_stkld_w
1210 .db <page1_imm_div_sw
1212 .db <page1_imm_xchg_stkst_w
1222 .db <page0_imm_stkld_w
1244 ; destroy stack frame
1245 .db <page0_imm_stkadj
1254 .db <page0_imm_stkld_w
1258 .db <page1_imm_gt_sw
1260 .db <page0_imm_jfalse
1263 ; no, set up for *result =
1264 .db <page0_imm_stkld_w
1268 .db <page1_imm_stkld_w
1272 .db <page1_imm_add_w
1275 ; push result pointer
1276 .db <page1_imm_stkptr
1279 ; call sm_factorial(argument - 1)
1285 .db <page0_imm_stkld_w
1291 ; set *result = sm_factorial(argument - 1) * argument
1299 ; yes, set up for *result =
1300 .db <page0_imm_stkld_w