Unroll slightly to avoid an inner loop jump to loop end on zero crossing
[stack_machine.git] / sm3.asm
1 page0   =       4
2 page1   =       6
3 page2   =       8
4
5         .area   SM (abs,ovr)
6
7         .org    0x100
8
9         ld      hl,0x1234
10         ld      de,0x56
11         call    math_mul_uw0
12         call    print_hlde
13         call    math_div_uw
14         call    print_hlde
15
16         ld      hl,0x6543
17         ld      de,0x21
18         call    math_mul_uw0
19         call    print_hlde
20         call    math_div_uw
21         call    print_hlde
22
23         ld      hl,0xb975
24         ld      de,0x31
25         call    math_mul_uw0
26         call    print_hlde
27         call    math_div_uw
28         call    print_hlde
29
30         ld      hl,0xdb97
31         ld      de,0x531
32         call    math_mul_uw0
33         call    print_hlde
34         call    math_div_uw
35         call    print_hlde
36
37         ld      hl,0x1234
38         ld      de,0x56
39         call    math_mul_sw0
40         call    print_hlde
41         call    math_div_sw
42         call    print_hlde
43
44         ld      hl,0x6543
45         ld      de,0x21
46         call    math_mul_sw0
47         call    print_hlde
48         call    math_div_sw
49         call    print_hlde
50
51         ld      hl,0xb975
52         ld      de,0x31
53         call    math_mul_sw0
54         call    print_hlde
55         call    math_div_sw
56         call    print_hlde
57
58         ld      hl,0xdb97
59         ld      de,0x531
60         call    math_mul_sw0
61         call    print_hlde
62         call    math_div_sw
63         call    print_hlde
64
65         ld      hl,-0x1234
66         ld      de,0x56
67         call    math_mul_sw0
68         call    print_hlde
69         call    math_div_sw
70         call    print_hlde
71
72         ld      hl,-0x6543
73         ld      de,0x21
74         call    math_mul_sw0
75         call    print_hlde
76         call    math_div_sw
77         call    print_hlde
78
79         ld      hl,-0xb975
80         ld      de,0x31
81         call    math_mul_sw0
82         call    print_hlde
83         call    math_div_sw
84         call    print_hlde
85
86         ld      hl,-0xdb97
87         ld      de,0x531
88         call    math_mul_sw0
89         call    print_hlde
90         call    math_div_sw
91         call    print_hlde
92
93         ld      hl,0x1234
94         ld      de,-0x56
95         call    math_mul_sw0
96         call    print_hlde
97         call    math_div_sw
98         call    print_hlde
99
100         ld      hl,0x6543
101         ld      de,-0x21
102         call    math_mul_sw0
103         call    print_hlde
104         call    math_div_sw
105         call    print_hlde
106
107         ld      hl,0xb975
108         ld      de,-0x31
109         call    math_mul_sw0
110         call    print_hlde
111         call    math_div_sw
112         call    print_hlde
113
114         ld      hl,0xdb97
115         ld      de,-0x531
116         call    math_mul_sw0
117         call    print_hlde
118         call    math_div_sw
119         call    print_hlde
120
121         ld      hl,-0x1234
122         ld      de,-0x56
123         call    math_mul_sw0
124         call    print_hlde
125         call    math_div_sw
126         call    print_hlde
127
128         ld      hl,-0x6543
129         ld      de,-0x21
130         call    math_mul_sw0
131         call    print_hlde
132         call    math_div_sw
133         call    print_hlde
134
135         ld      hl,-0xb975
136         ld      de,-0x31
137         call    math_mul_sw0
138         call    print_hlde
139         call    math_div_sw
140         call    print_hlde
141
142         ld      hl,-0xdb97
143         ld      de,-0x531
144         call    math_mul_sw0
145         call    print_hlde
146         call    math_div_sw
147         call    print_hlde
148
149         ld      hl,0xdb97
150         ld      de,0x7531
151         exx
152         ld      hl,0x1357
153         ld      de,0xfdb9
154         exx
155         call    math_mul_ul0
156         call    print_hlhldede
157         call    math_div_ul
158         call    print_hlhldede
159
160         ld      hl,0xdb97
161         ld      de,0x7531
162         exx
163         ld      hl,0x1357
164         ld      de,0xfdb9
165         exx
166         call    math_mul_sl0
167         call    print_hlhldede
168         call    math_div_sl
169         call    print_hlhldede
170
171         ld      hl,~0xdb97
172         ld      de,0x7531
173         exx
174         ld      hl,~0x1357
175         ld      de,0xfdb9
176         exx
177         call    math_mul_sl0
178         call    print_hlhldede
179         call    math_div_sl
180         call    print_hlhldede
181
182         ld      hl,0xdb97
183         ld      de,~0x7531
184         exx
185         ld      hl,0x1357
186         ld      de,~0xfdb9
187         exx
188         call    math_mul_sl0
189         call    print_hlhldede
190         call    math_div_sl
191         call    print_hlhldede
192
193         ld      hl,~0xdb97
194         ld      de,~0x7531
195         exx
196         ld      hl,~0x1357
197         ld      de,~0xfdb9
198         exx
199         call    math_mul_sl0
200         call    print_hlhldede
201         call    math_div_sl
202         call    print_hlhldede
203
204         ld      hl,restarts
205         ld      de,0x28
206         ld      bc,restarts_end - restarts
207         ldir
208
209         ld      bc,sm_start
210         jp      page0_dispatch0
211 sm_start:
212         .db     <page0_imm_call
213         .dw     sm_main
214         .dw     0
215         .db     <page0_esc
216         jp      0
217
218 restarts:
219         ; rst 0x28, immediate to hl
220         ld      a,(bc)
221         inc     bc
222         ld      l,a
223         ld      a,(bc)
224         inc     bc
225         ld      h,a
226         ret
227         .db     0
228         ; rst 0x30, pop hl:de'
229         ;pop    hl
230         ;exx
231         ;pop    de
232         ;exx
233         ;ex     (sp),hl
234         ;ret
235         .db     0,0,0,0,0,0
236         .db     0,0
237         ; rst 0x38, immediate to de':hl
238         ld      a,(bc)
239         inc     bc
240         ld      l,a
241         ld      a,(bc)
242         inc     bc
243         ld      h,a
244         ld      a,(bc)
245         inc     bc
246         exx
247         ld      e,a
248         exx
249         ld      a,(bc)
250         inc     bc
251         exx
252         ld      d,a
253         exx
254         ret
255 restarts_end:
256
257 ; page 0 interpreter
258 ; stack and control transfer
259
260         .org    page0 * 0x100 - 18
261
262 page0_dispatch0:
263         ld      a,(bc)
264         inc     bc
265         ld      l,a
266         ld      h,page0
267         jp      (hl)
268
269 page0_dispatch1:
270         ld      a,(bc)
271         inc     bc
272         ld      l,a
273         ld      h,page1
274         jp      (hl)
275
276 page0_dispatch2:
277         ld      a,(bc)
278         inc     bc
279         ld      l,a
280         ld      h,page2
281         jp      (hl)
282
283 ; page 0 administrative
284
285 page0_trace:
286         jp      print_trace
287
288 page0_esc:
289         ld      l,c
290         ld      h,b
291         jp      (hl)
292
293 ; page 0 to 0
294
295 page0_jeq:
296         jr      nz,not_taken
297 page0_imm_jmp:
298         rst     0x28
299         ld      c,l
300         ld      b,h
301         jr      page0_dispatch0
302
303 page0_jne:
304         jr      nz,page0_imm_jmp
305 not_taken:
306         inc     bc
307         inc     bc
308         jr      page0_dispatch0
309
310 page0_jlt:
311         jr      c,page0_imm_jmp
312         jr      not_taken
313
314 page0_jge:
315         jr      nc,page0_imm_jmp
316         jr      not_taken
317
318 page0_imm_call:
319         rst     0x28
320         push    bc
321         ld      c,l
322         ld      b,h
323         jr      page0_dispatch0
324
325 page0_ret:
326         pop     bc
327 page0_stkadj:
328         rst     0x28
329         add     hl,sp
330         ld      sp,hl
331         jr      page0_dispatch0
332
333 ; page 0 to 1
334
335 page0_page1:
336         pop     de
337         jr      page0_dispatch1
338
339 page0_peq:
340         call    test_eq
341         jr      page0_dispatch1
342
343 page0_pne:
344         call    test_ne
345         jr      page0_dispatch1
346
347 page0_plt:
348         call    test_lt
349         jr      page0_dispatch1
350
351 page0_pge:
352         call    test_ge
353         jr      page0_dispatch1
354
355 page0_stkptr:
356         rst     0x28
357         add     hl,sp
358         ex      de,hl
359         jr      page0_dispatch1
360
361 page0_stkld_w:
362         ;call   math_stkld_w
363         ;jr     page0_dispatch1
364         jp      math_stkld_w
365
366 page0_imm_w:
367         ;call   math_imm_w
368         ;jr     page0_dispatch1
369         jp      math_imm_w
370
371 ; page 0 to 2
372
373 page0_page2:
374         pop     de
375         exx
376         pop     hl
377         exx
378         jr      page0_dispatch2
379
380 page0_stkld_l:
381         ;call   math_stkld_l
382         ;jr     page0_dispatch2
383         jp      math_stkld_l
384
385 page0_imm_l:
386         ;call   math_imm_l
387         ;jr     page0_dispatch2
388         jp      math_imm_l
389
390 ; page 1 interpreter
391 ; word arithmetic operations
392 ; top stack word cached in de
393
394         .org    page1 * 0x100 - 13
395
396 page1_dispatch0:
397         ld      a,(bc)
398         inc     bc
399         ld      l,a
400         ld      h,page0
401         jp      (hl)
402
403 add_w_done:
404         ex      de,hl
405 page1_dispatch1:
406         ld      a,(bc)
407         inc     bc
408         ld      l,a
409         ld      h,page1
410         jp      (hl)
411
412 ; page 1 administrative
413
414 page1_trace:
415         jp      print_trace
416
417 ; page 1 to 0
418
419 page1_page0:
420         push    de
421         jr      page1_dispatch0
422
423 page1_call:
424         push    bc
425 page1_jmp:
426         ld      c,e
427         ld      b,d
428         jr      page1_dispatch0
429
430 page1_stkst_w:
431         ;call   math_stkst_w
432         ;jr     page1_dispatch0
433         jp      math_stkst_w
434
435 page1_st_w:
436         pop     hl
437         ld      (hl),e
438         inc     hl
439         ld      (hl),d
440         jr      page1_dispatch0
441
442 page1_imm_cmprev_sw:
443         rst     0x28
444         .db     0x3e ; ld a,
445 page1_cmp_sw:
446         pop     hl
447         ;call   math_cmprev_sw
448         ;jr     page1_dispatch0
449         jp      math_cmprev_sw
450
451 page1_imm_cmp_sw:
452         rst     0x28
453         .db     0x3e ; ld a,
454 page1_cmprev_sw:
455         pop     hl
456         ;call   math_cmp_sw
457         ;jr     page1_dispatch0
458         jp      math_cmp_sw
459
460 page1_imm_cmprev_uw:
461         rst     0x28
462         .db     0x3e ; ld a,
463 page1_cmp_uw:
464         pop     hl
465         or      a
466         sbc     hl,de
467         jr      page1_dispatch0
468
469 page1_imm_cmp_uw:
470         rst     0x28
471         .db     0x3e ; ld a,
472 page1_cmprev_uw:
473         pop     hl
474         ex      de,hl
475         or      a
476         sbc     hl,de
477         jr      page1_dispatch0
478
479 ; page 1 to 1
480
481 page1_ld_w:
482         ex      de,hl
483         ld      e,(hl)
484         inc     hl
485         ld      d,(hl)
486         jr      page1_dispatch1
487
488 page1_imm_and_w:
489         ;call   math_and_imm_w
490         ;jr     page1_dispatch1
491         jp      math_and_imm_w
492
493 page1_and_w:
494         pop     hl
495         ;call   math_and_w
496         ;jr     page1_dispatch1a
497         jp      math_and_w
498
499 page1_imm_or_w:
500         ;call   math_or_imm_w
501         ;jr     page1_dispatch1
502         jp      math_or_imm_w
503
504 page1_or_w:
505         pop     hl
506         ;call   math_or_w
507         ;jr     page1_dispatch1
508         jp      math_or_w
509
510 page1_imm_xor_w:
511         ;call   math_xor_imm_w
512         ;jr     page1_dispatch1
513         jp      math_xor_imm_w
514
515 page1_xor_w:
516         pop     hl
517         ;call   math_xor_w
518         ;jr     page1_dispatch1
519         jp      math_xor_w
520
521 page1_imm_add_w:
522         rst     0x28
523         .db     0x3e ; ld a,
524 page1_add_w:
525         pop     hl
526         add     hl,de
527         jr      add_w_done
528
529 page1_imm_subrev_w:
530         rst     0x28
531         .db     0x3e ; ld a,
532 page1_sub_w:
533         pop     hl
534         or      a
535         sbc     hl,de
536         jr      add_w_done
537
538 ; use addition for page1_imm_sub_w
539 page1_subrev_w:
540         pop     hl
541         ex      de,hl
542         or      a
543         sbc     hl,de
544         jr      add_w_done
545
546 page1_imm_slrev_w:
547         rst     0x28
548         .db     0x3e ; ld a,
549 page1_sl_w:
550         pop     hl
551         call    math_sl_w
552         jr      add_w_done ;mul_w_done
553
554 page1_imm_sl_w:
555         rst     0x28
556         .db     0x3e ; ld a,
557 page1_slrev_w:
558         pop     hl
559         call    math_sl_w0
560         jr      add_w_done ;mul_w_done
561
562 page1_imm_srrev_sw:
563         rst     0x28
564         .db     0x3e ; ld a,
565 page1_sr_sw:
566         pop     hl
567         call    math_sr_sw
568         jr      mul_w_done
569
570 page1_imm_sr_sw:
571         rst     0x28
572         .db     0x3e ; ld a,
573 page1_srrev_sw:
574         pop     hl
575         call    math_sr_sw0
576         jr      mul_w_done
577
578 page1_imm_srrev_uw:
579         rst     0x28
580         .db     0x3e ; ld a,
581 page1_sr_uw:
582         pop     hl
583         call    math_sr_uw
584         jr      mul_w_done
585
586 page1_imm_sr_uw:
587         rst     0x28
588         .db     0x3e ; ld a,
589 page1_srrev_uw:
590         pop     hl
591         call    math_sr_uw0
592         jr      mul_w_done
593
594 page1_imm_mul_uw:
595         rst     0x28
596         .db     0x3e ; ld a,
597 page1_mul_w:
598         pop     hl
599         push    bc
600         call    math_smul_w0
601         pop     bc
602         jr      mul_w_done
603
604 page1_imm_divrev_sw:
605         rst     0x28
606         .db     0x3e ; ld a,
607 page1_div_sw:
608         pop     hl      
609         push    bc
610         call    math_sdiv_sw0
611         jr      div_w_done
612
613 page1_imm_div_sw:
614         rst     0x28
615         .db     0x3e ; ld a,
616 page1_divrev_sw:
617         pop     hl
618         push    bc
619         call    math_sdiv_sw
620         jr      div_w_done
621
622 page1_imm_divrev_uw:
623         rst     0x28
624         .db     0x3e ; ld a,
625 page1_div_uw:
626         pop     hl
627         push    bc
628         call    math_sdiv_uw0
629         jr      div_w_done
630
631 page1_imm_div_uw:
632         rst     0x28
633         .db     0x3e ; ld a,
634 page1_divrev_uw:
635         pop     hl
636         push    bc
637         call    math_sdiv_uw
638         jr      div_w_done
639
640 ; page 1 to 2
641
642 page1_ld_l:
643         ex      de,hl
644         ;call   math_ld_l
645         ;jr     page1_dispatch2
646         jp      math_ld_l
647
648 page1_imm_slrev_l:
649         rst     0x38
650         ;.db    0x3e ; ld a,
651         call    math_sl_l0
652         jr      page1_dispatch2
653 page1_sl_l:
654         ;rst    0x30
655         pop     hl
656         exx
657         pop     de
658         exx
659         call    math_sl_l0
660         jr      page1_dispatch2
661
662 page1_imm_srrev_sl:
663         rst     0x38
664         ;.db    0x3e ; ld a,
665         call    math_sr_sl0
666         jr      page1_dispatch2
667 page1_sr_sl:
668         ;rst    0x30
669         pop     hl
670         exx
671         pop     de
672         exx
673         call    math_sr_sl0
674         jr      page1_dispatch2
675
676 page1_imm_srrev_ul:
677         ;rst    0x38
678         ;.db    0x3e ; ld a,
679         call    math_sr_ul0
680         jr      page1_dispatch2
681 page1_sr_ul:
682         ;rst    0x30
683         pop     hl
684         exx
685         pop     de
686         exx
687         call    math_sr_ul0
688 page1_dispatch2:
689         ld      a,(bc)
690         inc     bc
691         ld      l,a
692         ld      h,page2
693         jp      (hl)
694
695 div_w_done:
696         pop     bc
697         push    de
698 mul_w_done:
699         ex      de,hl
700 ;page1_dispatch1h:
701         ld      a,(bc)
702         inc     bc
703         ld      l,a
704         ld      h,page1
705         jp      (hl)
706
707 ; page 2 interpreter
708 ; long arithmetic operations
709 ; top stack long cached in de:hl'
710
711         .org    page2 * 0x100 - 13
712
713 page2_dispatch0:
714         ld      a,(bc)
715         inc     bc
716         ld      l,a
717         ld      h,page0
718         jp      (hl)
719
720 add_l_done:
721         ex      de,hl
722 page2_dispatch2:
723         ld      a,(bc)
724         inc     bc
725         ld      l,a
726         ld      h,page2
727         jp      (hl)
728
729 ; page 2 administrative
730
731 page2_trace:
732         jp      print_trace
733
734 ; page 2 to 0
735
736 page2_page0:
737         exx
738         push    hl
739         exx
740         push    de
741         jr      page2_dispatch0
742
743 page2_stkst_l:
744         ;call   math_stkst_l
745         ;jr     page2_dispatch0
746         jp      math_stkst_l
747
748 page2_st_l:
749         pop     hl
750         ;call   math_st_l
751         ;jr     page2_dispatch0
752         jp      math_st_l
753
754 page2_imm_cmprev_sl:
755         rst     0x38
756         ;.db    0x3e ; ld a,
757         jp      math_cmprev_sl
758 page2_cmp_sl:
759         ;rst    0x30
760         ;call   math_cmprev_sl
761         ;jr     page2_dispatch0
762         jp      math_cmprev_sl0
763
764 page2_imm_cmprev_ul:
765         rst     0x38
766         ;.db    0x3e ; ld a,
767         jp      math_cmprev_ul
768 page2_cmp_ul:
769         ;rst    0x30
770         ;call   math_cmprev_ul
771         ;jr     page2_dispatch0
772         jp      math_cmprev_ul0
773
774 page2_imm_cmp_sl:
775         rst     0x38
776         ;.db    0x3e ; ld a,
777         jp      math_cmp_sl
778 page2_cmprev_sl:
779         ;rst    0x30
780         ;call   math_cmp_sl
781         ;jr     page2_dispatch0
782         jp      math_cmp_sl0
783
784 page2_imm_cmp_ul:
785         rst     0x38
786         ;.db    0x3e ; ld a,
787         jp      math_cmp_ul
788 page2_cmprev_ul:
789         ;rst    0x30
790         ;call   math_cmp_ul
791         ;jr     page2_dispatch0
792         jp      math_cmp_ul0
793
794 ; page 2 to 2
795
796 page2_imm_and_l:
797         ;call   math_and_imm_l
798         ;jr     page2_dispatch2
799         jp      math_and_imm_l
800
801 page2_and_l:
802         ;rst    0x30
803         ;call   math_and_l
804         ;jr     page2_dispatch2
805         jp      math_and_l0
806
807 page2_imm_or_l:
808         ;call   math_or_imm_l
809         ;jr     page2_dispatch2
810         jp      math_or_imm_l
811
812 page2_or_l:
813         ;rst    0x30
814         ;call   math_or_l
815         ;jr     page2_dispatch2
816         jp      math_or_l0
817
818 page2_imm_xor_l:
819         ;call   math_xor_imm_l
820         ;jr     page2_dispatch2
821         jp      math_xor_imm_l
822
823 page2_xor_l:
824         ;rst    0x30
825         ;call   math_xor_l
826         ;jr     page2_dispatch2
827         jp      math_xor_l0
828
829 page2_imm_add_l:
830         rst     0x38
831         ;.db    0x3e ; ld a,
832         jr      add_l_entry
833 page2_add_l:
834         ;rst    0x30
835         pop     hl
836         exx
837         pop     de
838         exx
839 add_l_entry: ; optimize this
840         add     hl,de
841         exx
842         adc     hl,de
843         exx
844         jr      add_l_done
845
846 page2_imm_subrev_l:
847         rst     0x38
848         ;.db    0x3e ; ld a,
849         jr      sub_l_entry
850 page2_sub_l:
851         ;rst    0x30
852         pop     hl
853         exx
854         pop     de
855         exx
856 sub_l_entry: ; optimize this
857         or      a
858         sbc     hl,de
859         exx
860         ex      de,hl
861         sbc     hl,de
862         exx
863         jr      add_l_done
864
865 ; use addition for page2_imm_sub_l
866 page2_subrev_l:
867         ;rst    0x30
868         pop     hl
869         ;exx
870         ;pop    de
871         ;exx
872         ex      de,hl
873         or      a
874         sbc     hl,de
875         exx 
876  pop de
877         sbc     hl,de
878         jr      add_l_done
879
880 page2_imm_sl_l:
881         rst     0x28
882         .db     0x3e ; ld a,
883 page2_slrev_l:
884         pop     hl
885         ex      de,hl
886         call    math_sl_l
887         jr      mul_l_done
888
889 page2_imm_sr_sl:
890         rst     0x28
891         .db     0x3e ; ld a,
892 page2_srrev_sl:
893         pop     hl
894         ex      de,hl
895         call    math_sr_sl
896         jr      mul_l_done
897
898 page2_imm_sr_ul:
899         rst     0x28
900         .db     0x3e ; ld a,
901 page2_srrev_ul:
902         pop     hl
903         ex      de,hl
904         call    math_sr_ul
905         jr      mul_l_done
906
907 page2_imm_mul_ul:
908         rst     0x38
909         ;.db    0x3e
910         jr      mul_l_entry
911
912 page2_mul_l:
913         ;rst    0x30
914         pop     hl
915         exx
916         pop     de
917         exx
918 mul_l_entry:
919         ex      de,hl
920         push    bc
921         call    math_smul_l0
922         pop     bc
923         jr      mul_l_done
924
925 page2_imm_divrev_sl:
926         rst     0x38
927         ;.db    0x3e ; ld a,
928         ex      de,hl
929         push    bc
930         call    math_sdiv_sl
931         jr      div_l_done
932 page2_div_sl:
933         ;rst    0x30
934         pop     hl
935         exx
936         pop     de
937         exx
938         ex      de,hl
939         push    bc
940         call    math_sdiv_sl
941         jr      div_l_done
942
943 page2_imm_div_sl:
944         rst     0x38
945         ;.db    0x3e ; ld a,
946         push    bc
947         call    math_sdiv_sl0
948         jr      div_l_done
949 page2_divrev_sl:
950         ;rst    0x30
951         pop     hl
952         exx
953         pop     de
954         exx
955         push    bc
956         call    math_sdiv_sl0
957         jr      div_l_done
958
959 page2_imm_divrev_ul:
960         rst     0x38
961         ;.db    0x3e ; ld a,
962         ex      de,hl
963         push    bc
964         call    math_div_ul1
965         jr      div_l_done
966 page2_div_ul:
967         ;rst    0x30
968         pop     hl
969         exx
970         pop     de
971         exx
972         ex      de,hl
973         push    bc
974         call    math_div_ul1
975         jr      div_l_done
976
977 page2_imm_div_ul:
978         rst     0x38
979         ;.db    0x3e ; ld a,
980         push    bc
981         call    math_div_ul0
982         jr      div_l_done
983 page2_divrev_ul:
984         ;rst    0x30
985         pop     hl
986         exx
987         pop     de
988         exx
989         push    bc
990         call    math_div_ul0
991 div_l_done:
992         pop     bc
993         exx
994         push    de
995         exx
996         push    de
997 mul_l_done:
998         ex      de,hl
999 ;page2_dispatch2h:
1000         ld      a,(bc)
1001         inc     bc
1002         ld      l,a
1003         ld      h,page2
1004         jp      (hl)
1005
1006 ; conditionals
1007
1008 test_eq:
1009         ld      de,0
1010         ret     nz
1011         inc     de
1012         ret
1013
1014 test_ne:
1015         ld      de,0
1016         ret     z
1017         inc     de
1018         ret
1019
1020 test_ge:
1021         ccf
1022 test_lt:
1023         ld      hl,0
1024         adc     hl,hl
1025         ex      de,hl
1026         ret
1027
1028 ; math package
1029
1030 ; lightweight routines
1031
1032 ; these can be duplicated without much cost, and will be called often, so the
1033 ; calling convention is geared to what the interpreter needs (de:hl' and so on)
1034
1035 math_imm_w: ; immediate to de
1036         ld      a,(bc)
1037         inc     bc
1038         ld      e,a
1039         ld      a,(bc)
1040         inc     bc
1041         ld      d,a
1042         ;ret
1043         ld      a,(bc)
1044         inc     bc
1045         ld      l,a
1046         ld      h,page1
1047         jp      (hl)
1048
1049 math_imm_l: ; immediate to hl':de
1050         ld      a,(bc)
1051         inc     bc
1052         ld      e,a
1053         ld      a,(bc)
1054         inc     bc
1055         ld      d,a
1056         ld      a,(bc)
1057         inc     bc
1058         exx
1059         ld      l,a
1060         exx
1061         ld      a,(bc)
1062         inc     bc
1063         exx
1064         ld      h,a
1065         exx
1066         ;ret
1067         ld      a,(bc)
1068         inc     bc
1069         ld      l,a
1070         ld      h,page2
1071         jp      (hl)
1072
1073 math_stkld_w: ; sp(imm_w) to de
1074         ld      a,(bc)
1075         inc     bc
1076         ld      l,a
1077         ld      a,(bc)
1078         inc     bc
1079         ld      h,a
1080         add     hl,sp
1081 ; use inline code for math_ld_w
1082         ld      e,(hl)
1083         inc     hl
1084         ld      d,(hl)
1085         ;ret
1086         ld      a,(bc)
1087         inc     bc
1088         ld      l,a
1089         ld      h,page1
1090         jp      (hl)
1091
1092 math_stkld_l: ; sp(imm_w) to de:hl'
1093         ld      a,(bc)
1094         inc     bc
1095         ld      l,a
1096         ld      a,(bc)
1097         inc     bc
1098         ld      h,a
1099         add     hl,sp
1100 math_ld_l: ; (hl) to hl':de
1101         ld      e,(hl)
1102         inc     hl
1103         ld      d,(hl)
1104         inc     hl
1105         ld      a,(hl)
1106         inc     hl
1107         exx
1108         ld      l,a
1109         exx
1110         ld      a,(hl)
1111         exx
1112         ld      h,a
1113         exx
1114         ;ret
1115         ld      a,(bc)
1116         inc     bc
1117         ld      l,a
1118         ld      h,page2
1119         jp      (hl)
1120
1121 math_stkst_w: ; de to sp(imm_w)
1122         ld      a,(bc)
1123         inc     bc
1124         ld      l,a
1125         ld      a,(bc)
1126         inc     bc
1127         ld      h,a
1128         add     hl,sp
1129         ld      (hl),e
1130         inc     hl
1131         ld      (hl),d
1132         ;ret
1133         ld      a,(bc)
1134         inc     bc
1135         ld      l,a
1136         ld      h,page0
1137         jp      (hl)
1138
1139 math_stkst_l: ; de:hl' to sp(imm_w)
1140         ld      a,(bc)
1141         inc     bc
1142         ld      l,a
1143         ld      a,(bc)
1144         inc     bc
1145         ld      h,a
1146         add     hl,sp
1147 math_st_l: ; hl':de to (hl)
1148 .if 0
1149  call print_word
1150  ld a,':
1151  call print_char
1152  ex de,hl
1153  call print_word
1154  ex de,hl
1155  push hl
1156  exx
1157  push hl
1158  exx
1159  pop hl
1160  call print_word
1161  pop hl
1162  ld a,' 
1163  call print_char
1164 .endif
1165         ld      (hl),e
1166         inc     hl
1167         ld      (hl),d
1168         inc     hl
1169         exx
1170         ld      a,l
1171         exx
1172         ld      (hl),a
1173         inc     hl
1174         exx
1175         ld      a,h
1176         exx
1177         ld      (hl),a
1178         ;ret
1179         ld      a,(bc)
1180         inc     bc
1181         ld      l,a
1182         ld      h,page0
1183         jp      (hl)
1184
1185 math_and_imm_w: ; de &= imm_w
1186         ld      a,(bc)
1187         inc     bc
1188         and     e
1189         ld      e,a
1190         ld      a,(bc)
1191         inc     bc
1192         and     d
1193         ld      d,a
1194         ;ret
1195         ld      a,(bc)
1196         inc     bc
1197         ld      l,a
1198         ;ld     h,page1
1199         jp      (hl)
1200
1201 math_and_imm_l: ; hl':de &= imm_l
1202         ld      a,(bc)
1203         inc     bc
1204         and     e
1205         ld      e,a
1206         ld      a,(bc)
1207         inc     bc
1208         and     d
1209         ld      d,a
1210         ld      a,(bc)
1211         inc     bc
1212         exx
1213         and     l
1214         ld      l,a
1215         exx
1216         ld      a,(bc)
1217         inc     bc
1218         exx
1219         and     h
1220         ld      h,a
1221         exx
1222         ;ret
1223         ld      a,(bc)
1224         inc     bc
1225         ld      l,a
1226         ;ld     h,page2
1227         jp      (hl)
1228
1229 math_and_w: ; de &= hl
1230         ld      a,e
1231         and     l
1232         ld      e,a
1233         ld      a,d
1234         and     h
1235         ld      d,a
1236         ;ret
1237         ld      a,(bc)
1238         inc     bc
1239         ld      l,a
1240         ld      h,page1
1241         jp      (hl)
1242
1243 math_and_l0:
1244         pop     hl
1245         exx
1246         pop     de
1247         exx
1248 math_and_l: ; hl':de &= de':hl
1249         ld      a,e
1250         and     l
1251         ld      e,a
1252         ld      a,d
1253         and     h
1254         ld      d,a
1255         exx
1256         ld      a,l
1257         and     e
1258         ld      l,a
1259         ld      a,h
1260         and     d
1261         ld      h,a
1262         exx
1263         ;ret
1264         ld      a,(bc)
1265         inc     bc
1266         ld      l,a
1267         ld      h,page2
1268         jp      (hl)
1269
1270 math_or_imm_w: ; de |= imm_w
1271         ld      a,(bc)
1272         inc     bc
1273         or      e
1274         ld      e,a
1275         ld      a,(bc)
1276         inc     bc
1277         or      d
1278         ld      d,a
1279         ;ret
1280         ld      a,(bc)
1281         inc     bc
1282         ld      l,a
1283         ;ld     h,page1
1284         jp      (hl)
1285
1286 math_or_imm_l: ; hl':de |= imm_l
1287         ld      a,(bc)
1288         inc     bc
1289         or      e
1290         ld      e,a
1291         ld      a,(bc)
1292         inc     bc
1293         or      d
1294         ld      d,a
1295         ld      a,(bc)
1296         inc     bc
1297         exx
1298         or      l
1299         ld      l,a
1300         exx
1301         ld      a,(bc)
1302         inc     bc
1303         exx
1304         or      h
1305         ld      h,a
1306         exx
1307         ;ret
1308         ld      a,(bc)
1309         inc     bc
1310         ld      l,a
1311         ;ld     h,page2
1312         jp      (hl)
1313
1314 math_or_w: ; de |= hl
1315         ld      a,e
1316         or      l
1317         ld      e,a
1318         ld      a,d
1319         or      h
1320         ld      d,a
1321         ;ret
1322         ld      a,(bc)
1323         inc     bc
1324         ld      l,a
1325         ld      h,page1
1326         jp      (hl)
1327
1328 math_or_l0:
1329         pop     hl
1330         exx
1331         pop     de
1332         exx
1333 math_or_l: ; hl':de |= de':hl
1334         ld      a,e
1335         or      l
1336         ld      e,a
1337         ld      a,d
1338         or      h
1339         ld      d,a
1340         exx
1341         ld      a,l
1342         or      e
1343         ld      l,a
1344         ld      a,h
1345         or      d
1346         ld      h,a
1347         exx
1348         ;ret
1349         ld      a,(bc)
1350         inc     bc
1351         ld      l,a
1352         ld      h,page2
1353         jp      (hl)
1354
1355 math_xor_imm_w: ; de ^= imm_w
1356         ld      a,(bc)
1357         inc     bc
1358         xor     e
1359         ld      e,a
1360         ld      a,(bc)
1361         inc     bc
1362         xor     d
1363         ld      d,a
1364         ;ret
1365         ld      a,(bc)
1366         inc     bc
1367         ld      l,a
1368         ;ld     h,page1
1369         jp      (hl)
1370
1371 math_xor_imm_l: ; hl':de ^= imm_l
1372         ld      a,(bc)
1373         inc     bc
1374         xor     e
1375         ld      e,a
1376         ld      a,(bc)
1377         inc     bc
1378         xor     d
1379         ld      d,a
1380         ld      a,(bc)
1381         inc     bc
1382         exx
1383         xor     l
1384         ld      l,a
1385         exx
1386         ld      a,(bc)
1387         inc     bc
1388         exx
1389         xor     h
1390         ld      h,a
1391         exx
1392         ;ret
1393         ld      a,(bc)
1394         inc     bc
1395         ld      l,a
1396         ;ld     h,page2
1397         jp      (hl)
1398
1399 math_xor_w: ; de ^= hl
1400         ld      a,e
1401         xor     l
1402         ld      e,a
1403         ld      a,d
1404         xor     h
1405         ld      d,a
1406         ;ret
1407         ld      a,(bc)
1408         inc     bc
1409         ld      l,a
1410         ld      h,page1
1411         jp      (hl)
1412
1413 math_xor_l0:
1414         pop     hl
1415         exx
1416         pop     de
1417         exx
1418 math_xor_l: ; hl':de ^= de':hl
1419         ld      a,e
1420         xor     l
1421         ld      e,a
1422         ld      a,d
1423         xor     h
1424         ld      d,a
1425         exx
1426         ld      a,l
1427         xor     e
1428         ld      l,a
1429         ld      a,h
1430         xor     d
1431         ld      h,a
1432         exx
1433         ;ret
1434         ld      a,(bc)
1435         inc     bc
1436         ld      l,a
1437         ld      h,page2
1438         jp      (hl)
1439
1440 math_cmp_sw: ; cf=1 de < hl, zf=1 de == hl, signed
1441         ex      de,hl
1442 math_cmprev_sw: ; cf=1 hl < de, zf=1 hl == de, signed
1443         or      a
1444         sbc     hl,de
1445         ld      a,h
1446         rla
1447         ;ret    po
1448         jp      po,1$
1449         ccf
1450         ;ret
1451 1$:     ld      a,(bc)
1452         inc     bc
1453         ld      l,a
1454         ld      h,page0
1455         jp      (hl)
1456
1457 ; use inline code for math_cmp_uw, math_cmprev_uw
1458
1459 math_cmp_sl0:
1460         pop     hl
1461         exx
1462         pop     de
1463         exx
1464 math_cmp_sl: ; cf=1 hl':de < de':hl, zf=1 hl':de == de':hl, signed
1465         exx
1466         or      a
1467         sbc     hl,de
1468         ld      a,h
1469         exx ; optimize this
1470         jr      z,cmp_l_entry
1471         rla
1472         ;ret    po
1473         jp      po,1$
1474         ccf
1475         ;ret
1476 1$:     ld      a,(bc)
1477         inc     bc
1478         ld      l,a
1479         ld      h,page0
1480         jp      (hl)
1481
1482 math_cmp_ul0:
1483         pop     hl
1484         exx
1485         pop     de
1486         exx ; optimize this
1487 math_cmp_ul: ; cf=1 hl':de < de':hl, zf=1 hl':de == de':hl, unsigned
1488         exx
1489         or      a
1490         sbc     hl,de
1491         ;ret    nz
1492         exx
1493         jr      nz,cmp_l_dispatch
1494 cmp_l_entry:
1495         ex      de,hl
1496         sbc     hl,de
1497         ;ret
1498 cmp_l_dispatch:
1499         ld      a,(bc)
1500         inc     bc
1501         ld      l,a
1502         ld      h,page0
1503         jp      (hl)
1504
1505 math_cmprev_sl0:
1506         pop     hl
1507         exx
1508         pop     de
1509         exx
1510 math_cmprev_sl: ; cf=1 de':hl < hl':de, zf=1 de':hl == hl':de, signed
1511         exx
1512         ex      de,hl
1513         or      a
1514         sbc     hl,de
1515         ld      a,h
1516         exx ; optimize this
1517         jr      z,cmprev_l_entry
1518         rla
1519         ;ret    po
1520         jp      po,1$
1521         ccf
1522         ;ret
1523 1$:     ld      a,(bc)
1524         inc     bc
1525         ld      l,a
1526         ld      h,page0
1527         jp      (hl)
1528
1529 math_cmprev_ul0:
1530         pop     hl
1531         exx
1532         pop     de
1533         exx
1534 math_cmprev_ul: ; cf=1 de':hl < hl':de, zf=1 de':hl == hl':de, signed
1535         exx
1536         ex      de,hl
1537         or      a
1538         sbc     hl,de
1539         exx
1540         ;ret    nz
1541         jr      nz,cmprev_l_dispatch
1542 cmprev_l_entry:
1543         sbc     hl,de
1544         ;ret
1545 cmprev_l_dispatch:
1546         ld      a,(bc)
1547         inc     bc
1548         ld      l,a
1549         ld      h,page0
1550         jp      (hl)
1551
1552 ; heavyweight routines
1553
1554 ; these have unrolled loops and so there needs to be as much reuse as possible
1555
1556 ; for the multiply and divide the unrolled loops are placed in subroutines, so
1557 ; there is some overhead to use them, but it allows the calling code to itself
1558 ; be cheaply unrolled, so the amount left to do is determined by context not
1559 ; by a counter; the tradeoff is do we count loops by push bc/pop bc/djnz or by
1560 ; call/call/call, since both need a stack push/pop it should be about the same
1561
1562 ; for these routines the calling convention is geared to whatever the routine
1563 ; needs to work most efficiently, this makes the usage more cumbersome as you
1564 ; to do something like ex de,hl/call/ex de,hl but it is done this way because
1565 ; otherwise some callsites need to exchange registers into place on one side
1566 ; of a call/ret boundary only for them to be immediately exchanged back again
1567
1568 ; as an exception to this we may provide an earlier entry point(s), before the
1569 ; routine proper, which exchanges arguments into place (the caller must still
1570 ; deal with exchanges afterwards), we do this because of callsites that are in
1571 ; the interpreter pages and need to conserve code size, therefore the prefix
1572 ; chosen need not occur more than once, and we'll use the longest such prefix
1573
1574 ; while some of these earlier entry points have a meaning, e.g. math_divrev_l
1575 ; before math_div_l, many of them do not, so we will just number them instead
1576 ; (this is because the prefix code can be a compromise between callers' needs)
1577
1578 math_sl_w0: ; hl = de << (l & 0xf)
1579         ex      de,hl
1580 math_sl_w: ; hl <<= e & 0xf
1581         ; by 1
1582         bit     0,e
1583         jr      z,1$
1584         add     hl,hl
1585 1$:     ; by 2
1586         bit     1,e
1587         jr      z,2$
1588         add     hl,hl
1589         add     hl,hl
1590 2$:     ; by 4
1591         bit     2,e
1592         jr      z,3$
1593         add     hl,hl
1594         add     hl,hl
1595         add     hl,hl
1596         add     hl,hl
1597 3$:     ; by 8
1598         bit     3,e
1599         ret     z
1600         ld      h,l
1601         ld      l,0
1602         ret
1603
1604 math_sl_l0: ; de':hl <<= e & 0x1f
1605         exx
1606         ex      de,hl
1607         exx
1608 math_sl_l: ; hl':hl <<= e & 0x1f
1609         ; by 1
1610         bit     0,e
1611         jr      z,1$
1612         add     hl,hl
1613         exx
1614         adc     hl,hl
1615         exx
1616 1$:     ; by 2
1617         bit     1,e
1618         jr      z,2$
1619         add     hl,hl
1620         exx
1621         adc     hl,hl
1622         exx
1623         add     hl,hl
1624         exx
1625         adc     hl,hl
1626         exx
1627 2$:     ; by 4
1628         bit     2,e
1629         jr      z,3$
1630         add     hl,hl
1631         exx
1632         adc     hl,hl
1633         exx
1634         add     hl,hl
1635         exx
1636         adc     hl,hl
1637         exx
1638         add     hl,hl
1639         exx
1640         adc     hl,hl
1641         exx
1642         add     hl,hl
1643         exx
1644         adc     hl,hl
1645         exx
1646 3$:     ; by 8
1647         bit     3,e
1648         jr      z,4$
1649         ld      a,h
1650         ld      h,l
1651         ld      l,0
1652         exx
1653         ld      h,l
1654         ld      l,a
1655         exx
1656 4$:     ; by 16
1657         bit     4,e
1658         ret     z
1659         push    hl
1660         ld      hl,0
1661         exx
1662         pop     hl
1663         exx
1664         ret
1665
1666 math_sr_uw0: ; hl = de >> (l & 0xf), logical
1667         ex      de,hl
1668 math_sr_uw: ; hl >>= e & 0xf, logical
1669         ld      a,e
1670         and     0x1f
1671         add     7
1672 math_sr_uw1: ; hl >>= a - 7, immediate a in [7, 0x17), arithmetic
1673         ld      e,a
1674         sub     a
1675         jr      sr_w_entry
1676
1677 math_sr_sw0: ; hl = de >> (l & 0xf), arithmetic
1678         ex      de,hl
1679 math_sr_sw: ; hl >>= e & 0xf, arithmetic
1680         ld      a,e
1681         and     0xf
1682         add     7
1683 math_sr_sw1: ; hl >>= a - 7, immediate a in [7, 0x17), arithmetic
1684         ld      e,a
1685         ld      a,h
1686         rla
1687         sbc     a,a
1688 sr_w_entry:
1689         ; by -1
1690         bit     0,e
1691         jr      nz,1$
1692         add     hl,hl
1693         rla
1694 1$:     ; by -2
1695         bit     1,e
1696         jr      nz,2$
1697         add     hl,hl
1698         rla
1699         add     hl,hl
1700         rla
1701 2$:     ; by -4
1702         bit     2,e
1703         jr      nz,3$
1704         add     hl,hl
1705         rla
1706         add     hl,hl
1707         rla
1708         add     hl,hl
1709         rla
1710         add     hl,hl
1711         rla
1712 3$:     ; by 8
1713         bit     3,e
1714         jr      z,4$
1715         ld      l,h
1716         ld      h,a
1717         ret
1718 4$:     ; by 16 (can't occur simultaneously with by 8)
1719         bit     4,e
1720         ret     z
1721         ld      l,a
1722         rla
1723         sbc     a,a
1724         ld      h,a
1725         ret
1726
1727 math_sr_ul0: ; hl:de' >>= e & 0x1f, logical
1728         exx
1729         ex      de,hl
1730         exx
1731 math_sr_ul: ; hl:hl' >>= e & 0x1f, logical
1732         ld      a,e
1733         and     0x1f
1734         add     7
1735 math_sr_ul1: ; hl:hl' >>= a - 7, immediate a in [7, 0x27), logical
1736         ld      e,a
1737         sub     a
1738         jr      sr_l_entry
1739
1740 math_sr_sl0: ; de':hl >>= e & 0x1f, arithmetic
1741         exx
1742         ex      de,hl
1743         exx
1744 math_sr_sl: ; hl':hl >>= e & 0x1f, arithmetic
1745         ld      a,e
1746         and     0xf
1747         add     7
1748 math_sr_sl1: ; hl':hl >>= a - 7, immediate a in [7, 0x27), arithmetic
1749         ld      e,a
1750         exx
1751         ld      a,h
1752         exx
1753         rla
1754         sbc     a,a
1755 sr_l_entry:
1756         ; by -1
1757         bit     0,e
1758         jr      nz,1$
1759         add     hl,hl
1760         exx
1761         adc     hl,hl
1762         exx
1763         rla
1764 1$:     ; by -2
1765         bit     1,e
1766         jr      nz,2$
1767         add     hl,hl
1768         exx
1769         adc     hl,hl
1770         exx
1771         rla
1772         add     hl,hl
1773         exx
1774         adc     hl,hl
1775         exx
1776         rla
1777 2$:     ; by -4
1778         bit     2,e
1779         jr      nz,3$
1780         add     hl,hl
1781         exx
1782         adc     hl,hl
1783         exx
1784         rla
1785         add     hl,hl
1786         exx
1787         adc     hl,hl
1788         exx
1789         rla
1790         add     hl,hl
1791         exx
1792         adc     hl,hl
1793         exx
1794         rla
1795         add     hl,hl
1796         exx
1797         adc     hl,hl
1798         exx
1799         rla
1800 3$:     ; by 8
1801         bit     3,e
1802         jr      z,4$
1803         exx
1804         ld      d,l
1805         ld      l,h
1806         ld      h,a
1807         rla
1808         ld      a,d
1809         exx
1810         ld      l,h
1811         ld      h,a
1812         sbc     a,a
1813 4$:     ; by 16
1814         bit     4,e
1815         jr      z,5$
1816         exx
1817         push    hl
1818         ld      l,a
1819         rla
1820         sbc     a,a
1821         ld      h,a
1822         exx
1823         pop     hl
1824         ret
1825 5$:     ; by 32 (can't occur simultaneously with by 16)
1826         bit     5,e
1827         ret     z
1828         ld      l,a
1829         rla
1830         sbc     a,a
1831         ld      h,a
1832         exx
1833         ld      l,a
1834         ld      h,a
1835         exx
1836         ret
1837
1838 ; smul: short multiplication
1839 ; 16 * 16 to 16 bit product (word)
1840 ; 32 * 32 to 32 bit product (long)
1841 ; mul: long multiplication
1842 ; 16 + 16 * 16 to 32 bit product (word)
1843 ; 32 + 32 * 32 to 64 bit product (long)
1844
1845 ; smul is implemented in a more optimal way that uses only left shifts,
1846 ; since left shifts are cheaper on the z80, this works for smul because
1847 ; there is no need to worry about propagating carries into high result
1848
1849 ; mul has the ability to initialize the product with some nonzero value,
1850 ; which smul doesn't have because it only shifts zeros in from the left,
1851 ; using this ability the long multiplication reverses the long division
1852 ; (initialize product with a remainder, then add in quotient * divisor)
1853
1854 math_smul_w0: ; hl *= de
1855         ld      c,l
1856         ld      b,h
1857 math_smul_w: ; hl = bc * de
1858         ld      a,d
1859         call    smul_w0
1860         ld      a,e
1861 smul_w: ; bit 0
1862         add     hl,hl
1863 smul_w0:        rla
1864         jr      nc,1$
1865         add     hl,bc
1866 1$:     ; bit 1
1867         add     hl,hl
1868         rla
1869         jr      nc,2$
1870         add     hl,bc
1871 2$:     ; bit 2
1872         add     hl,hl
1873         rla
1874         jr      nc,3$
1875         add     hl,bc
1876 3$:     ; bit 3
1877         add     hl,hl
1878         rla
1879         jr      nc,4$
1880         add     hl,bc
1881 4$:     ; bit 4
1882         add     hl,hl
1883         rla
1884         jr      nc,5$
1885         add     hl,bc
1886 5$:     ; bit 5
1887         add     hl,hl
1888         rla
1889         jr      nc,6$
1890         add     hl,bc
1891 6$:     ; bit 6
1892         add     hl,hl
1893         rla
1894         jr      nc,7$
1895         add     hl,bc
1896 7$:     ; bit 7
1897         add     hl,hl
1898         rla
1899         ret     nc
1900         add     hl,bc
1901         ret
1902
1903 math_smul_l0: ; hl':hl *= de':de
1904         ld      c,l
1905         ld      b,h
1906         exx
1907         ld      c,l
1908         ld      b,h
1909         exx
1910 math_smul_l: ; hl':hl = de':de * bc':bc
1911         exx
1912         ld      a,d
1913         exx
1914         call    smul_l0
1915         exx
1916         ld      a,e
1917         exx
1918         call    smul_l
1919         ld      a,d
1920         call    smul_l
1921         ld      a,e
1922 smul_l: ; bit 0
1923         add     hl,hl
1924         exx
1925         adc     hl,hl
1926         exx
1927 smul_l0:        rla
1928         jr      nc,1$
1929         add     hl,bc
1930         exx
1931         adc     hl,bc
1932         exx
1933 1$:     ; bit 1
1934         add     hl,hl
1935         exx
1936         adc     hl,hl
1937         exx
1938         rla
1939         jr      nc,2$
1940         add     hl,bc
1941         exx
1942         adc     hl,bc
1943         exx
1944 2$:     ; bit 2
1945         add     hl,hl
1946         exx
1947         adc     hl,hl
1948         exx
1949         rla
1950         jr      nc,3$
1951         add     hl,bc
1952         exx
1953         adc     hl,bc
1954         exx
1955 3$:     ; bit 3
1956         add     hl,hl
1957         exx
1958         adc     hl,hl
1959         exx
1960         rla
1961         jr      nc,4$
1962         add     hl,bc
1963         exx
1964         adc     hl,bc
1965         exx
1966 4$:     ; bit 4
1967         add     hl,hl
1968         exx
1969         adc     hl,hl
1970         exx
1971         rla
1972         jr      nc,5$
1973         add     hl,bc
1974         exx
1975         adc     hl,bc
1976         exx
1977 5$:     ; bit 5
1978         add     hl,hl
1979         exx
1980         adc     hl,hl
1981         exx
1982         rla
1983         jr      nc,6$
1984         add     hl,bc
1985         exx
1986         adc     hl,bc
1987         exx
1988 6$:     ; bit 6
1989         add     hl,hl
1990         exx
1991         adc     hl,hl
1992         exx
1993         rla
1994         jr      nc,7$
1995         add     hl,bc
1996         exx
1997         adc     hl,bc
1998         exx
1999 7$:     ; bit 7
2000         add     hl,hl
2001         exx
2002         adc     hl,hl
2003         exx
2004         rla
2005         ret     nc
2006         add     hl,bc
2007         exx
2008         adc     hl,bc
2009         exx
2010         ret
2011
2012 math_mul_sw0: ; hl:de = hl * de, signed
2013         ld      c,l
2014         ld      b,h
2015         ld      hl,0
2016 math_mul_sw: ; hl:de = hl + bc * de, signed
2017         ld      a,b
2018         rla ; cf will be preserved through to the last rra below
2019         ld      a,e
2020         call    mul_uw
2021         push    af
2022         ld      a,d
2023         call    mul_uw1 ; do only 7 bits, get sign of d into cf
2024         jr      nc,1$
2025         or      a
2026         sbc     hl,bc
2027 1$:     rr      h
2028         rr      l
2029         rra
2030         jr      nc,2$
2031         or      a
2032         sbc     hl,de
2033 2$:     ld      d,a
2034         pop     af
2035         ld      e,a
2036         ret
2037
2038 math_mul_uw0: ; hl:de = hl * de, unsigned
2039         ld      c,l
2040         ld      b,h
2041         ld      hl,0
2042 math_mul_uw: ; hl:de = hl + bc * de, unsigned
2043         ld      a,e
2044         call    mul_uw
2045         ld      e,a
2046         ld      a,d
2047         call    mul_uw
2048         ld      d,a
2049         ret
2050
2051 mul_uw: rra
2052         ; bit 0
2053         jr      nc,1$
2054         add     hl,bc
2055 1$:     rr      h
2056         rr      l
2057 mul_uw1:
2058         rra
2059         ; bit 1
2060         jr      nc,2$
2061         add     hl,bc
2062 2$:     rr      h
2063         rr      l
2064         rra
2065         ; bit 2
2066         jr      nc,3$
2067         add     hl,bc
2068 3$:     rr      h
2069         rr      l
2070         rra
2071         ; bit 3
2072         jr      nc,4$
2073         add     hl,bc
2074 4$:     rr      h
2075         rr      l
2076         rra
2077         ; bit 4
2078         jr      nc,5$
2079         add     hl,bc
2080 5$:     rr      h
2081         rr      l
2082         rra
2083         ; bit 5
2084         jr      nc,6$
2085         add     hl,bc
2086 6$:     rr      h
2087         rr      l
2088         rra
2089         ; bit 6 
2090         jr      nc,7$
2091         add     hl,bc
2092 7$:     rr      h
2093         rr      l
2094         rra
2095         ; bit 7
2096         jr      nc,8$
2097         add     hl,bc
2098 8$:     rr      h
2099         rr      l
2100         rra
2101         ret
2102
2103 math_mul_sl0: ; hl':hl:de':de = hl':hl * de':de, signed
2104         ld      c,l
2105         ld      b,h
2106         sub     a
2107         ld      l,a
2108         ld      h,a
2109         exx
2110         ld      c,l
2111         ld      b,h
2112         ld      l,a
2113         ld      h,a
2114         exx ; hard to optimize this
2115 math_mul_sl: ; hl':hl:de':de = hl':hl + bc':bc * de':de, signed
2116         exx
2117         ld      a,b
2118         rla ; cf will be preserved through to the last rra below
2119         exx
2120         ld      a,e
2121         call    mul_ul
2122         push    af
2123         ld      a,d
2124         call    mul_ul
2125         push    af
2126         exx
2127         ld      a,e
2128         exx
2129         call    mul_ul
2130         push    af
2131         exx
2132         ld      a,d
2133         exx
2134         call    mul_ul1 ; do only 7 bits, get sign of d into cf
2135         jr      nc,1$
2136         or      a
2137         sbc     hl,bc
2138         exx
2139         sbc     hl,bc
2140         exx ; hard to optimize this
2141 1$:     exx
2142         rr      h
2143         rr      l
2144         exx
2145         rr      h
2146         rr      l
2147         rra
2148         jr      nc,2$
2149         or      a
2150         sbc     hl,de
2151         exx
2152         sbc     hl,de
2153         exx ; hard to optimize this
2154 2$:     exx
2155         ld      d,a
2156         pop     af
2157         ld      e,a
2158         exx
2159         pop     de
2160         pop     af
2161         ld      e,a
2162         ret
2163
2164 math_mul_ul0: ; hl':hl:de':de = hl':hl * de':de, unsigned
2165         ld      c,l
2166         ld      b,h
2167         sub     a
2168         ld      l,a
2169         ld      h,a
2170         exx
2171         ld      c,l
2172         ld      b,h
2173         ld      l,a
2174         ld      h,a
2175         exx
2176 math_mul_ul: ; hl':hl:de':de = hl':hl + bc':bc * de':de, unsigned
2177         ld      a,e
2178         call    mul_ul
2179         ld      e,a
2180         ld      a,d
2181         call    mul_ul
2182         ld      d,a
2183         exx
2184         ld      a,e
2185         exx
2186         call    mul_ul
2187         exx
2188         ld      e,a
2189         ld      a,d
2190         exx
2191         call    mul_ul
2192         exx
2193         ld      d,a
2194         exx
2195         ret
2196
2197 mul_ul: rra
2198         ; bit 0
2199         jr      nc,1$
2200         add     hl,bc
2201         exx
2202         adc     hl,bc
2203         exx ; optimize this
2204 1$:     exx
2205         rr      h
2206         rr      l
2207         exx
2208         rr      h
2209         rr      l
2210 mul_ul1:
2211         rra
2212         ; bit 1
2213         jr      nc,2$
2214         add     hl,bc
2215         exx
2216         adc     hl,bc
2217         exx ; optimize this
2218 2$:     exx
2219         rr      h
2220         rr      l
2221         exx
2222         rr      h
2223         rr      l
2224         rra
2225         ; bit 2
2226         jr      nc,3$
2227         add     hl,bc
2228         exx
2229         adc     hl,bc
2230         exx ; optimize this
2231 3$:     exx
2232         rr      h
2233         rr      l
2234         exx
2235         rr      h
2236         rr      l
2237         rra
2238         ; bit 3
2239         jr      nc,4$
2240         add     hl,bc
2241         exx
2242         adc     hl,bc
2243         exx ; optimize this
2244 4$:     exx
2245         rr      h
2246         rr      l
2247         exx
2248         rr      h
2249         rr      l
2250         rra
2251         ; bit 4
2252         jr      nc,5$
2253         add     hl,bc
2254         exx
2255         adc     hl,bc
2256         exx ; optimize this
2257 5$:     exx
2258         rr      h
2259         rr      l
2260         exx
2261         rr      h
2262         rr      l
2263         rra
2264         ; bit 5
2265         jr      nc,6$
2266         add     hl,bc
2267         exx
2268         adc     hl,bc
2269         exx ; optimize this
2270 6$:     exx
2271         rr      h
2272         rr      l
2273         exx
2274         rr      h
2275         rr      l
2276         rra
2277         ; bit 6 
2278         jr      nc,7$
2279         add     hl,bc
2280         exx
2281         adc     hl,bc
2282         exx ; optimize this
2283 7$:     exx
2284         rr      h
2285         rr      l
2286         exx
2287         rr      h
2288         rr      l
2289         rra
2290         ; bit 7
2291         jr      nc,8$
2292         add     hl,bc
2293         exx
2294         adc     hl,bc
2295         exx ; optimize this
2296 8$:     exx
2297         rr      h
2298         rr      l
2299         exx
2300         rr      h
2301         rr      l
2302         rra
2303         ret
2304
2305 ; sdiv: short division
2306 ; 16 / 16 to 16 bit quotient, 16 bit remainder (word)
2307 ; 32 / 32 to 32 bit quotient, 32 bit remainder (long)
2308 ; div: long division
2309 ; 32 / 16 to 16 bit quotient, 16 bit remainder (word)
2310 ; 64 / 32 to 32 bit quotient, 32 bit remainder (long)
2311
2312 ; sdiv is implemented as sign/zero extension then div
2313
2314 math_sdiv_sw0: ; hl, de = hl % de, hl / de, signed
2315         ex      de,hl
2316 math_sdiv_sw: ; hl, de = de % hl, de / hl, signed
2317         ld      c,l
2318         ld      b,h
2319         ld      a,d
2320         rla
2321         sbc     a,a
2322         ld      l,a
2323         ld      h,a
2324 math_div_sw: ; hl, de = hl:de % bc, hl:de / bc, signed
2325         ld      a,h
2326         or      a
2327         ld      a,b
2328         rla
2329         jp      m,div_w_n               ; positive dividend
2330
2331         ; positive dividend
2332         ld      a,d
2333         jr      nc,div_w_pp             ; positive dividend, positive divisor
2334
2335         ; positive dividend, negative divisor
2336         call    div_w_n1
2337         ld      d,a
2338         ld      a,e
2339         call    div_w_ncf
2340         inc     a
2341         ld      e,a
2342         ret     c
2343         sbc     hl,bc
2344         ret
2345
2346 div_w_n:
2347         ; negative dividend
2348         dec     de                      ; reduces remainder by 1 (we inc later)
2349         ld      a,d
2350         jr      c,div_w_nn              ; negative dividend, negative divisor 
2351
2352         ; negative dividend, positive divisor
2353         call    div_w1
2354         ld      d,a
2355         ld      a,e
2356         call    div_wcf
2357         inc     a
2358         ld      e,a
2359         inc     hl                      ; get into range -divisor+1..0
2360         ret     c
2361         sbc     hl,bc
2362         ret
2363
2364 div_w_nn: ; negative dividend, negative divisor
2365         call    div_w_n0
2366         ld      d,a
2367         ld      a,e
2368         call    div_w_ncf
2369         ld      e,a
2370         inc     hl                      ; get into range divisor+1..0
2371         ret     nc
2372         add     hl,bc
2373         ret
2374
2375 math_sdiv_uw0: ; hl, de = hl % de, hl / de, unsigned
2376         ex      de,hl
2377 math_sdiv_uw: ; hl, de = de % hl, de / hl, unsigned
2378         ld      c,l
2379         ld      b,h
2380         ld      hl,0
2381 math_div_uw: ; hl, de = hl:de % bc, hl:de / bc, unsigned
2382         ld      a,d
2383 div_w_pp: ; positive dividend, positive divisor
2384         call    div_w0
2385         ld      d,a
2386         ld      a,e
2387         call    div_wcf
2388         ld      e,a
2389         ret     nc
2390         add     hl,bc
2391         ret
2392
2393 ; non-restoring division routine
2394
2395 ; de = divisor, hl:a = dividend with hl = previous remainder, a = next byte
2396 ; enter at div0 with positive remainder in hl, such that hl < de
2397 ; enter at div1 with negative remainder in hl, such that hl >= -de
2398
2399 ; div0/1 return a = 8-bit quotient as an odd number interpreted as -ff..ff,
2400 ; by summing positive/negative place values, e.g. -80 +40 +20 -10 +8 -4 -2 +1
2401
2402 ; if entered at div0, there is a -80 and so quotient is in range -ff..-1
2403 ; if entered at div1, there is a +80 and so quotient is in range 1..ff
2404 ; falls out of loop after div01 with positive remainder, div11 with negative,
2405 ; depending on this we should re-enter at div0 or div1, signalled by cf return
2406
2407 ; the successive quotient bytes can be concatenated into a full quotient,
2408 ; but negative bytes require the next higher quotient byte to be decremented,
2409 ; we know in advance if this will happen because the implied sign of the
2410 ; quotient byte depends only on whether we entered at div0 or div1, hence,
2411 ; before the div11 return we'll decrement to compensate for next negative byte
2412
2413 ; the decrement can also be seen as compensating for the extra add hl,de that
2414 ; may be needed to make negative remainder positive before return to caller,
2415 ; thus leaving quotient in a consistent state regardless of which exit taken,
2416 ; remainder needs the add hl,de if cf=1 returned (equiv. return byte is even)
2417
2418 ; in the following code each sbc hl,de gets an inc a and each add hl,de gets
2419 ; a dec a, guaranteeing the integrity of the division, the initial scf/rla is
2420 ; needed to make the result 100 + -ff..ff or 1..1ff, so that the decrements
2421 ; cannot borrow into the upcoming dividend bits also held in a, and there must
2422 ; be another shift between the scf/rla and increment/decrement so that the scf
2423 ; is implicitly in the 100s place, making the code awkward though it's correct
2424
2425 ; now optimized to only inc/dec a when doing zero-crossing, fix above analysis
2426
2427 .if 1 ; temporary
2428 div_wcf:
2429         jr      c,div_w1
2430 div_w0: ; above
2431         push    de
2432         ld      d,8
2433         scf
2434         rla
2435 div_w00:
2436         adc     hl,hl
2437         jr      c,div_w01
2438         sbc     hl,bc
2439         jr      nc,div_w02
2440         dec     a
2441         ;jr     div_w12
2442         add     a,a
2443         dec     d
2444         jr      nz,div_w10
2445         ;inc    a
2446         ;dec    a                       ; compensation
2447         scf
2448         pop     de
2449         ret
2450 div_w01:
2451         or      a
2452         sbc     hl,bc
2453 div_w02:
2454         add     a,a
2455         dec     d
2456         jr      nz,div_w00
2457         dec     a
2458         or      a
2459         pop     de
2460         ret
2461
2462 div_w1: ; below
2463         push    de
2464         ld      d,8
2465         add     a,a
2466 div_w10:
2467         adc     hl,hl
2468         jr      nc,div_w11
2469         add     hl,bc
2470         jr      nc,div_w12
2471         inc     a
2472         ;jr     div_w02
2473         add     a,a
2474         dec     d
2475         jr      nz,div_w00
2476         dec     a
2477         or      a
2478         pop     de
2479         ret
2480 div_w11:
2481         add     hl,bc
2482 div_w12:
2483         add     a,a
2484         dec     d
2485         jr      nz,div_w10
2486         ;inc    a
2487         ;dec    a                       ; compensation
2488         scf
2489         pop     de
2490         ret
2491
2492 div_w_ncf:
2493         jr      c,div_w_n1
2494 div_w_n0: ; above
2495         push    de
2496         ld      d,8
2497         scf
2498         rla
2499 div_w_n00:
2500         adc     hl,hl
2501         jr      nc,div_w_n01
2502         or      a
2503         sbc     hl,bc
2504         jr      c,div_w_n02
2505         dec     a
2506         ;jr     div_w_n12
2507         add     a,a
2508         dec     d
2509         jr      nz,div_w_n10
2510         ;inc    a
2511         ;dec    a                       ; compensation
2512         scf
2513         pop     de
2514         ret
2515 div_w_n01:
2516         sbc     hl,bc
2517 div_w_n02:
2518         add     a,a
2519         dec     d
2520         jr      nz,div_w_n00
2521         dec     a
2522         or      a
2523         pop     de
2524         ret
2525
2526 div_w_n1: ; below
2527         push    de
2528         ld      d,8
2529         add     a,a
2530 div_w_n10:
2531         adc     hl,hl
2532         jr      c,div_w_n11
2533         add     hl,bc
2534         jr      c,div_w_n12
2535         inc     a
2536         ;jr     div_w_n02
2537         add     a,a
2538         dec     d
2539         jr      nz,div_w_n00
2540         dec     a
2541         or      a
2542         pop     de
2543         ret
2544 div_w_n11:
2545         add     hl,bc
2546 div_w_n12:
2547         add     a,a
2548         dec     d
2549         jr      nz,div_w_n10
2550         ;inc    a
2551         ;dec    a                       ; compensation
2552         scf
2553         pop     de
2554         ret
2555 .else
2556 div_wcf:
2557         jr      c,div_w1
2558 div_w0: ; bit 0, above
2559         scf
2560         rla
2561         adc     hl,hl
2562         sbc     hl,bc
2563         jr      nc,div_w01
2564         dec     a
2565 div_w11: ; bit 1, below
2566         add     a,a
2567         adc     hl,hl
2568         add     hl,bc
2569         jr      nc,div_w12
2570         inc     a
2571 div_w02: ; bit 2, above
2572         add     a,a
2573         adc     hl,hl
2574         sbc     hl,bc
2575         jr      nc,div_w03
2576         dec     a
2577 div_w13: ; bit 3, below
2578         add     a,a
2579         adc     hl,hl
2580         add     hl,bc
2581         jr      nc,div_w14
2582         inc     a
2583 div_w04: ; bit 4, above
2584         add     a,a
2585         adc     hl,hl
2586         sbc     hl,bc
2587         jr      nc,div_w05
2588         dec     a
2589 div_w15: ; bit 5, below
2590         add     a,a
2591         adc     hl,hl
2592         add     hl,bc
2593         jr      nc,div_w16
2594         inc     a
2595 div_w06: ; bit 6, above
2596         add     a,a
2597         adc     hl,hl
2598         sbc     hl,bc
2599         jr      nc,div_w07
2600         dec     a
2601 div_w17: ; bit 7, below
2602         add     a,a
2603         adc     hl,hl
2604         add     hl,bc
2605         jr      nc,div_w18
2606         inc     a
2607 div_w08: ; done, above
2608         add     a,a
2609         dec     a
2610         or      a
2611         ret
2612
2613 div_w1: ; bit 0, below
2614         add     a,a
2615         adc     hl,hl
2616         add     hl,bc
2617         jr      nc,div_w11
2618         inc     a
2619 div_w01: ; bit 1, above
2620         add     a,a
2621         adc     hl,hl
2622         sbc     hl,bc
2623         jr      nc,div_w02
2624         dec     a
2625 div_w12: ; bit 2, below
2626         add     a,a
2627         adc     hl,hl
2628         add     hl,bc
2629         jr      nc,div_w13
2630         inc     a
2631 div_w03: ; bit 3, above
2632         add     a,a
2633         adc     hl,hl
2634         sbc     hl,bc
2635         jr      nc,div_w04
2636         dec     a
2637 div_w14: ; bit 4, below
2638         add     a,a
2639         adc     hl,hl
2640         add     hl,bc
2641         jr      nc,div_w15
2642         inc     a
2643 div_w05: ; bit 5, above
2644         add     a,a
2645         adc     hl,hl
2646         sbc     hl,bc
2647         jr      nc,div_w06
2648         dec     a
2649 div_w16: ; bit 6, below
2650         add     a,a
2651         adc     hl,hl
2652         add     hl,bc
2653         jr      nc,div_w17
2654         inc     a
2655 div_w07: ; bit 7, above
2656         add     a,a
2657         adc     hl,hl
2658         sbc     hl,bc
2659         jr      nc,div_w08
2660         dec     a
2661 div_w18: ; done, below
2662         add     a,a
2663         ;inc    a
2664         ;dec    a                       ; compensation
2665         scf
2666         ret
2667
2668 ; divn0/1 are the same as div0/1 but carry reversed after add/subtract divisor
2669 ; this is for negative divisors where we expect carry (means no zero crossing)
2670
2671 ; when divisor negated, remainder also negated, so we expect to do subtraction
2672 ; when remainder negative and vice versa, need to clear carry after add hl,hl
2673
2674 div_w_ncf:
2675         jr      c,div_w_n1
2676 div_w_n0: ; bit 0, above
2677         scf
2678         rla
2679         adc     hl,hl
2680         or      a
2681         sbc     hl,bc
2682         jr      c,div_w_n01
2683         dec     a
2684 div_w_n11: ; bit 1, below
2685         add     a,a
2686         adc     hl,hl
2687         add     hl,bc
2688         jr      c,div_w_n12
2689         inc     a
2690 div_w_n02: ; bit 2, above
2691         add     a,a
2692         adc     hl,hl
2693         or      a
2694         sbc     hl,bc
2695         jr      c,div_w_n03
2696         dec     a
2697 div_w_n13: ; bit 3, below
2698         add     a,a
2699         adc     hl,hl
2700         add     hl,bc
2701         jr      c,div_w_n14
2702         inc     a
2703 div_w_n04: ; bit 4, above
2704         add     a,a
2705         adc     hl,hl
2706         or      a
2707         sbc     hl,bc
2708         jr      c,div_w_n05
2709         dec     a
2710 div_w_n15: ; bit 5, below
2711         add     a,a
2712         adc     hl,hl
2713         add     hl,bc
2714         jr      c,div_w_n16
2715         inc     a
2716 div_w_n06: ; bit 6, above
2717         add     a,a
2718         adc     hl,hl
2719         or      a
2720         sbc     hl,bc
2721         jr      c,div_w_n07
2722         dec     a
2723 div_w_n17: ; bit 7, below
2724         add     a,a
2725         adc     hl,hl
2726         add     hl,bc
2727         jr      c,div_w_n18
2728         inc     a
2729 div_w_n08: ; done, above
2730         add     a,a
2731         dec     a
2732         or      a
2733         ret
2734
2735 div_w_n1: ; bit 0, below
2736         add     a,a
2737         adc     hl,hl
2738         add     hl,bc
2739         jr      c,div_w_n11
2740         inc     a
2741 div_w_n01: ; bit 1, above
2742         add     a,a
2743         adc     hl,hl
2744         or      a
2745         sbc     hl,bc
2746         jr      c,div_w_n02
2747         dec     a
2748 div_w_n12: ; bit 2, below
2749         add     a,a
2750         adc     hl,hl
2751         add     hl,bc
2752         jr      c,div_w_n13
2753         inc     a
2754 div_w_n03: ; bit 3, above
2755         add     a,a
2756         adc     hl,hl
2757         or      a
2758         sbc     hl,bc
2759         jr      c,div_w_n04
2760         dec     a
2761 div_w_n14: ; bit 4, below
2762         add     a,a
2763         adc     hl,hl
2764         add     hl,bc
2765         jr      c,div_w_n15
2766         inc     a
2767 div_w_n05: ; bit 5, above
2768         add     a,a
2769         adc     hl,hl
2770         or      a
2771         sbc     hl,bc
2772         jr      c,div_w_n06
2773         dec     a
2774 div_w_n16: ; bit 6, below
2775         add     a,a
2776         adc     hl,hl
2777         add     hl,bc
2778         jr      c,div_w_n17
2779         inc     a
2780 div_w_n07: ; bit 7, above
2781         add     a,a
2782         adc     hl,hl
2783         or      a
2784         sbc     hl,bc
2785         jr      c,div_w_n08
2786         dec     a
2787 div_w_n18: ; done, below
2788         add     a,a
2789         ;inc    a
2790         ;dec    a                       ; compensation
2791         scf
2792         ret
2793 .endif
2794
2795 math_sdiv_sl0: ; hl':hl, de':de = hl':de % de':hl, hl':de / de':hl, signed
2796         exx
2797         ex      de,hl
2798         exx
2799 math_sdiv_sl: ; ; hl':hl, de':de = de':de % hl':hl, de':de / hl':hl, signed
2800         exx
2801         ld      c,l
2802         ld      b,h
2803         ld      a,d
2804         rla
2805         sub     a,a
2806         ld      l,a
2807         ld      h,a
2808         exx
2809         ld      c,l
2810         ld      b,h
2811         ld      l,a
2812         ld      h,a
2813 math_div_sl:
2814         ; hl':hl, de':de =
2815         ;   hl':hl:de':de % bc':bc, hl':hl:de':de / bc':bc, signed
2816         exx
2817         ld      a,h
2818         or      a
2819         jp      m,div_l_n               ; positive dividend
2820
2821         ; positive dividend
2822         ld      a,b
2823         rla
2824         ld      a,d
2825         exx
2826         jr      nc,div_l_pp             ; positive dividend, positive divisor
2827
2828         ; positive dividend, negative divisor
2829         call    div_l_n1
2830         exx
2831         ld      d,a
2832         ld      a,e
2833         exx
2834         call    div_l_ncf
2835         exx
2836         ld      e,a
2837         exx
2838         ld      a,d
2839         call    div_l_ncf
2840         ld      d,a
2841         ld      a,e
2842         call    div_l_ncf
2843         inc     a
2844         ld      e,a
2845         ret     c
2846         sbc     hl,bc
2847         exx
2848         sbc     hl,bc
2849         exx
2850         ret
2851
2852 div_l_n: ; negative dividend
2853         exx
2854         ld      a,e
2855         or      d
2856         dec     de                      ; reduces remainder by 1 (we inc later)
2857         exx
2858         jr      nz,1$
2859         dec     de
2860 1$:     ld      a,b
2861         rla
2862         ld      a,d
2863         exx
2864         jr      c,div_l_nn              ; negative dividend, negative divisor 
2865
2866         ; negative dividend, positive divisor
2867         call    div_l1
2868         exx
2869         ld      d,a
2870         ld      a,e
2871         exx
2872         call    div_lcf
2873         exx
2874         ld      e,a
2875         exx
2876         ld      a,d
2877         call    div_lcf
2878         ld      d,a
2879         ld      a,e
2880         call    div_lcf
2881         inc     a
2882         ld      e,a
2883         jr      c,2$
2884         sbc     hl,bc
2885         exx
2886         sbc     hl,bc
2887         exx
2888 2$:     inc     hl                      ; get into range divisor+1..0
2889         ld      a,l
2890         or      h
2891         ret     nz
2892         exx
2893         inc     hl
2894         exx
2895         ret
2896
2897 math_div_ul0: ; hl':hl, de':de = hl':de % de':hl, hl':de / de':hl, unsigned
2898         exx
2899         ex      de,hl
2900         exx
2901 math_div_ul1: ; ; hl':hl, de':de = de':de % hl':hl, de':de / hl':hl, unsigned
2902         ld      c,l
2903         ld      b,h
2904         sub     a
2905         ld      l,a
2906         ld      h,a
2907         exx
2908         ld      c,l
2909         ld      b,h
2910         ld      l,a
2911         ld      h,a
2912         exx
2913 math_div_ul:
2914         ; hl':hl, de':de =
2915         ;   hl':hl:de':de % bc':bc, hl':hl:de':de / bc':bc, unsigned
2916         exx
2917         ld      a,d
2918         exx
2919 div_l_pp: ; positive dividend, positive divisor
2920         call    div_l0
2921         exx
2922         ld      d,a
2923         ld      a,e
2924         exx
2925         call    div_lcf
2926         exx
2927         ld      e,a
2928         exx
2929         ld      a,d
2930         call    div_lcf
2931         ld      d,a
2932         ld      a,e
2933         call    div_lcf
2934         ld      e,a
2935         ret     nc
2936         add     hl,bc
2937         exx
2938         adc     hl,bc
2939         exx
2940         ret
2941
2942 div_l_nn: ; negative dividend, negative divisor
2943         call    div_l_n0
2944         exx
2945         ld      d,a
2946         ld      a,e
2947         exx
2948         call    div_l_ncf
2949         exx
2950         ld      e,a
2951         exx
2952         ld      a,d
2953         call    div_l_ncf
2954         ld      d,a
2955         ld      a,e
2956         call    div_l_ncf
2957         ld      e,a
2958         jr      nc,1$
2959         add     hl,bc
2960         exx
2961         adc     hl,bc
2962         exx
2963 1$:     inc     hl                      ; get into range divisor+1..0
2964         ld      a,l
2965         or      h
2966         ret     nz
2967         exx
2968         inc     hl
2969         exx
2970         ret
2971
2972 ; non-restoring division routine
2973 ; see earlier comments for the word version, this extends the concept to long
2974
2975 .if 1 ; temporary
2976 div_lcf:
2977         jr      c,div_l1
2978 div_l0: ; above
2979         push    de
2980         ld      d,8
2981         scf
2982         rla
2983 div_l00:
2984         adc     hl,hl
2985         exx
2986         adc     hl,hl
2987         exx
2988         jr      c,div_l01
2989         sbc     hl,bc
2990         exx
2991         sbc     hl,bc
2992         exx
2993         jr      nc,div_l02
2994         dec     a
2995         ;jr     div_l12
2996         add     a,a
2997         dec     d
2998         jr      nz,div_l10
2999         ;inc    a
3000         ;dec    a                       ; compensation
3001         scf
3002         pop     de
3003         ret
3004 div_l01:
3005         or      a
3006         sbc     hl,bc
3007         exx
3008         sbc     hl,bc
3009         exx
3010 div_l02:
3011         add     a,a
3012         dec     d
3013         jr      nz,div_l00
3014         dec     a
3015         or      a
3016         pop     de
3017         ret
3018
3019 div_l1: ; below
3020         push    de
3021         ld      d,8
3022         add     a,a
3023 div_l10:
3024         adc     hl,hl
3025         exx
3026         adc     hl,hl
3027         exx
3028         jr      nc,div_l11
3029         add     hl,bc
3030         exx
3031         adc     hl,bc
3032         exx
3033         jr      nc,div_l12
3034         inc     a
3035         ;jr     div_l02
3036         add     a,a
3037         dec     d
3038         jr      nz,div_l00
3039         dec     a
3040         or      a
3041         pop     de
3042         ret
3043 div_l11:
3044         add     hl,bc
3045         exx
3046         adc     hl,bc
3047         exx
3048 div_l12:
3049         add     a,a
3050         dec     d
3051         jr      nz,div_l10
3052         ;inc    a
3053         ;dec    a                       ; compensation
3054         scf
3055         pop     de
3056         ret
3057
3058 div_l_ncf:
3059         jr      c,div_l_n1
3060 div_l_n0: ; above
3061         push    de
3062         ld      d,8
3063         scf
3064         rla
3065 div_l_n00:
3066         adc     hl,hl
3067         exx
3068         adc     hl,hl
3069         exx
3070         jr      nc,div_l_n01
3071         or      a
3072         sbc     hl,bc
3073         exx
3074         sbc     hl,bc
3075         exx
3076         jr      c,div_l_n02
3077         dec     a
3078         ;jr     div_l_n12
3079         add     a,a
3080         dec     d
3081         jr      nz,div_l_n10
3082         ;inc    a
3083         ;dec    a                       ; compensation
3084         scf
3085         pop     de
3086         ret
3087 div_l_n01:
3088         sbc     hl,bc
3089         exx
3090         sbc     hl,bc
3091         exx
3092 div_l_n02:
3093         add     a,a
3094         dec     d
3095         jr      nz,div_l_n00
3096         dec     a
3097         or      a
3098         pop     de
3099         ret
3100
3101 div_l_n1: ; below
3102         push    de
3103         ld      d,8
3104         add     a,a
3105 div_l_n10:
3106         adc     hl,hl
3107         exx
3108         adc     hl,hl
3109         exx
3110         jr      c,div_l_n11
3111         add     hl,bc
3112         exx
3113         adc     hl,bc
3114         exx
3115         jr      c,div_l_n12
3116         inc     a
3117         ;jr     div_l_n02
3118         add     a,a
3119         dec     d
3120         jr      nz,div_l_n00
3121         dec     a
3122         or      a
3123         pop     de
3124         ret
3125 div_l_n11:
3126         add     hl,bc
3127         exx
3128         adc     hl,bc
3129         exx
3130 div_l_n12:
3131         add     a,a
3132         dec     d
3133         jr      nz,div_l_n10
3134         ;inc    a
3135         ;dec    a                       ; compensation
3136         scf
3137         pop     de
3138         ret
3139 .else
3140 ; changed all jr to jp, revisit this
3141
3142 div_lcf:
3143         jp      c,div_l1
3144 div_l0: ; bit 0, above
3145         scf
3146         rla
3147         adc     hl,hl
3148         exx
3149         adc     hl,hl
3150         exx
3151         sbc     hl,bc
3152         exx
3153         sbc     hl,bc
3154         exx
3155         jp      nc,div_l01
3156         dec     a
3157 div_l11: ; bit 1, below
3158         add     a,a
3159         adc     hl,hl
3160         exx
3161         adc     hl,hl
3162         exx
3163         add     hl,bc
3164         exx
3165         adc     hl,bc
3166         exx
3167         jp      nc,div_l12
3168         inc     a
3169 div_l02: ; bit 2, above
3170         add     a,a
3171         adc     hl,hl
3172         exx
3173         adc     hl,hl
3174         exx
3175         sbc     hl,bc
3176         exx
3177         sbc     hl,bc
3178         exx
3179         jp      nc,div_l03
3180         dec     a
3181 div_l13: ; bit 3, below
3182         add     a,a
3183         adc     hl,hl
3184         exx
3185         adc     hl,hl
3186         exx
3187         add     hl,bc
3188         exx
3189         adc     hl,bc
3190         exx
3191         jp      nc,div_l14
3192         inc     a
3193 div_l04: ; bit 4, above
3194         add     a,a
3195         adc     hl,hl
3196         exx
3197         adc     hl,hl
3198         exx
3199         sbc     hl,bc
3200         exx
3201         sbc     hl,bc
3202         exx
3203         jp      nc,div_l05
3204         dec     a
3205 div_l15: ; bit 5, below
3206         add     a,a
3207         adc     hl,hl
3208         exx
3209         adc     hl,hl
3210         exx
3211         add     hl,bc
3212         exx
3213         adc     hl,bc
3214         exx
3215         jp      nc,div_l16
3216         inc     a
3217 div_l06: ; bit 6, above
3218         add     a,a
3219         adc     hl,hl
3220         exx
3221         adc     hl,hl
3222         exx
3223         sbc     hl,bc
3224         exx
3225         sbc     hl,bc
3226         exx
3227         jp      nc,div_l07
3228         dec     a
3229 div_l17: ; bit 7, below
3230         add     a,a
3231         adc     hl,hl
3232         exx
3233         adc     hl,hl
3234         exx
3235         add     hl,bc
3236         exx
3237         adc     hl,bc
3238         exx
3239         jp      nc,div_l18
3240         inc     a
3241 div_l08: ; done, above
3242         add     a,a
3243         dec     a
3244         or      a
3245         ret
3246
3247 div_l1: ; bit 0, below
3248         add     a,a
3249         adc     hl,hl
3250         exx
3251         adc     hl,hl
3252         exx
3253         add     hl,bc
3254         exx
3255         adc     hl,bc
3256         exx
3257         jp      nc,div_l11
3258         inc     a
3259 div_l01: ; bit 1, above
3260         add     a,a
3261         adc     hl,hl
3262         exx
3263         adc     hl,hl
3264         exx
3265         sbc     hl,bc
3266         exx
3267         sbc     hl,bc
3268         exx
3269         jp      nc,div_l02
3270         dec     a
3271 div_l12: ; bit 2, below
3272         add     a,a
3273         adc     hl,hl
3274         exx
3275         adc     hl,hl
3276         exx
3277         add     hl,bc
3278         exx
3279         adc     hl,bc
3280         exx
3281         jp      nc,div_l13
3282         inc     a
3283 div_l03: ; bit 3, above
3284         add     a,a
3285         adc     hl,hl
3286         exx
3287         adc     hl,hl
3288         exx
3289         sbc     hl,bc
3290         exx
3291         sbc     hl,bc
3292         exx
3293         jp      nc,div_l04
3294         dec     a
3295 div_l14: ; bit 4, below
3296         add     a,a
3297         adc     hl,hl
3298         exx
3299         adc     hl,hl
3300         exx
3301         add     hl,bc
3302         exx
3303         adc     hl,bc
3304         exx
3305         jp      nc,div_l15
3306         inc     a
3307 div_l05: ; bit 5, above
3308         add     a,a
3309         adc     hl,hl
3310         exx
3311         adc     hl,hl
3312         exx
3313         sbc     hl,bc
3314         exx
3315         sbc     hl,bc
3316         exx
3317         jp      nc,div_l06
3318         dec     a
3319 div_l16: ; bit 6, below
3320         add     a,a
3321         adc     hl,hl
3322         exx
3323         adc     hl,hl
3324         exx
3325         add     hl,bc
3326         exx
3327         adc     hl,bc
3328         exx
3329         jp      nc,div_l17
3330         inc     a
3331 div_l07: ; bit 7, above
3332         add     a,a
3333         adc     hl,hl
3334         exx
3335         adc     hl,hl
3336         exx
3337         sbc     hl,bc
3338         exx
3339         sbc     hl,bc
3340         exx
3341         jp      nc,div_l08
3342         dec     a
3343 div_l18: ; done, below
3344         add     a,a
3345         ;inc    a
3346         ;dec    a                       ; compensation
3347         scf
3348         ret
3349
3350 ; version for negative divisors
3351 ; see earlier comments for the word version, this extends the concept to long
3352
3353 div_l_ncf:
3354         jp      c,div_l_n1
3355 div_l_n0: ; bit 0, above
3356         scf
3357         rla
3358         adc     hl,hl
3359         exx
3360         adc     hl,hl
3361         exx
3362         or      a
3363         sbc     hl,bc
3364         exx
3365         sbc     hl,bc
3366         exx
3367         jp      c,div_l_n01
3368         dec     a
3369 div_l_n11: ; bit 1, below
3370         add     a,a
3371         adc     hl,hl
3372         exx
3373         adc     hl,hl
3374         exx
3375         add     hl,bc
3376         exx
3377         adc     hl,bc
3378         exx
3379         jp      c,div_l_n12
3380         inc     a
3381 div_l_n02: ; bit 2, above
3382         add     a,a
3383         adc     hl,hl
3384         exx
3385         adc     hl,hl
3386         exx
3387         or      a
3388         sbc     hl,bc
3389         exx
3390         sbc     hl,bc
3391         exx
3392         jp      c,div_l_n03
3393         dec     a
3394 div_l_n13: ; bit 3, below
3395         add     a,a
3396         adc     hl,hl
3397         exx
3398         adc     hl,hl
3399         exx
3400         add     hl,bc
3401         exx
3402         adc     hl,bc
3403         exx
3404         jp      c,div_l_n14
3405         inc     a
3406 div_l_n04: ; bit 4, above
3407         add     a,a
3408         adc     hl,hl
3409         exx
3410         adc     hl,hl
3411         exx
3412         or      a
3413         sbc     hl,bc
3414         exx
3415         sbc     hl,bc
3416         exx
3417         jp      c,div_l_n05
3418         dec     a
3419 div_l_n15: ; bit 5, below
3420         add     a,a
3421         adc     hl,hl
3422         exx
3423         adc     hl,hl
3424         exx
3425         add     hl,bc
3426         exx
3427         adc     hl,bc
3428         exx
3429         jp      c,div_l_n16
3430         inc     a
3431 div_l_n06: ; bit 6, above
3432         add     a,a
3433         adc     hl,hl
3434         exx
3435         adc     hl,hl
3436         or      a
3437         exx
3438         sbc     hl,bc
3439         exx
3440         sbc     hl,bc
3441         exx
3442         jp      c,div_l_n07
3443         dec     a
3444 div_l_n17: ; bit 7, below
3445         add     a,a
3446         adc     hl,hl
3447         exx
3448         adc     hl,hl
3449         exx
3450         add     hl,bc
3451         exx
3452         adc     hl,bc
3453         exx
3454         jp      c,div_l_n18
3455         inc     a
3456 div_l_n08: ; done, above
3457         add     a,a
3458         dec     a
3459         or      a
3460         ret
3461
3462 div_l_n1: ; bit 0, below
3463         add     a,a
3464         adc     hl,hl
3465         exx
3466         adc     hl,hl
3467         exx
3468         add     hl,bc
3469         exx
3470         adc     hl,bc
3471         exx
3472         jp      c,div_l_n11
3473         inc     a
3474 div_l_n01: ; bit 1, above
3475         add     a,a
3476         adc     hl,hl
3477         exx
3478         adc     hl,hl
3479         exx
3480         or      a
3481         sbc     hl,bc
3482         exx
3483         sbc     hl,bc
3484         exx
3485         jp      c,div_l_n02
3486         dec     a
3487 div_l_n12: ; bit 2, below
3488         add     a,a
3489         adc     hl,hl
3490         exx
3491         adc     hl,hl
3492         exx
3493         add     hl,bc
3494         exx
3495         adc     hl,bc
3496         exx
3497         jp      c,div_l_n13
3498         inc     a
3499 div_l_n03: ; bit 3, above
3500         add     a,a
3501         adc     hl,hl
3502         exx
3503         adc     hl,hl
3504         exx
3505         or      a
3506         sbc     hl,bc
3507         exx
3508         sbc     hl,bc
3509         exx
3510         jp      c,div_l_n04
3511         dec     a
3512 div_l_n14: ; bit 4, below
3513         add     a,a
3514         adc     hl,hl
3515         exx
3516         adc     hl,hl
3517         exx
3518         add     hl,bc
3519         exx
3520         adc     hl,bc
3521         exx
3522         jp      c,div_l_n15
3523         inc     a
3524 div_l_n05: ; bit 5, above
3525         add     a,a
3526         adc     hl,hl
3527         exx
3528         adc     hl,hl
3529         exx
3530         or      a
3531         sbc     hl,bc
3532         exx
3533         sbc     hl,bc
3534         exx
3535         jp      c,div_l_n06
3536         dec     a
3537 div_l_n16: ; bit 6, below
3538         add     a,a
3539         adc     hl,hl
3540         exx
3541         adc     hl,hl
3542         exx
3543         add     hl,bc
3544         exx
3545         adc     hl,bc
3546         exx
3547         jp      c,div_l_n17
3548         inc     a
3549 div_l_n07: ; bit 7, above
3550         add     a,a
3551         adc     hl,hl
3552         exx
3553         adc     hl,hl
3554         exx
3555         or      a
3556         sbc     hl,bc
3557         exx
3558         sbc     hl,bc
3559         exx
3560         jp      c,div_l_n08
3561         dec     a
3562 div_l_n18: ; done, below
3563         add     a,a
3564         ;inc    a
3565         ;dec    a                       ; compensation
3566         scf
3567         ret
3568 .endif
3569
3570 ; debugging
3571
3572 print_hlde:
3573         call    print_word
3574         ld      a,':
3575         call    print_char
3576         ex      de,hl
3577         call    print_word
3578         ex      de,hl
3579         ld      a,0xd
3580         call    print_char
3581         ld      a,0xa
3582         jp      print_char
3583
3584 print_hlhldede:
3585         exx
3586         call    print_word
3587         exx
3588         call    print_word
3589         ld      a,':
3590         call    print_char
3591         exx
3592         ex      de,hl
3593         call    print_word
3594         ex      de,hl
3595         exx
3596         ex      de,hl
3597         call    print_word
3598         ex      de,hl
3599         ld      a,0xd
3600         call    print_char
3601         ld      a,0xa
3602         jp      print_char
3603
3604 print_trace: ; print af, bc, hl':de, de':hl, (sp+2):(sp), sp
3605         call    print_trace2
3606         ld      a,(bc)
3607         inc     bc
3608         ld      l,a
3609         jp      (hl)
3610 print_trace2:
3611         push    hl
3612         push    af
3613         pop     hl
3614         push    hl
3615         call    print_word
3616         ld      a,' 
3617         call    print_char
3618         ld      l,c
3619         ld      h,b
3620         call    print_word
3621         ld      a,' 
3622         call    print_char
3623         exx
3624         push    hl
3625         exx
3626         pop     hl
3627         call    print_word
3628         ld      a,':
3629         call    print_char
3630         ld      l,e
3631         ld      h,d
3632         call    print_word
3633         ld      a,' 
3634         call    print_char
3635         exx
3636         push    de
3637         exx
3638         pop     hl
3639         call    print_word
3640         ld      a,':
3641         call    print_char
3642         pop     af
3643         pop     hl
3644         push    hl
3645         push    af
3646         call    print_word
3647         ld      a,' 
3648         call    print_char
3649         ld      hl,8
3650         add     hl,sp
3651         ld      a,(hl)
3652         inc     hl
3653         ld      h,(hl)
3654         ld      l,a
3655         call    print_word
3656         ld      a,':
3657         call    print_char
3658         ld      hl,6
3659         add     hl,sp
3660         ld      a,(hl)
3661         inc     hl
3662         ld      h,(hl)
3663         ld      l,a
3664         call    print_word
3665         ld      a,' 
3666         call    print_char
3667         ld      hl,6
3668         add     hl,sp
3669         call    print_word
3670         ld      a,0xd
3671         call    print_char
3672         ld      a,0xa
3673         call    print_char
3674         pop     af
3675         pop     hl
3676         ret
3677
3678 print_word:
3679         push    af
3680         ld      a,h
3681         call    print_byte
3682         ld      a,l
3683         call    print_byte
3684         pop     af
3685         ret
3686
3687 print_byte:
3688         push    af
3689         push    af
3690         rrca
3691         rrca
3692         rrca
3693         rrca
3694         call    print_digit
3695         pop     af
3696         call    print_digit
3697         pop     af
3698         ret
3699
3700 print_digit:
3701         push    de
3702         push    hl
3703         and     0xf
3704         ld      e,a
3705         ld      d,0
3706         ld      hl,digits
3707         add     hl,de
3708         ld      a,(hl)
3709         pop     hl
3710         pop     de
3711 print_char:
3712         push    bc
3713         push    de
3714         push    hl
3715         ld      e,a
3716         ld      c,2
3717         call    5
3718         pop     hl
3719         pop     de
3720         pop     bc
3721         ret
3722
3723 digits:
3724         .ascii  '0123456789abcdef'
3725
3726 ; sm code
3727
3728 sm_main:
3729         ; create stack frame
3730         .db     <page0_stkadj
3731         .dw     -4
3732
3733         ; push argument
3734         .db     <page0_imm_w
3735         .dw     7
3736
3737         ; push result pointer
3738         .db     <page1_page0
3739         .db     <page0_stkptr
3740         .dw     2
3741
3742         ; call sm_factorial(argument)
3743         .db     <page1_page0
3744         .db     <page0_imm_call
3745         .dw     sm_factorial
3746         .dw     4
3747
3748         ; let i = 0
3749         .db     <page0_imm_w
3750         .dw     0
3751         .db     <page1_stkst_w
3752         .dw     2;+2
3753
3754 digit_loop:
3755         ; while i < 5
3756         .db     <page0_stkld_w
3757         .dw     2;+2
3758         .db     <page1_imm_cmp_sw
3759         .dw     5
3760         .db     <page0_jge
3761         .dw     digit_loope
3762
3763         ; get current value
3764         .db     <page0_stkld_w
3765         .dw     0;+2
3766
3767         ; get place value
3768         .db     <page1_page0
3769         .db     <page0_stkld_w
3770         .dw     4;+2
3771         .db     <page1_imm_sl_w
3772         .dw     1
3773         .db     <page1_imm_add_w
3774         .dw     place_values
3775         .db     <page1_ld_w
3776
3777         ; divide by place value
3778         .db     <page1_div_sw
3779
3780         ; replace current value with remainder
3781         .db     <page1_stkst_w
3782         .dw     2;+2
3783
3784         ; print quotient plus '0
3785         .db     <page0_page1
3786         .db     <page1_imm_add_w
3787         .dw     '0
3788         .db     <page1_page0
3789         .db     <page0_imm_call
3790         .dw     sm_print_char
3791         .dw     2
3792
3793         ; ++i
3794         .db     <page0_stkld_w
3795         .dw     2;+2
3796         .db     <page1_imm_add_w
3797         .dw     1
3798         .db     <page1_stkst_w
3799         .dw     2;+2
3800
3801         ; loop
3802         .db     <page0_imm_jmp
3803         .dw     digit_loop
3804
3805 digit_loope:
3806         ; print cr
3807         .db     <page0_imm_w
3808         .dw     0xd
3809         .db     <page1_page0
3810         .db     <page0_imm_call
3811         .dw     sm_print_char
3812         .dw     2
3813
3814         ; print lf
3815         .db     <page0_imm_w
3816         .dw     0xa
3817         .db     <page1_page0
3818         .db     <page0_imm_call
3819         .dw     sm_print_char
3820         .dw     2
3821
3822         ; enlarge stack frame
3823         .db     <page0_stkadj
3824         .dw     -2
3825
3826         ; push argument
3827         .db     <page0_imm_l
3828         .dw     12,0
3829
3830         ; push result pointer
3831         .db     <page2_page0
3832         .db     <page0_stkptr
3833         .dw     4
3834
3835         ; call sm_factorial(argument)
3836         .db     <page1_page0
3837         .db     <page0_imm_call
3838         .dw     sm_factorial2
3839         .dw     6
3840
3841         ; let i = 0
3842         .db     <page0_imm_w
3843         .dw     0
3844         .db     <page1_stkst_w
3845         .dw     4;+2
3846
3847 digit_loop2:
3848         ; while i < 10
3849         .db     <page0_stkld_w
3850         .dw     4;+2
3851         .db     <page1_imm_cmp_sw
3852         .dw     10
3853         .db     <page0_jge
3854         .dw     digit_loope2
3855
3856         ; get current value
3857         .db     <page0_stkld_l
3858         .dw     0;+2
3859
3860         ; get place value
3861         .db     <page2_page0
3862         .db     <page0_stkld_w
3863         .dw     8;+2
3864         .db     <page1_imm_sl_w
3865         .dw     2
3866         .db     <page1_imm_add_w
3867         .dw     place_values2
3868         .db     <page1_ld_l
3869
3870         ; divide by place value
3871         .db     <page2_div_sl
3872
3873         ; replace current value with remainder
3874         .db     <page2_stkst_l
3875         .dw     4;+2
3876
3877         ; print quotient plus '0
3878         .db     <page0_page1
3879         .db     <page1_imm_add_w
3880         .dw     '0
3881         .db     <page1_page0
3882         .db     <page0_imm_call
3883         .dw     sm_print_char
3884         .dw     4 ; cheating -- kill hi word of long too
3885
3886         ; ++i
3887         .db     <page0_stkld_w
3888         .dw     4;+2
3889         .db     <page1_imm_add_w
3890         .dw     1
3891         .db     <page1_stkst_w
3892         .dw     4;+2
3893
3894         ; loop
3895         .db     <page0_imm_jmp
3896         .dw     digit_loop2
3897
3898 digit_loope2:
3899         ; print cr
3900         .db     <page0_imm_w
3901         .dw     0xd
3902         .db     <page1_page0
3903         .db     <page0_imm_call
3904         .dw     sm_print_char
3905         .dw     2
3906
3907         ; print lf
3908         .db     <page0_imm_w
3909         .dw     0xa
3910         .db     <page1_page0
3911         .db     <page0_imm_call
3912         .dw     sm_print_char
3913         .dw     2
3914
3915         ; destroy stack frame
3916         .db     <page0_stkadj
3917         .dw     6
3918
3919         ; return
3920         .db     <page0_ret
3921
3922 place_values:
3923         .dw     10000,1000,100,10,1
3924 place_values2:
3925         .dw     0xca00,0x3b9a ; 1000000000
3926         .dw     0xe100,0x5f5 ; 100000000
3927         .dw     0x9680,0x98 ; 10000000
3928         .dw     0x4240,0xf ; 1000000
3929         .dw     0x86a0,1 ; 100000
3930         .dw     10000,0
3931         .dw     1000,0
3932         .dw     100,0
3933         .dw     10,0
3934         .dw     1,0
3935
3936 sm_factorial:
3937         ; get argument
3938         .db     <page0_stkld_w
3939         .dw     4;+2
3940
3941         ; is argument < 2?
3942         .db     <page1_imm_cmp_sw
3943         .dw     2
3944         .db     <page0_jlt
3945         .dw     1$
3946
3947         ; no, set up for *result =
3948         .db     <page0_stkld_w
3949         .dw     2;+2
3950
3951         ; get argument
3952         .db     <page1_page0
3953         .db     <page0_stkld_w
3954         .dw     6;+2
3955
3956         ; subtract 1
3957         .db     <page1_imm_add_w
3958         .dw     -1
3959
3960         ; push result pointer
3961         .db     <page1_page0
3962         .db     <page0_stkptr
3963         .dw     0
3964
3965         ; call sm_factorial(argument - 1)
3966         .db     <page1_page0
3967         .db     <page0_imm_call
3968         .dw     sm_factorial
3969         .dw     2
3970
3971         ; get argument
3972         .db     <page0_stkld_w
3973         .dw     8;+2
3974
3975         ; multiply
3976         .db     <page1_mul_w
3977
3978         ; set *result = sm_factorial(argument - 1) * argument
3979         .db     <page1_st_w
3980
3981         ; return
3982         .db     <page0_ret
3983
3984 1$:
3985         ; yes, set up for *result =
3986         .db     <page0_stkld_w
3987         .dw     2;+2
3988
3989         ; set *result = 1
3990         .db     <page1_page0
3991         .db     <page0_imm_w
3992         .dw     1
3993         .db     <page1_st_w
3994
3995         ; return
3996         .db     <page0_ret
3997
3998 sm_factorial2:
3999         ; get argument
4000         .db     <page0_stkld_l
4001         .dw     4;+2
4002
4003         ; is argument < 2?
4004         .db     <page2_imm_cmp_sl
4005         .dw     2
4006         .dw     0
4007         .db     <page0_jlt
4008         .dw     1$
4009
4010         ; no, set up for *result =
4011         .db     <page0_stkld_w
4012         .dw     2;+2
4013
4014         ; get argument
4015         .db     <page1_page0
4016         .db     <page0_stkld_l
4017         .dw     6;+2
4018
4019         ; subtract 1
4020         .db     <page2_imm_add_l
4021         .dw     -1,-1
4022
4023         ; push result pointer
4024         .db     <page2_page0
4025         .db     <page0_stkptr
4026         .dw     0
4027
4028         ; call sm_factorial(argument - 1)
4029         .db     <page1_page0
4030         .db     <page0_imm_call
4031         .dw     sm_factorial2
4032         .dw     2
4033
4034         ; get argument
4035         .db     <page0_stkld_l
4036         .dw     10;+2
4037
4038         ; multiply
4039         .db     <page2_mul_l
4040
4041         ; set *result = sm_factorial(argument - 1) * argument
4042         .db     <page2_st_l
4043
4044         ; return
4045         .db     <page0_ret
4046
4047 1$:
4048         ; yes, set up for *result =
4049         .db     <page0_stkld_w
4050         .dw     2;+2
4051
4052         ; set *result = 1
4053         .db     <page1_page0
4054         .db     <page0_imm_l
4055         .dw     1,0
4056         .db     <page2_st_l
4057
4058         ; return
4059         .db     <page0_ret
4060
4061 sm_print_char:
4062         .db     <page0_esc
4063         ld      hl,2
4064         add     hl,sp
4065         ld      a,(hl)
4066         call    print_char
4067         jp      page0_ret