|
- ; codegen.s - documented scalar instruction emitter (E04-S03).
- ;
- ; The emitter writes into cg_code, a 256-byte RAM buffer. cg_len is the byte
- ; count (0-254); every failure sets cg_err and returns C=1. It does not emit a
- ; whole function yet: parser/codegen integration is E04-S04.
- ;
- ; API:
- ; cg_init
- ; cg_put A = byte
- ; cg_lda_imm A = value
- ; cg_ldx_imm A = value
- ; cg_ora_imm A = value
- ; cg_lda_abs A/X = address
- ; cg_ldx_abs A/X = address
- ; cg_sta_abs A/X = address
- ; cg_stx_abs A/X = address
- ; cg_adc_abs A/X = address
- ; cg_sbc_abs A/X = address
- ; cg_cmp_abs A/X = address
- ; cg_jsr_abs A/X = address
- ; cg_clc, cg_sec, cg_rts
- ; cg_branch_fwd A = branch opcode; emits opcode + placeholder, returns
- ; C=0 and A = fixup index
- ; cg_patch_here A = fixup index; target is the current end of buffer
- ; cg_here returns A = current length
- ;
- ; Only forward relative branches within +0..+127 bytes are accepted. This is
- ; enough for the scalar shapes and gives E04-S04 the checked primitive it
- ; needs for a later long-branch expansion.
-
- .setcpu "6502"
- .include "../common/codegen.inc"
-
- .export cg_init, cg_put, cg_here, cg_branch_fwd, cg_patch_here
- .export cg_lda_imm, cg_ldx_imm, cg_ora_imm, cg_lda_abs, cg_ldx_abs
- .export cg_sta_abs, cg_stx_abs, cg_adc_abs, cg_sbc_abs, cg_cmp_abs
- .export cg_jsr_abs, cg_clc, cg_sec, cg_rts
- .export cg_code, cg_len, cg_err
-
- .segment "CODE"
-
- cg_init:
- lda #$00
- sta cg_len
- sta cg_err
- sta cg_fix_count
- clc
- rts
-
- cg_here:
- lda cg_len
- rts
-
- ; A = byte to append. C=1 on overflow.
- cg_put:
- ldy cg_len
- cpy #CG_MAX
- bcs @full
- sta cg_code,y
- inc cg_len
- clc
- rts
- @full: lda #CG_ERR_FULL
- sta cg_err
- sec
- rts
-
- ; Immediate forms.
- cg_lda_imm:
- pha
- lda #$A9
- jsr cg_put
- bcs @out
- pla
- jmp cg_put
- @out: pla
- sec
- rts
-
- cg_ldx_imm:
- pha
- lda #$A2
- jsr cg_put
- bcs @out
- pla
- jmp cg_put
- @out: pla
- sec
- rts
-
- cg_ora_imm:
- pha
- lda #$09
- jsr cg_put
- bcs @out
- pla
- jmp cg_put
- @out: pla
- sec
- rts
-
- ; Absolute-address forms. Each wrapper supplies the opcode in Y; the shared
- ; routine stores the address before Y is reused by cg_put.
- cg_lda_abs:
- ldy #$AD
- jmp cg_emit_addr
- cg_ldx_abs:
- ldy #$AE
- jmp cg_emit_addr
- cg_sta_abs:
- ldy #$8D
- jmp cg_emit_addr
- cg_stx_abs:
- ldy #$8E
- jmp cg_emit_addr
- cg_adc_abs:
- ldy #$6D
- jmp cg_emit_addr
- cg_sbc_abs:
- ldy #$ED
- jmp cg_emit_addr
- cg_cmp_abs:
- ldy #$CD
- jmp cg_emit_addr
- cg_jsr_abs:
- ldy #$20
- jmp cg_emit_addr
-
- cg_emit_addr:
- sta cg_addr
- stx cg_addr+1
- tya
- jsr cg_put
- bcs @out
- lda cg_addr
- jsr cg_put
- bcs @out
- lda cg_addr+1
- jmp cg_put
- @out: sec
- rts
-
- cg_clc:
- lda #$18
- jmp cg_put
- cg_sec:
- lda #$38
- jmp cg_put
- cg_rts:
- lda #$60
- jmp cg_put
-
- ; A = branch opcode; forward target must be patched later.
- cg_branch_fwd:
- sta cg_op
- lda cg_fix_count
- cmp #CG_FIX_MAX
- bcs @fix_full
- sta cg_idx
- lda cg_op
- jsr cg_put
- bcs @out
- lda cg_len
- sta cg_pos
- ldy cg_idx
- sta cg_fixpos,y
- inc cg_fix_count
- lda #$00
- jsr cg_put
- bcs @out
- lda cg_idx
- clc
- rts
- @fix_full:
- lda #CG_ERR_FIX
- sta cg_err
- sec
- rts
- @out: sec
- rts
-
- ; A = fixup index. Patch its placeholder so the branch targets cg_len.
- cg_patch_here:
- cmp cg_fix_count
- bcs @bad
- tax
- lda cg_len
- sec
- sbc cg_fixpos,x
- sec
- sbc #1
- cmp #128
- bcs @range
- ldy cg_fixpos,x
- sta cg_code,y
- clc
- rts
- @bad: lda #CG_ERR_FIX
- sta cg_err
- sec
- rts
- @range: lda #CG_ERR_RANGE
- sta cg_err
- sec
- rts
-
- .segment "BSS"
- cg_code: .res 256
- cg_len: .res 1
- cg_err: .res 1
- cg_fix_count: .res 1
- cg_fixpos: .res CG_FIX_MAX
- cg_addr: .res 2
- cg_op: .res 1
- cg_idx: .res 1
- cg_pos: .res 1
|