7 ; stack and control transfer
100 .org page0 * 0x100 + 0x84
250 ; word arithmetic operations
251 ; top stack word cached in de
359 page1_imm_xor_w: ; xor is less common than and/or, so save space for immediate
381 page1_imm_add_w: ; use also for page1_imm_sub_w with negated argument
399 page1_imm_xchg_sub_w: ; reversed, use with argument 0 for neg, -1 for cpl
458 page1_imm_sl_w: ; nonzero unsigned byte argument
466 page1_imm_sr_uw: ; nonzero unsigned byte argument
476 page1_imm_sr_sw: ; nonzero unsigned byte argument
509 page1_imm_mul_w: ; big endian argument
518 jp mul ; a shame it can't be jr
533 page1_lt_sw: ; put this at the end because it's the longest one
616 divpp: ; positive dividend, positive divisor
644 jp p,divp ; positive dividend
647 dec hl ; reduces remainder by 1 (we inc later)
651 jr nc,divnp ; a shame it can't be a fallthru
652 jr divnn ; negative dividend, negative divisor
654 mul_w: ; mul placed as soon as possible after all div entry points
703 divp: ; positive dividend
707 jr nc,divpp ; positive dividend, positive divisor
709 ; positive dividend, negative divisor
722 divnp: ; negative dividend, positive divisor
730 1$: inc hl ; get into range -divisor+1..0
736 divnn: ; negative dividend, negative divisor
743 1$: inc hl ; get into range divisor+1..0
749 ; non-restoring division routine
751 ; de = divisor, hl:a = dividend with hl = previous remainder, a = next byte
752 ; enter at div0 with positive remainder in hl, such that hl < de
753 ; enter at div1 with negative remainder in hl, such that hl >= -de
755 ; div0/1 return a = 8-bit quotient as an odd number interpreted as -ff..ff,
756 ; by summing positive/negative place values, e.g. -80 +40 +20 -10 +8 -4 -2 +1
758 ; if entered at div0, there is a -80 and so quotient is in range -ff..-1
759 ; if entered at div1, there is a +80 and so quotient is in range 1..ff
760 ; falls out of loop after div01 with positive remainder, div11 with negative,
761 ; depending on this we should re-enter at div0 or div1, signalled by cf return
763 ; the successive quotient bytes can be concatenated into a full quotient,
764 ; but negative bytes require the next higher quotient byte to be decremented,
765 ; we know in advance if this will happen because the implied sign of the
766 ; quotient byte depends only on whether we entered at div0 or div1, hence,
767 ; before the div11 return we'll decrement to compensate for next negative byte
769 ; the decrement can also be seen as compensating for the extra add hl,de that
770 ; may be needed to make negative remainder positive before return to caller,
771 ; thus leaving quotient in a consistent state regardless of which exit taken,
772 ; remainder needs the add hl,de if cf=1 returned (equiv. return byte is even)
774 ; in the following code each sbc hl,de gets an inc a and each add hl,de gets
775 ; a dec a, guaranteeing the integrity of the division, the initial scf/rla is
776 ; needed to make the result 100 + -ff..ff or 1..1ff, so that the decrements
777 ; cannot borrow into the upcoming dividend bits also held in a, and there must
778 ; be another shift between the scf/rla and increment/decrement so that the scf
779 ; is implicitly in the 100s place, making the code awkward though it's correct
781 ; now optimized to only inc/dec a when doing zero-crossing, fix above analysis
791 div11: ; bit 1, below
797 div02: ; bit 2, above
803 div13: ; bit 3, below
809 div04: ; bit 4, above
815 div15: ; bit 5, below
821 div06: ; bit 6, above
827 div17: ; bit 7, below
845 div01: ; bit 1, above
851 div12: ; bit 2, below
857 div03: ; bit 3, above
863 div14: ; bit 4, below
869 div05: ; bit 5, above
875 div16: ; bit 6, below
881 div07: ; bit 7, above
890 ;dec a ; compensation
894 ; divn0/1 are the same as div0/1 but carry reversed after add/subtract divisor
895 ; this is for negative divisors where we expect carry (means no zero crossing)
897 ; when divisor negated, remainder also negated, so we expect to do subtraction
898 ; when remainder negative and vice versa, need to clear carry after add hl,hl
901 divn0: ; bit 0, above
909 divn11: ; bit 1, below
915 divn02: ; bit 2, above
922 divn13: ; bit 3, below
928 divn04: ; bit 4, above
935 divn15: ; bit 5, below
941 divn06: ; bit 6, above
948 divn17: ; bit 7, below
954 divn08: ; done, above
960 divn1: ; bit 0, below
966 divn01: ; bit 1, above
973 divn12: ; bit 2, below
979 divn03: ; bit 3, above
986 divn14: ; bit 4, below
992 divn05: ; bit 5, above
999 divn16: ; bit 6, below
1005 divn07: ; bit 7, above
1012 divn18: ; done, below
1015 ;dec a ; compensation
1093 .ascii '0123456789abcdef'
1107 ; create stack frame
1115 ; push result pointer
1119 ; call sm_factorial(argument)
1127 .db <page1_imm_div_sw
1141 .db <page1_imm_div_sw
1155 .db <page1_imm_div_sw
1169 .db <page1_imm_div_sw
1203 ; destroy stack frame
1217 .db <page1_imm_gt_sw
1219 .db <page0_imm_jfalse
1222 ; no, set up for *result =
1231 .db <page1_imm_add_w
1234 ; push result pointer
1238 ; call sm_factorial(argument - 1)
1250 ; set *result = sm_factorial(argument - 1) * argument
1258 ; yes, set up for *result =