.org page0 * 0x100
-p0_page1:
+ jp start
+
+page0_trace:
+ ld l,c
+ ld h,b
+ call print_word
+ ld a,'
+ call print_char
+ ld hl,0
+ push af
+ add hl,sp
+ pop af
+ call print_word
+ ld a,'
+ call print_char
+ pop hl
+ push hl
+ call print_word
+ ld a,0xd
+ call print_char
+ ld a,0xa
+ call print_char
+ ld a,(bc)
+ inc bc
+ ld l,a
+ ld h,page0
+ jp (hl)
+
+page0_esc:
+ ld l,c
+ ld h,b
+ jp (hl)
+
+page0_page1:
pop de
ld a,(bc)
inc bc
inc h ; page 1
jp (hl)
-p0_imm_call:
+page0_imm_call:
ld a,(bc)
inc bc
ld l,a
ld l,a
jp (hl)
-p0_call:
+page0_call:
pop hl
push bc
ld c,l
ld h,page0
jp (hl)
-p0_imm_jfalse:
- jr nc,p0_imm_jmp
+page0_imm_jfalse:
+ jr nc,page0_imm_jmp
imm_not_taken:
inc bc
inc bc
ld l,a
jp (hl)
-p0_imm_jtrue:
+page0_imm_jtrue:
jr nc,imm_not_taken
-p0_imm_jmp:
+page0_imm_jmp:
ld a,(bc)
inc bc
ld l,a
ld l,a
jp (hl)
-p0_jfalse:
- jr nc,p0_jmp
+page0_jfalse:
+ jr nc,page0_jmp
not_taken:
inc sp
inc sp
ld l,a
jp (hl)
-p0_jtrue:
+page0_jtrue:
jr nc,not_taken
-p0_jmp:
+page0_jmp:
pop bc
ld a,(bc)
inc bc
ld l,a
jp (hl)
- .org page0 * 0x100 + 0x8f
+ .org page0 * 0x100 + 0x83
-p0_imm_stkadj:
+page0_imm_stkadj:
imm_stkadj:
ld a,(bc)
inc bc
inc bc
ld h,a
.db 0x3e ; ld a,
-p0_stkadj:
+page0_stkadj:
pop hl
stkadj:
add hl,sp
ld h,page0
jp (hl)
-p0_imm_stkptr:
+page0_imm_stkptr:
imm_stkptr:
ld a,(bc)
inc bc
inc bc
ld h,a
.db 0x3e ; ld a,
-p0_stkptr:
+page0_stkptr:
pop hl
stkptr:
add hl,sp
ld h,page1
jp (hl)
-p0_imm_stkld_w:
+page0_imm_stkld_w:
imm_stkld_w:
ld a,(bc)
inc bc
inc bc
ld h,a
.db 0x3e ; ld a,
-p0_stkld_w:
+page0_stkld_w:
pop hl
stkld_w:
add hl,sp
ld h,page1
jp (hl)
-p0_imm_stkst_w:
+page0_imm_stkstrev_w:
pop de
-imm_stkst_w:
+imm_stkstrev_w:
ld a,(bc)
inc bc
ld l,a
ld a,(bc)
inc bc
ld h,a
+ add hl,sp
+ ld (hl),e
+ inc hl
+ ld (hl),d
+ ld a,(bc)
+ inc bc
+ ld l,a
+ ld h,page0
+ jp (hl)
+
+page0_stkst_w:
+ pop de
stkst_w:
+ pop hl
add hl,sp
ld (hl),e
inc hl
ld h,page0
jp (hl)
-p0_imm_w:
+page0_imm_w:
inc h ; page1
imm_w:
ld a,(bc)
ld l,a
jp (hl)
-p0_ld_w:
+page0_ld_w:
pop de
inc h ; page1
ld_w:
ld l,a
jp (hl)
-p0_imm_st_w:
+page0_imm_st_w:
pop de
imm_st_w:
ld a,(bc)
ld l,a
jp (hl)
-p0_st_w:
+page0_st_w:
pop de
st_w:
pop hl
.org page1 * 0x100
-p1_page0:
- push de
- ld a,(bc)
- inc bc
- ld l,a
- dec h ; page 0
- jp (hl)
-
-p1_imm_stkadj:
+page1_imm_stkadj:
push de
jr imm_stkadj
-p1_stkadj:
+page1_stkadj:
ex de,hl
jr stkadj
-p1_imm_stkptr:
+page1_imm_stkptr:
push de
jr imm_stkptr
-p1_stkptr:
+page1_stkptr:
ex de,hl
jr stkptr
-p1_imm_stkld_w:
+page1_imm_stkld_w:
push de
jr imm_stkld_w
-p1_stkld_w:
+page1_stkld_w:
ex de,hl
jr stkld_w
-p1_imm_stkst_w:
- jr imm_stkst_w
-p1_stkst_w:
- push de
+page1_imm_stkstrev_w:
+ jr imm_stkstrev_w
+page1_stkst_w:
jr stkst_w
-p1_imm_w:
+page1_imm_w:
+ push de
jr imm_w
-p1_ld_w:
+page1_ld_w:
jr ld_w
-p1_imm_st_w:
+page1_imm_st_w:
dec h ; page0
jr imm_st_w
-p1_st_w:
+page1_st_w:
jr st_w
-p1_imm_and_w:
+page1_page0:
+ push de
+ ld a,(bc)
+ inc bc
+ ld l,a
+ dec h ; page 0
+ jp (hl)
+
+page1_imm_and_w:
ld a,(bc)
inc bc
and e
ld l,a
jp (hl)
-p1_and_w:
+page1_and_w:
pop hl
ld a,e
and l
ld h,page1
jp (hl)
-p1_imm_or_w:
+page1_imm_or_w:
ld a,(bc)
inc bc
or e
ld l,a
jp (hl)
-p1_or_w:
+page1_or_w:
pop hl
ld a,e
or l
ld h,page1
jp (hl)
-;p1_imm_xor_w:
+;page1_imm_xor_w:
; ld a,(bc)
; inc bc
; xor e
; ld l,a
; jp (hl)
-p1_imm_xor_w: ; xor is less common than and/or, so save space for immediate
+page1_imm_xor_w: ; xor is less common than and/or, so save space for immediate
ld a,(bc)
ld l,a
inc bc
ld h,a
inc bc
.db 0x3e ; ld a,
-p1_xor_w:
+page1_xor_w:
pop hl
ld a,e
xor l
ld h,page1
jp (hl)
-p1_imm_add_w: ; use also for p1_imm_sub_w with negated argument
+page1_imm_add_w: ; use also for page1_imm_sub_w with negated argument
ld a,(bc)
ld l,a
inc bc
ld h,a
inc bc
.db 0x3e ; ld a,
-p1_add_w:
+page1_add_w:
pop hl
add hl,de
ex de,hl
ld h,page1
jp (hl)
-p1_imm_subr_w: ; reversed, use with argument 0 for neg, -1 for cpl
+page1_imm_subrev_w: ; reversed, use with argument 0 for neg, -1 for cpl
ld a,(bc)
ld l,a
inc bc
ld h,a
inc bc
.db 0x3e ; ld a,
-p1_sub_w:
+page1_sub_w:
pop hl
or a
sbc hl,de
ld h,page1
jp (hl)
-p1_imm_eq_w:
+page1_imm_eq_w:
ld a,(bc)
ld l,a
inc bc
ld h,a
inc bc
.db 0x3e ; ld a,
-p1_eq_w:
+page1_eq_w:
pop hl
or a
sbc hl,de
ld h,page0
jp (hl)
-p1_imm_gt_uw:
+page1_imm_gt_uw:
ld a,(bc)
ld l,a
inc bc
ld h,a
inc bc
.db 0x3e ; ld a,
-p1_lt_uw:
+page1_lt_uw:
pop hl
or a
sbc hl,de
ld h,page0
jp (hl)
-p1_imm_gt_sw:
- ld a,(bc)
- ld l,a
- inc bc
- ld a,(bc)
- ld h,a
- inc bc
- .db 0x3e ; ld a,
-p1_lt_sw:
- pop hl
- ld a,l
- sub e
- ld a,h
- sbc a,d
- rla
- jp po,1$
- ccf
-1$: ld a,(bc)
- inc bc
- ld l,a
- ld h,page0
- jp (hl)
-
-p1_imm_sl_w: ; nonzero unsigned byte argument
+page1_imm_sl_w: ; nonzero unsigned byte argument
jr imm_sl_w
-p1_sl_w:
+page1_sl_w:
pop hl
inc e
jr sl_loope
-p1_imm_sr_uw: ; nonzero unsigned byte argument
+page1_imm_sr_uw: ; nonzero unsigned byte argument
jr imm_sr_uw
-p1_sr_uw:
+page1_sr_uw:
ld l,e
pop de
ld a,e
inc l
jr srl_loope
-p1_imm_sr_sw: ; nonzero unsigned byte argument
+page1_imm_sr_sw: ; nonzero unsigned byte argument
jr imm_sr_sw
-p1_sr_sw:
+page1_sr_sw:
ld l,e
pop de
ld a,e
inc l
jr sra_loope
-p1_imm_mul_w: ; big endian argument
+page1_div_sw:
+ pop hl
+ call div_sw
+div_done:
+ push de
+ ex de,hl
+ ld a,(bc)
+ inc bc
+ ld l,a
+ ld h,page1
+ jp (hl)
+
+page1_div_uw:
+ ld l,<div_done
+ ex (sp),hl
+ jr div_uw
+
+page1_imm_div_sw:
+ jr imm_div_sw
+
+page1_imm_div_uw:
+ jr imm_div_uw
+
+page1_imm_mul_w: ; big endian argument
ld l,mul_done
push hl
ld a,(bc)
inc bc
ld hl,0
- call mul
+ call mul0
ld a,(bc)
inc bc
- jr mul
+ jp mul ; a shame it can't be jr
-p1_mul_w:
+page1_mul_w:
ld l,<mul_done
ex (sp),hl
jr mul_w
-p1_div_uw:
- ld l,<div_done
- ex (sp),hl
- jr div_uw
-
-p1_div_sw:
- pop hl
- call div_sw
-div_done:
- push de
- ex de,hl
+page1_imm_gt_sw:
+ ld a,(bc)
+ ld l,a
+ inc bc
ld a,(bc)
+ ld h,a
+ inc bc
+ .db 0x3e ; ld a,
+page1_lt_sw: ; put this at the end because it's the longest one
+ pop hl
+ ld a,l
+ sub e
+ ld a,h
+ sbc a,d
+ rla
+ jp po,1$
+ ccf
+1$: ld a,(bc)
inc bc
ld l,a
- ld h,page1
+ ld h,page0
jp (hl)
; math package
ld l,a
jp (hl)
-mul_w:
+imm_div_uw:
+ ld l,div_done
+ push hl
+ ld a,(bc)
+ inc bc
+ ld l,a
+ ld a,(bc)
+ inc bc
+ ld h,a
+ ex de,hl
+div_uw:
+ push bc
+ ld a,h
+ ld c,l
+ ld hl,0
+divpp: ; positive dividend, positive divisor
+ call div0
+ ld b,a
+ ld a,c
+ call div
+ jr nc,1$
+ add hl,de
+1$: ld d,b
+ ld e,a
+ pop bc
+ ret
+
+imm_div_sw:
+ ld l,div_done
+ push hl
+ ld a,(bc)
+ inc bc
+ ld l,a
+ ld a,(bc)
+ inc bc
+ ld h,a
+ ex de,hl
+div_sw:
+ push bc
+ ld a,h
+ or a
+ ld a,d
+ rla
+ jp p,divp ; positive dividend
+
+ ; negative dividend
+ dec hl ; reduces remainder by 1 (we inc later)
+ ld a,h
+ ld c,l
+ ld hl,-1
+ jr nc,divnp ; a shame it can't be a fallthru
+ jr divnn ; negative dividend, negative divisor
+
+mul_w: ; mul placed as soon as possible after all div entry points
ld a,l
push af
ld a,h
ld hl,0
- call mul
+ call mul0
pop af
mul: ; bit 0
add hl,hl
- rla
+mul0: rla
jr nc,1$
add hl,de
1$: ; bit 1
add hl,de
ret
-div_uw:
- push bc
+divp: ; positive dividend
ld a,h
ld c,l
ld hl,0
+ jr nc,divpp ; positive dividend, positive divisor
-divu: ; positive dividend, positive divisor
- call div0
+ ; positive dividend, negative divisor
+ call divn1
ld b,a
ld a,c
- call div
- jr nc,1$
- add hl,de
+ call divn
+ inc a
+ jr c,1$
+ sbc hl,de
1$: ld d,b
ld e,a
pop bc
ret
-div_sw:
- push bc
- ld a,h
- or a
- ld a,d
- rla
- jp p,4$ ; positive dividend
-
- ; negative dividend
- dec hl ; reduces remainder by 1 (we inc later)
- ld a,h
- ld c,l
- ld hl,-1
- jr c,2$ ; negative dividend, negative divisor
-
- ; negative dividend, positive divisor
+divnp: ; negative dividend, positive divisor
call div1
ld b,a
ld a,c
pop bc
ret
-2$: ; negative dividend, negative divisor
+divnn: ; negative dividend, negative divisor
call divn0
ld b,a
ld a,c
call divn
- jr nc,3$
+ jr nc,1$
add hl,de
-3$: inc hl ; get into range divisor+1..0
+1$: inc hl ; get into range divisor+1..0
ld d,b
ld e,a
pop bc
ret
-4$: ; positive dividend
- ld a,h
- ld c,l
- ld hl,0
- jr nc,divu ; positive dividend, positive divisor
-
- ; positive dividend, negative divisor
- call divn1
- ld b,a
- ld a,c
- call divn
- inc a
- jr c,5$
- sbc hl,de
-5$: ld d,b
- ld e,a
- pop bc
- ret
-
; non-restoring division routine
; de = divisor, hl:a = dividend with hl = previous remainder, a = next byte
pop de
pop bc
ret
+
+; sm code
+
+start:
+ ld h,page0
+ call page0_jmp
+ .db <page0_imm_call
+ .dw sm_main
+ .db <page0_esc
+ jp 0
+
+sm_main:
+ ; create stack frame
+ .db <page0_imm_stkadj
+ .dw -2
+
+ ; push argument
+ .db <page0_imm_w
+ .dw 5
+
+ ; push result pointer
+ .db <page1_imm_stkptr
+ .dw 2
+
+ ; call sm_factorial(argument)
+ .db <page1_page0
+ .db <page0_imm_call
+ .dw sm_factorial
+ .db <page0_imm_stkadj
+ .dw 4
+
+ ; print 10000s
+ .db <page0_imm_stkld_w
+ .dw 0
+ .db <page1_imm_div_sw
+ .dw 10000
+ .db <page1_imm_stkstrev_w
+ .dw 2
+ .db <page0_page1
+ .db page1_imm_add_w
+ .dw '0
+ .db <page1_page0
+ .db <page0_imm_call
+ .dw sm_print_char
+ .db <page0_imm_stkadj
+ .dw 2
+
+ ; print 1000s
+ .db <page0_imm_stkld_w
+ .dw 0
+ .db <page1_imm_div_sw
+ .dw 1000
+ .db <page1_imm_stkstrev_w
+ .dw 2
+ .db <page0_page1
+ .db page1_imm_add_w
+ .dw '0
+ .db <page1_page0
+ .db <page0_imm_call
+ .dw sm_print_char
+ .db <page0_imm_stkadj
+ .dw 2
+
+ ; print 100s
+ .db <page0_imm_stkld_w
+ .dw 0
+ .db <page1_imm_div_sw
+ .dw 100
+ .db <page1_imm_stkstrev_w
+ .dw 2
+ .db <page0_page1
+ .db page1_imm_add_w
+ .dw '0
+ .db <page1_page0
+ .db <page0_imm_call
+ .dw sm_print_char
+ .db <page0_imm_stkadj
+ .dw 2
+
+ ; print 10s
+ .db <page0_imm_stkld_w
+ .dw 0
+ .db <page1_imm_div_sw
+ .dw 10
+ .db <page1_imm_stkstrev_w
+ .dw 2
+ .db <page0_page1
+ .db page1_imm_add_w
+ .dw '0
+ .db <page1_page0
+ .db <page0_imm_call
+ .dw sm_print_char
+ .db <page0_imm_stkadj
+ .dw 2
+
+ ; print 1s
+ .db <page0_imm_stkld_w
+ .dw 0
+ .db page1_imm_add_w
+ .dw '0
+ .db <page1_page0
+ .db <page0_imm_call
+ .dw sm_print_char
+ .db <page0_imm_stkadj
+ .dw 2
+
+ ; print cr
+ .db <page0_imm_w
+ .dw 0xd
+ .db <page1_page0
+ .db <page0_imm_call
+ .dw sm_print_char
+ .db <page0_imm_stkadj
+ .dw 2
+
+ ; print lf
+ .db <page0_imm_w
+ .dw 0xa
+ .db <page1_page0
+ .db <page0_imm_call
+ .dw sm_print_char
+ .db <page0_imm_stkadj
+ .dw 2
+
+ ; destroy stack frame
+ .db <page0_imm_stkadj
+ .dw 2
+
+ ; return
+ .db <page0_jmp
+
+sm_factorial:
+ .db <page0_trace
+ ; get argument
+ .db <page0_imm_stkld_w
+ .dw 4
+
+ ; is argument < 2?
+ .db <page1_imm_gt_sw
+ .dw 1
+ .db <page0_imm_jfalse
+ .dw 1$
+
+ ; no, set up for *result =
+ .db <page0_imm_stkld_w
+ .dw 2
+
+ ; get argument
+ .db <page1_imm_stkld_w
+ .dw 6
+
+ ; subtract 1
+ .db <page1_imm_add_w
+ .dw -1
+
+ ; push result pointer
+ .db <page1_imm_stkptr
+ .dw 0
+
+ ; call sm_factorial(argument - 1)
+ .db <page1_page0
+ .db <page0_imm_call
+ .dw sm_factorial
+ .db <page0_imm_stkadj
+ .dw 2
+
+ ; get argument
+ .db <page0_imm_stkld_w
+ .dw 8
+
+ ; multiply
+ .db <page1_mul_w
+
+ ; set *result = sm_factorial(argument - 1) * argument
+ .db <page1_st_w
+
+ ; return
+ .db <page0_trace
+ .db <page0_jmp
+
+1$:
+ ; yes, set up for *result =
+ .db <page0_imm_stkld_w
+ .dw 2
+
+ ; set *result = 1
+ .db page1_imm_w
+ .dw 1
+ .db <page1_st_w
+
+ ; return
+ .db <page0_trace
+ .db <page0_jmp
+
+sm_print_char:
+ .db <page0_esc
+ ld hl,2
+ add hl,sp
+ ld a,(hl)
+ call print_char
+ ld h,page0
+ jp page0_jmp