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