Unroll slightly to avoid an inner loop jump to loop end on zero crossing
[stack_machine.git] / sm2.asm
1 page0   =       1
2 page1   =       2
3
4         .area   SM (abs,ovr)
5
6 ; page 0 interpreter
7 ; stack and control transfer
8
9         .org    page0 * 0x100
10
11         jp      start
12
13 page0_trace:
14         jp      print_trace
15
16 page0_esc:
17         ld      l,c
18         ld      h,b
19         jp      (hl)
20
21 page0_page1:
22         pop     de
23         ld      a,(bc)
24         inc     bc
25         ld      l,a
26         inc     h ; page 1
27         jp      (hl)
28
29 page0_imm_xchg_w:
30         ld      a,(bc)
31         inc     bc
32         ld      l,a
33         ld      a,(bc)
34         inc     bc
35         ld      h,a
36         .db     0x3e ; ld a,
37 page0_xchg_w:
38         pop     hl
39         ex      (sp),hl
40         push    hl
41         ld      a,(bc)
42         inc     bc
43         ld      l,a
44         ld      h,page0
45         jp      (hl)
46
47 page0_call:
48         pop     de
49 _call:
50         push    bc
51         ld      c,e
52         ld      b,d
53         inc     bc
54         ld      l,(hl)
55         jp      (hl)
56
57 page0_imm_jfalse:
58         jr      nc,page0_imm_jmp
59 imm_not_taken:
60         inc     bc
61         inc     bc
62         ld      a,(bc)
63         inc     bc
64         ld      l,a
65         jp      (hl)
66
67 page0_imm_jtrue:
68         jr      nc,imm_not_taken
69 page0_imm_jmp:
70         ld      a,(bc)
71         inc     bc
72         ld      l,a
73         ld      a,(bc)
74         ld      b,a
75         ld      c,l
76         ld      a,(bc)
77         inc     bc
78         ld      l,a
79         jp      (hl)
80
81 page0_jfalse:
82         jr      nc,page0_jmp
83 not_taken:
84         inc     sp
85         inc     sp
86         ld      a,(bc)
87         inc     bc
88         ld      l,a
89         jp      (hl)
90
91 page0_jtrue:
92         jr      nc,not_taken
93 page0_jmp:
94         pop     bc
95         ld      a,(bc)
96         inc     bc
97         ld      l,a
98         jp      (hl)
99
100         .org    page0 * 0x100 + 0x84
101
102 imm_call:
103         push    de
104         dec     h ; page 0
105 page0_imm_call:
106         ld      a,(bc)
107         inc     bc
108         ld      l,a
109         ld      a,(bc)
110         inc     bc
111         push    bc
112         ld      b,a
113         ld      c,l
114         ld      a,(bc)
115         inc     bc
116         ld      l,a
117         jp      (hl)
118
119 stkptr:
120         push    de
121 page0_stkptr:
122         ld      a,(bc)
123         inc     bc
124         ld      l,a
125         ld      a,(bc)
126         inc     bc
127         ld      h,a
128         add     hl,sp
129         ex      de,hl
130         ld      a,(bc)
131         inc     bc
132         ld      l,a
133         ld      h,page1
134         jp      (hl)
135
136 page0_ret:
137         pop     bc
138 page0_stkadj:
139 stkadj:
140         ld      a,(bc)
141         inc     bc
142         ld      l,a
143         ld      a,(bc)
144         inc     bc
145         ld      h,a
146         add     hl,sp
147         ld      sp,hl
148         ld      a,(bc)
149         inc     bc
150         ld      l,a
151         ld      h,page0
152         jp      (hl)
153
154 stkld_w:
155         push    de
156 page0_stkld_w:
157         ld      a,(bc)
158         inc     bc
159         ld      l,a
160         ld      a,(bc)
161         inc     bc
162         ld      h,a
163         add     hl,sp
164         ld      e,(hl)
165         inc     hl
166         ld      d,(hl)
167         ld      a,(bc)
168         inc     bc
169         ld      l,a
170         ld      h,page1
171         jp      (hl)
172
173 page0_stkst_w:
174         pop     de
175 stkst_w:
176         ld      a,(bc)
177         inc     bc
178         ld      l,a
179         ld      a,(bc)
180         inc     bc
181         ld      h,a
182         add     hl,sp
183         ld      (hl),e
184         inc     hl
185         ld      (hl),d
186         ld      a,(bc)
187         inc     bc
188         ld      l,a
189         ld      h,page0
190         jp      (hl)
191
192 page0_imm_w:
193         inc     h ; page1
194 imm_w:
195         ld      a,(bc)
196         inc     bc
197         ld      e,a
198         ld      a,(bc)
199         inc     bc
200         ld      d,a
201         ld      a,(bc)
202         inc     bc
203         ld      l,a
204         jp      (hl)
205
206 page0_ld_w:
207         pop     de
208         inc     h ; page1
209 ld_w:
210         ld      a,(de)
211         inc     de
212         ld      l,a
213         ld      a,(de)
214         ld      d,a
215         ld      e,l
216         ld      a,(bc)
217         inc     bc
218         ld      l,a
219         jp      (hl)
220
221 page0_imm_st_w:
222         pop     de
223 imm_st_w:
224         ld      a,(bc)
225         inc     bc
226         ld      (de),a
227         inc     de
228         ld      a,(bc)
229         inc     bc
230         ld      (de),a
231         ld      a,(bc)
232         inc     bc
233         ld      l,a
234         jp      (hl)
235
236 page0_st_w:
237         pop     de
238 st_w:
239         pop     hl
240         ld      (hl),e
241         inc     hl
242         ld      (hl),d
243         ld      a,(bc)
244         inc     bc
245         ld      l,a
246         ld      h,page0
247         jp      (hl)
248
249 ; page 1 interpreter
250 ; word arithmetic operations
251 ; top stack word cached in de
252
253         .org    page1 * 0x100
254
255 page1_imm_call:
256         jr      imm_call
257 page1_stkptr:
258         jr      stkptr
259 page1_stkadj:
260         push    de
261         jr      stkadj
262 page1_stkld_w:
263         jr      stkld_w
264 page1_stkst_w:
265         jr      stkst_w
266 page1_imm_w:
267         push    de
268         jr      imm_w
269 page1_ld_w:
270         jr      ld_w
271 page1_imm_st_w:
272         dec     h ; page0
273         jr      imm_st_w
274 page1_st_w:
275         jr      st_w
276
277 page1_page0:
278         push    de
279         ld      a,(bc)
280         inc     bc
281         ld      l,a
282         dec     h ; page 0
283         jp      (hl)
284
285 page1_call:
286         dec     h ; page 0
287         jp      _call
288
289 page1_imm_and_w:
290         ld      a,(bc)
291         inc     bc
292         and     e
293         ld      e,a
294         ld      a,(bc)
295         inc     bc
296         and     d
297         ld      d,a
298         ld      a,(bc)
299         inc     bc
300         ld      l,a
301         jp      (hl)
302
303 page1_and_w:
304         pop     hl
305         ld      a,e
306         and     l
307         ld      e,a
308         ld      a,d
309         and     h
310         ld      d,a
311         ld      a,(bc)
312         inc     bc
313         ld      l,a
314         ld      h,page1
315         jp      (hl)
316
317 page1_imm_or_w:
318         ld      a,(bc)
319         inc     bc
320         or      e
321         ld      e,a
322         ld      a,(bc)
323         inc     bc
324         or      d
325         ld      d,a
326         ld      a,(bc)
327         inc     bc
328         ld      l,a
329         jp      (hl)
330
331 page1_or_w:
332         pop     hl
333         ld      a,e
334         or      l
335         ld      e,a
336         ld      a,d
337         or      h
338         ld      d,a
339         ld      a,(bc)
340         inc     bc
341         ld      l,a
342         ld      h,page1
343         jp      (hl)
344
345 ;page1_imm_xor_w:
346 ;       ld      a,(bc)
347 ;       inc     bc
348 ;       xor     e
349 ;       ld      e,a
350 ;       ld      a,(bc)
351 ;       inc     bc
352 ;       xor     d
353 ;       ld      d,a
354 ;       ld      a,(bc)
355 ;       inc     bc
356 ;       ld      l,a
357 ;       jp      (hl)
358
359 page1_imm_xor_w: ; xor is less common than and/or, so save space for immediate
360         ld      a,(bc)
361         ld      l,a
362         inc     bc
363         ld      a,(bc)
364         ld      h,a
365         inc     bc
366         .db     0x3e ; ld a,
367 page1_xor_w:
368         pop     hl
369         ld      a,e
370         xor     l
371         ld      e,a
372         ld      a,d
373         xor     h
374         ld      d,a
375         ld      a,(bc)
376         inc     bc
377         ld      l,a
378         ld      h,page1
379         jp      (hl)
380
381 page1_imm_add_w: ; use also for page1_imm_sub_w with negated argument
382         ld      a,(bc)
383         ld      l,a
384         inc     bc
385         ld      a,(bc)
386         ld      h,a
387         inc     bc
388         .db     0x3e ; ld a,
389 page1_add_w:
390         pop     hl
391         add     hl,de
392         ex      de,hl
393         ld      a,(bc)
394         inc     bc
395         ld      l,a
396         ld      h,page1
397         jp      (hl)
398
399 page1_imm_xchg_sub_w: ; reversed, use with argument 0 for neg, -1 for cpl
400         ld      a,(bc)
401         ld      l,a
402         inc     bc
403         ld      a,(bc)
404         ld      h,a
405         inc     bc
406         .db     0x3e ; ld a,
407 page1_sub_w:
408         pop     hl
409         or      a
410         sbc     hl,de
411 mul_done:
412         ex      de,hl
413         ld      a,(bc)
414         inc     bc
415         ld      l,a
416         ld      h,page1
417         jp      (hl)
418
419 page1_imm_eq_w:
420         ld      a,(bc)
421         ld      l,a
422         inc     bc
423         ld      a,(bc)
424         ld      h,a
425         inc     bc
426         .db     0x3e ; ld a,
427 page1_eq_w:
428         pop     hl
429         or      a
430         sbc     hl,de
431         ld      a,l
432         or      h
433         cp      1
434         ld      a,(bc)
435         inc     bc
436         ld      l,a
437         ld      h,page0
438         jp      (hl)
439
440 page1_imm_gt_uw:
441         ld      a,(bc)
442         ld      l,a
443         inc     bc
444         ld      a,(bc)
445         ld      h,a
446         inc     bc
447         .db     0x3e ; ld a,
448 page1_lt_uw:
449         pop     hl
450         or      a
451         sbc     hl,de
452         ld      a,(bc)
453         inc     bc
454         ld      l,a
455         ld      h,page0
456         jp      (hl)
457
458 page1_imm_sl_w: ; nonzero unsigned byte argument
459         jr      imm_sl_w
460
461 page1_sl_w:
462         pop     hl
463         inc     e
464         jr      sl_loope
465
466 page1_imm_sr_uw: ; nonzero unsigned byte argument
467         jr      imm_sr_uw
468
469 page1_sr_uw:
470         ld      l,e
471         pop     de
472         ld      a,e
473         inc     l
474         jr      srl_loope
475
476 page1_imm_sr_sw: ; nonzero unsigned byte argument
477         jr      imm_sr_sw
478
479 page1_sr_sw:
480         ld      l,e
481         pop     de
482         ld      a,e
483         inc     l
484         jr      sra_loope
485
486 page1_div_sw:
487         pop     hl
488         call    div_sw
489 div_done:
490         push    de
491         ex      de,hl
492         ld      a,(bc)
493         inc     bc
494         ld      l,a
495         ld      h,page1
496         jp      (hl)
497
498 page1_div_uw:
499         ld      l,<div_done
500         ex      (sp),hl
501         jr      div_uw
502
503 page1_imm_div_sw:
504         jr      imm_div_sw
505
506 page1_imm_div_uw:
507         jr      imm_div_uw
508
509 page1_imm_mul_w: ; big endian argument
510         ld      l,mul_done
511         push    hl
512         ld      a,(bc)
513         inc     bc
514         ld      hl,0
515         call    mul0
516         ld      a,(bc)
517         inc     bc
518         jp      mul ; a shame it can't be jr
519
520 page1_mul_w:
521         ld      l,<mul_done
522         ex      (sp),hl
523         jr      mul_w
524
525 page1_imm_gt_sw:
526         ld      a,(bc)
527         ld      l,a
528         inc     bc
529         ld      a,(bc)
530         ld      h,a
531         inc     bc
532         .db     0x3e ; ld a,
533 page1_lt_sw: ; put this at the end because it's the longest one
534         pop     hl
535         ld      a,l
536         sub     e
537         ld      a,h
538         sbc     a,d
539         rla
540         jp      po,1$
541         ccf
542 1$:     ld      a,(bc)
543         inc     bc
544         ld      l,a
545         ld      h,page0
546         jp      (hl)
547
548 ; math package
549
550 imm_sl_w:
551         ex      de,hl
552         ld      a,(bc)
553         inc     bc
554         ld      e,a
555 sl_loop:
556         add     hl,hl
557 sl_loope:
558         dec     e
559         jr      nz,sl_loop
560         ex      de,hl
561         ld      a,(bc)
562         inc     bc
563         ld      l,a
564         ld      h,page1
565         jp      (hl)
566
567 imm_sr_uw:
568         ld      a,(bc)
569         inc     bc
570         ld      l,a
571         ld      a,e
572 srl_loop:
573         srl     d
574         rra
575 srl_loope:
576         dec     l
577         jr      nz,srl_loop
578         ld      e,a
579         ld      a,(bc)
580         inc     bc
581         ld      l,a
582         jp      (hl)
583
584 imm_sr_sw:
585         ld      a,(bc)
586         inc     bc
587         ld      l,a
588         ld      a,e
589 sra_loop:
590         sra     d
591         rra
592 sra_loope:
593         dec     l
594         jr      nz,sra_loop
595         ld      e,a
596         ld      a,(bc)
597         inc     bc
598         ld      l,a
599         jp      (hl)
600
601 imm_div_uw:
602         ld      l,div_done
603         push    hl
604         ld      a,(bc)
605         inc     bc
606         ld      l,a
607         ld      a,(bc)
608         inc     bc
609         ld      h,a
610         ex      de,hl
611 div_uw:
612         push    bc
613         ld      a,h
614         ld      c,l
615         ld      hl,0
616 divpp:  ; positive dividend, positive divisor
617         call    div0
618         ld      b,a
619         ld      a,c
620         call    div
621         jr      nc,1$
622         add     hl,de
623 1$:     ld      d,b
624         ld      e,a
625         pop     bc
626         ret
627
628 imm_div_sw:
629         ld      l,div_done
630         push    hl
631         ld      a,(bc)
632         inc     bc
633         ld      l,a
634         ld      a,(bc)
635         inc     bc
636         ld      h,a
637         ex      de,hl
638 div_sw:
639         push    bc
640         ld      a,h
641         or      a
642         ld      a,d
643         rla
644         jp      p,divp                  ; positive dividend
645
646         ; negative dividend
647         dec     hl                      ; reduces remainder by 1 (we inc later)
648         ld      a,h
649         ld      c,l
650         ld      hl,-1
651         jr      nc,divnp ; a shame it can't be a fallthru
652         jr      divnn                   ; negative dividend, negative divisor
653
654 mul_w:  ; mul placed as soon as possible after all div entry points
655         ld      a,l
656         push    af
657         ld      a,h
658         ld      hl,0
659         call    mul0
660         pop     af
661 mul:    ; bit 0
662         add     hl,hl
663 mul0:   rla
664         jr      nc,1$
665         add     hl,de
666 1$:     ; bit 1
667         add     hl,hl
668         rla
669         jr      nc,2$
670         add     hl,de
671 2$:     ; bit 2
672         add     hl,hl
673         rla
674         jr      nc,3$
675         add     hl,de
676 3$:     ; bit 3
677         add     hl,hl
678         rla
679         jr      nc,4$
680         add     hl,de
681 4$:     ; bit 4
682         add     hl,hl
683         rla
684         jr      nc,5$
685         add     hl,de
686 5$:     ; bit 5
687         add     hl,hl
688         rla
689         jr      nc,6$
690         add     hl,de
691 6$:     ; bit 6
692         add     hl,hl
693         rla
694         jr      nc,7$
695         add     hl,de
696 7$:     ; bit 7
697         add     hl,hl
698         rla
699         ret     nc
700         add     hl,de
701         ret
702
703 divp:   ; positive dividend
704         ld      a,h
705         ld      c,l
706         ld      hl,0
707         jr      nc,divpp                ; positive dividend, positive divisor
708
709         ; positive dividend, negative divisor
710         call    divn1
711         ld      b,a
712         ld      a,c
713         call    divn
714         inc     a
715         jr      c,1$
716         sbc     hl,de
717 1$:     ld      d,b
718         ld      e,a
719         pop     bc
720         ret
721
722 divnp:  ; negative dividend, positive divisor
723         call    div1
724         ld      b,a
725         ld      a,c
726         call    div
727         inc     a
728         jr      c,1$
729         sbc     hl,de
730 1$:     inc     hl                      ; get into range -divisor+1..0
731         ld      d,b
732         ld      e,a
733         pop     bc
734         ret
735
736 divnn:  ; negative dividend, negative divisor
737         call    divn0
738         ld      b,a
739         ld      a,c
740         call    divn
741         jr      nc,1$
742         add     hl,de
743 1$:     inc     hl                      ; get into range divisor+1..0
744         ld      d,b
745         ld      e,a
746         pop     bc
747         ret
748
749 ; non-restoring division routine
750
751 ; de = divisor, hl:a = dividend with hl = previous remainder, a = next byte
752 ; enter at div0 with positive remainder in hl, such that hl < de
753 ; enter at div1 with negative remainder in hl, such that hl >= -de
754
755 ; div0/1 return a = 8-bit quotient as an odd number interpreted as -ff..ff,
756 ; by summing positive/negative place values, e.g. -80 +40 +20 -10 +8 -4 -2 +1
757
758 ; if entered at div0, there is a -80 and so quotient is in range -ff..-1
759 ; if entered at div1, there is a +80 and so quotient is in range 1..ff
760 ; falls out of loop after div01 with positive remainder, div11 with negative,
761 ; depending on this we should re-enter at div0 or div1, signalled by cf return
762
763 ; the successive quotient bytes can be concatenated into a full quotient,
764 ; but negative bytes require the next higher quotient byte to be decremented,
765 ; we know in advance if this will happen because the implied sign of the
766 ; quotient byte depends only on whether we entered at div0 or div1, hence,
767 ; before the div11 return we'll decrement to compensate for next negative byte
768
769 ; the decrement can also be seen as compensating for the extra add hl,de that
770 ; may be needed to make negative remainder positive before return to caller,
771 ; thus leaving quotient in a consistent state regardless of which exit taken,
772 ; remainder needs the add hl,de if cf=1 returned (equiv. return byte is even)
773
774 ; in the following code each sbc hl,de gets an inc a and each add hl,de gets
775 ; a dec a, guaranteeing the integrity of the division, the initial scf/rla is
776 ; needed to make the result 100 + -ff..ff or 1..1ff, so that the decrements
777 ; cannot borrow into the upcoming dividend bits also held in a, and there must
778 ; be another shift between the scf/rla and increment/decrement so that the scf
779 ; is implicitly in the 100s place, making the code awkward though it's correct
780
781 ; now optimized to only inc/dec a when doing zero-crossing, fix above analysis
782
783 div:    jr      c,div1
784 div0:   ; bit 0, above
785         scf
786         rla
787         adc     hl,hl
788         sbc     hl,de
789         jr      nc,div01
790         dec     a
791 div11:  ; bit 1, below
792         add     a,a
793         adc     hl,hl
794         add     hl,de
795         jr      nc,div12
796         inc     a
797 div02:  ; bit 2, above
798         add     a,a
799         adc     hl,hl
800         sbc     hl,de
801         jr      nc,div03
802         dec     a
803 div13:  ; bit 3, below
804         add     a,a
805         adc     hl,hl
806         add     hl,de
807         jr      nc,div14
808         inc     a
809 div04:  ; bit 4, above
810         add     a,a
811         adc     hl,hl
812         sbc     hl,de
813         jr      nc,div05
814         dec     a
815 div15:  ; bit 5, below
816         add     a,a
817         adc     hl,hl
818         add     hl,de
819         jr      nc,div16
820         inc     a
821 div06:  ; bit 6, above
822         add     a,a
823         adc     hl,hl
824         sbc     hl,de
825         jr      nc,div07
826         dec     a
827 div17:  ; bit 7, below
828         add     a,a
829         adc     hl,hl
830         add     hl,de
831         jr      nc,div18
832         inc     a
833 div08:  ; done, above
834         add     a,a
835         dec     a
836         or      a
837         ret
838
839 div1:   ; bit 0, below
840         add     a,a
841         adc     hl,hl
842         add     hl,de
843         jr      nc,div11
844         inc     a
845 div01:  ; bit 1, above
846         add     a,a
847         adc     hl,hl
848         sbc     hl,de
849         jr      nc,div02
850         dec     a
851 div12:  ; bit 2, below
852         add     a,a
853         adc     hl,hl
854         add     hl,de
855         jr      nc,div13
856         inc     a
857 div03:  ; bit 3, above
858         add     a,a
859         adc     hl,hl
860         sbc     hl,de
861         jr      nc,div04
862         dec     a
863 div14:  ; bit 4, below
864         add     a,a
865         adc     hl,hl
866         add     hl,de
867         jr      nc,div15
868         inc     a
869 div05:  ; bit 5, above
870         add     a,a
871         adc     hl,hl
872         sbc     hl,de
873         jr      nc,div06
874         dec     a
875 div16:  ; bit 6, below
876         add     a,a
877         adc     hl,hl
878         add     hl,de
879         jr      nc,div17
880         inc     a
881 div07:  ; bit 7, above
882         add     a,a
883         adc     hl,hl
884         sbc     hl,de
885         jr      nc,div08
886         dec     a
887 div18:  ; done, below
888         add     a,a
889         ;inc    a
890         ;dec    a                       ; compensation
891         scf
892         ret
893
894 ; divn0/1 are the same as div0/1 but carry reversed after add/subtract divisor
895 ; this is for negative divisors where we expect carry (means no zero crossing)
896
897 ; when divisor negated, remainder also negated, so we expect to do subtraction
898 ; when remainder negative and vice versa, need to clear carry after add hl,hl
899
900 divn:   jr      c,divn1
901 divn0:  ; bit 0, above
902         scf
903         rla
904         adc     hl,hl
905         or      a
906         sbc     hl,de
907         jr      c,divn01
908         dec     a
909 divn11: ; bit 1, below
910         add     a,a
911         adc     hl,hl
912         add     hl,de
913         jr      c,divn12
914         inc     a
915 divn02: ; bit 2, above
916         add     a,a
917         adc     hl,hl
918         or      a
919         sbc     hl,de
920         jr      c,divn03
921         dec     a
922 divn13: ; bit 3, below
923         add     a,a
924         adc     hl,hl
925         add     hl,de
926         jr      c,divn14
927         inc     a
928 divn04: ; bit 4, above
929         add     a,a
930         adc     hl,hl
931         or      a
932         sbc     hl,de
933         jr      c,divn05
934         dec     a
935 divn15: ; bit 5, below
936         add     a,a
937         adc     hl,hl
938         add     hl,de
939         jr      c,divn16
940         inc     a
941 divn06: ; bit 6, above
942         add     a,a
943         adc     hl,hl
944         or      a
945         sbc     hl,de
946         jr      c,divn07
947         dec     a
948 divn17: ; bit 7, below
949         add     a,a
950         adc     hl,hl
951         add     hl,de
952         jr      c,divn18
953         inc     a
954 divn08: ; done, above
955         add     a,a
956         dec     a
957         or      a
958         ret
959
960 divn1:  ; bit 0, below
961         add     a,a
962         adc     hl,hl
963         add     hl,de
964         jr      c,divn11
965         inc     a
966 divn01: ; bit 1, above
967         add     a,a
968         adc     hl,hl
969         or      a
970         sbc     hl,de
971         jr      c,divn02
972         dec     a
973 divn12: ; bit 2, below
974         add     a,a
975         adc     hl,hl
976         add     hl,de
977         jr      c,divn13
978         inc     a
979 divn03: ; bit 3, above
980         add     a,a
981         adc     hl,hl
982         or      a
983         sbc     hl,de
984         jr      c,divn04
985         dec     a
986 divn14: ; bit 4, below
987         add     a,a
988         adc     hl,hl
989         add     hl,de
990         jr      c,divn15
991         inc     a
992 divn05: ; bit 5, above
993         add     a,a
994         adc     hl,hl
995         or      a
996         sbc     hl,de
997         jr      c,divn06
998         dec     a
999 divn16: ; bit 6, below
1000         add     a,a
1001         adc     hl,hl
1002         add     hl,de
1003         jr      c,divn17
1004         inc     a
1005 divn07: ; bit 7, above
1006         add     a,a
1007         adc     hl,hl
1008         or      a
1009         sbc     hl,de
1010         jr      c,divn08
1011         dec     a
1012 divn18: ; done, below
1013         add     a,a
1014         ;inc    a
1015         ;dec    a                       ; compensation
1016         scf
1017         ret
1018
1019 ; debugging
1020
1021 print_trace:
1022         ld      l,c
1023         ld      h,b
1024         call    print_word
1025         ld      a,' 
1026         call    print_char
1027         ld      hl,0
1028         push    af
1029         add     hl,sp
1030         pop     af
1031         call    print_word
1032         ld      a,' 
1033         call    print_char
1034         pop     hl
1035         push    hl
1036         call    print_word
1037         ld      a,0xd
1038         call    print_char
1039         ld      a,0xa
1040         call    print_char
1041         ld      a,(bc)
1042         inc     bc
1043         ld      l,a
1044         ld      h,page0
1045         jp      (hl)
1046
1047 print_word:
1048         push    af
1049         ld      a,h
1050         call    print_byte
1051         ld      a,l
1052         call    print_byte
1053         pop     af
1054         ret
1055
1056 print_byte:
1057         push    af
1058         push    af
1059         rrca
1060         rrca
1061         rrca
1062         rrca
1063         call    print_digit
1064         pop     af
1065         call    print_digit
1066         pop     af
1067         ret
1068
1069 print_digit:
1070         push    de
1071         push    hl
1072         and     0xf
1073         ld      e,a
1074         ld      d,0
1075         ld      hl,digits
1076         add     hl,de
1077         ld      a,(hl)
1078         pop     hl
1079         pop     de
1080 print_char:
1081         push    bc
1082         push    de
1083         push    hl
1084         ld      e,a
1085         ld      c,2
1086         call    5
1087         pop     hl
1088         pop     de
1089         pop     bc
1090         ret
1091
1092 digits:
1093         .ascii  '0123456789abcdef'
1094
1095 ; sm code
1096
1097 start:
1098         ld      h,page0
1099         call    page0_jmp
1100         .db     <page0_imm_call
1101         .dw     sm_main
1102         .dw     0
1103         .db     <page0_esc
1104         jp      0
1105
1106 sm_main:
1107         ; create stack frame
1108         .db     <page0_stkadj
1109         .dw     -2
1110
1111         ; push argument
1112         .db     <page0_imm_w
1113         .dw     5
1114
1115         ; push result pointer
1116         .db     <page1_stkptr
1117         .dw     2
1118
1119         ; call sm_factorial(argument)
1120         .db     <page1_imm_call
1121         .dw     sm_factorial
1122         .dw     4
1123
1124         ; print 10000s
1125         .db     <page0_stkld_w
1126         .dw     0
1127         .db     <page1_imm_div_sw
1128         .dw     10000
1129         .db     <page1_stkst_w
1130         .dw     2
1131         .db     <page0_page1
1132         .db     page1_imm_add_w
1133         .dw     '0
1134         .db     <page1_imm_call
1135         .dw     sm_print_char
1136         .dw     2
1137
1138         ; print 1000s
1139         .db     <page0_stkld_w
1140         .dw     0
1141         .db     <page1_imm_div_sw
1142         .dw     1000
1143         .db     <page1_stkst_w
1144         .dw     2
1145         .db     <page0_page1
1146         .db     page1_imm_add_w
1147         .dw     '0
1148         .db     <page1_imm_call
1149         .dw     sm_print_char
1150         .dw     2
1151
1152         ; print 100s
1153         .db     <page0_stkld_w
1154         .dw     0
1155         .db     <page1_imm_div_sw
1156         .dw     100
1157         .db     <page1_stkst_w
1158         .dw     2
1159         .db     <page0_page1
1160         .db     page1_imm_add_w
1161         .dw     '0
1162         .db     <page1_imm_call
1163         .dw     sm_print_char
1164         .dw     2
1165
1166         ; print 10s
1167         .db     <page0_stkld_w
1168         .dw     0
1169         .db     <page1_imm_div_sw
1170         .dw     10
1171         .db     <page1_stkst_w
1172         .dw     2
1173         .db     <page0_page1
1174         .db     page1_imm_add_w
1175         .dw     '0
1176         .db     <page1_imm_call
1177         .dw     sm_print_char
1178         .dw     2
1179
1180         ; print 1s
1181         .db     <page0_stkld_w
1182         .dw     0
1183         .db     page1_imm_add_w
1184         .dw     '0
1185         .db     <page1_imm_call
1186         .dw     sm_print_char
1187         .dw     2
1188
1189         ; print cr
1190         .db     <page0_imm_w
1191         .dw     0xd
1192         .db     <page1_imm_call
1193         .dw     sm_print_char
1194         .dw     2
1195
1196         ; print lf
1197         .db     <page0_imm_w
1198         .dw     0xa
1199         .db     <page1_imm_call
1200         .dw     sm_print_char
1201         .dw     2
1202
1203         ; destroy stack frame
1204         .db     <page0_stkadj
1205         .dw     2
1206
1207         ; return
1208         .db     <page0_ret
1209
1210 sm_factorial:
1211  .db <page0_trace
1212         ; get argument
1213         .db     <page0_stkld_w
1214         .dw     4
1215
1216         ; is argument < 2?
1217         .db     <page1_imm_gt_sw
1218         .dw     1
1219         .db     <page0_imm_jfalse
1220         .dw     1$
1221
1222         ; no, set up for *result =
1223         .db     <page0_stkld_w
1224         .dw     2
1225
1226         ; get argument
1227         .db     <page1_stkld_w
1228         .dw     6
1229
1230         ; subtract 1
1231         .db     <page1_imm_add_w
1232         .dw     -1
1233
1234         ; push result pointer
1235         .db     <page1_stkptr
1236         .dw     0
1237
1238         ; call sm_factorial(argument - 1)
1239         .db     <page1_imm_call
1240         .dw     sm_factorial
1241         .dw     2
1242
1243         ; get argument
1244         .db     <page0_stkld_w
1245         .dw     8
1246
1247         ; multiply
1248         .db     <page1_mul_w
1249
1250         ; set *result = sm_factorial(argument - 1) * argument
1251         .db     <page1_st_w
1252
1253         ; return
1254  .db <page0_trace
1255         .db     <page0_ret
1256
1257 1$:
1258         ; yes, set up for *result =
1259         .db     <page0_stkld_w
1260         .dw     2
1261
1262         ; set *result = 1
1263         .db     page1_imm_w
1264         .dw     1
1265         .db     <page1_st_w
1266
1267         ; return
1268  .db <page0_trace
1269         .db     <page0_ret
1270
1271 sm_print_char:
1272         .db     <page0_esc
1273         ld      hl,2
1274         add     hl,sp
1275         ld      a,(hl)
1276         call    print_char
1277         ld      h,page0
1278         jp      page0_ret