1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-06-26 19:30:00 +00:00

Implemented new interrupt system supporting more platforms and CPUs. Closes #599

This commit is contained in:
jespergravgaard 2020-12-21 01:04:34 +01:00
parent cd6c33a92c
commit 089125ff5e
284 changed files with 6338 additions and 24553 deletions

View File

@ -1,244 +1,4 @@
//KICKC FRAGMENT CACHE 140bf2a915 140bf2c716
//FRAGMENT vbuzz=vbuc1
ldz #{c1}
//FRAGMENT vbuzz_lt_vbuc1_then_la1
cpz #{c1}
bcc {la1}
//FRAGMENT pbuc1_derefidx_vbuzz=vbuzz
tza
tax
sta {c1},x
//FRAGMENT vbuzz=_inc_vbuzz
inz
//FRAGMENT vbsz1=_deref_pbsc1
lda {c1}
sta {z1}
//FRAGMENT vbsz1=_neg_vbsz2
lda {z2}
neg
sta {z1}
//FRAGMENT _deref_pbsc1=vbsz1
lda {z1}
sta {c1}
//FRAGMENT vbsz1=vbsz2_ror_2
lda {z2}
asr
asr
sta {z1}
//FRAGMENT vbsaa=_deref_pbsc1
lda {c1}
//FRAGMENT vbsxx=_deref_pbsc1
ldx {c1}
//FRAGMENT vbsz1=_neg_vbsaa
neg
sta {z1}
//FRAGMENT vbsz1=_neg_vbsxx
txa
neg
sta {z1}
//FRAGMENT vbsz1=_neg_vbsyy
tya
neg
sta {z1}
//FRAGMENT vbsz1=_neg_vbszz
tza
neg
sta {z1}
//FRAGMENT vbsaa=_neg_vbsz1
lda {z1}
neg
//FRAGMENT vbsaa=_neg_vbsaa
neg
//FRAGMENT vbsaa=_neg_vbsxx
txa
neg
//FRAGMENT vbsaa=_neg_vbsyy
tya
neg
//FRAGMENT vbsaa=_neg_vbszz
tza
neg
//FRAGMENT vbsxx=_neg_vbsz1
lda {z1}
neg
tax
//FRAGMENT vbsxx=_neg_vbsaa
neg
tax
//FRAGMENT vbsxx=_neg_vbsxx
txa
neg
tax
//FRAGMENT vbsxx=_neg_vbsyy
tya
neg
tax
//FRAGMENT vbsxx=_neg_vbszz
tza
neg
tax
//FRAGMENT vbsyy=_neg_vbsz1
lda {z1}
neg
tay
//FRAGMENT vbsyy=_neg_vbsaa
neg
tay
//FRAGMENT vbsyy=_neg_vbsxx
txa
neg
tay
//FRAGMENT vbsyy=_neg_vbsyy
tya
neg
tay
//FRAGMENT vbsyy=_neg_vbszz
tza
neg
tay
//FRAGMENT vbszz=_neg_vbsz1
lda {z1}
neg
taz
//FRAGMENT vbszz=_neg_vbsaa
neg
taz
//FRAGMENT vbszz=_neg_vbsxx
txa
neg
taz
//FRAGMENT vbszz=_neg_vbsyy
tya
neg
taz
//FRAGMENT vbszz=_neg_vbszz
tza
neg
taz
//FRAGMENT _deref_pbsc1=vbsaa
sta {c1}
//FRAGMENT vbsz1=vbsaa_ror_2
asr
asr
sta {z1}
//FRAGMENT vbsz1=vbsxx_ror_2
txa
asr
asr
sta {z1}
//FRAGMENT vbsz1=vbsyy_ror_2
tya
asr
asr
sta {z1}
//FRAGMENT vbsz1=vbszz_ror_2
tza
asr
asr
sta {z1}
//FRAGMENT vbsaa=vbsz1_ror_2
lda {z1}
asr
asr
//FRAGMENT vbsaa=vbsaa_ror_2
asr
asr
//FRAGMENT vbsaa=vbsxx_ror_2
txa
asr
asr
//FRAGMENT vbsaa=vbsyy_ror_2
tya
asr
asr
//FRAGMENT vbsaa=vbszz_ror_2
tza
asr
asr
//FRAGMENT vbsxx=vbsz1_ror_2
lda {z1}
asr
asr
tax
//FRAGMENT vbsxx=vbsaa_ror_2
asr
asr
tax
//FRAGMENT vbsxx=vbsxx_ror_2
txa
asr
asr
tax
//FRAGMENT vbsxx=vbsyy_ror_2
tya
asr
asr
tax
//FRAGMENT vbsxx=vbszz_ror_2
tza
asr
asr
tax
//FRAGMENT vbsyy=vbsz1_ror_2
lda {z1}
asr
asr
tay
//FRAGMENT vbsyy=vbsaa_ror_2
asr
asr
tay
//FRAGMENT vbsyy=vbsxx_ror_2
txa
asr
asr
tay
//FRAGMENT vbsyy=vbsyy_ror_2
tya
asr
asr
tay
//FRAGMENT vbsyy=vbszz_ror_2
tza
asr
asr
tay
//FRAGMENT vbszz=vbsz1_ror_2
lda {z1}
asr
asr
taz
//FRAGMENT vbszz=vbsaa_ror_2
asr
asr
taz
//FRAGMENT vbszz=vbsxx_ror_2
txa
asr
asr
taz
//FRAGMENT vbszz=vbsyy_ror_2
tya
asr
asr
taz
//FRAGMENT vbszz=vbszz_ror_2
tza
asr
asr
taz
//FRAGMENT vbsyy=_deref_pbsc1
ldy {c1}
//FRAGMENT vbszz=_deref_pbsc1
lda {c1}
taz
//FRAGMENT _deref_pbsc1=vbsxx
stx {c1}
//FRAGMENT _deref_pbsc1=vbsyy
sty {c1}
//FRAGMENT _deref_pbsc1=vbszz
tza
sta {c1}
//KICKC FRAGMENT CACHE 149935006b 1499351e94
//FRAGMENT vbuz1=vbuc1
lda #{c1}
sta {z1}
@ -324,8 +84,8 @@ inc {z1}+1
inc {z1}
//FRAGMENT pbuz1_derefidx_vbuz2=vbuc1
lda #{c1}
ldy {z2}
sta ({z1}),y
ldz {z2}
sta ({z1}),z
//FRAGMENT vbuz1=_deref_pbuz2
ldy #0
lda ({z2}),y
@ -385,8 +145,8 @@ sta {c1},y
dec {z1}
//FRAGMENT pbuz1_derefidx_vbuz2=vbuz3
lda {z3}
ldy {z2}
sta ({z1}),y
ldz {z2}
sta ({z1}),z
//FRAGMENT vbuz1_neq_vbuc1_then_la1
lda #{c1}
cmp {z1}
@ -719,12 +479,20 @@ sta {c1},y
cmp #{c1}
beq {la1}
//FRAGMENT pbuz1_derefidx_vbuz2=vbuaa
ldy {z2}
sta ({z1}),y
ldz {z2}
sta ({z1}),z
//FRAGMENT pbuz1_derefidx_vbuz2=vbuxx
txa
ldz {z2}
sta ({z1}),z
//FRAGMENT pbuz1_derefidx_vbuz2=vbuyy
tya
ldz {z2}
sta ({z1}),z
//FRAGMENT pbuz1_derefidx_vbuz2=vbuzz
tza
ldz {z2}
sta ({z1}),z
//FRAGMENT vbuaa=_byte_vwuz1
lda {z1}
//FRAGMENT vbuxx=_byte_vwuz1
@ -925,34 +693,6 @@ eor #$ff
sec
adc {z1}
tax
//FRAGMENT vbszz=vbsz1_minus_vbsz2
lda {z1}
sec
sbc {z2}
taz
//FRAGMENT vbszz=vbsz1_minus_vbsaa
eor #$ff
sec
adc {z1}
taz
//FRAGMENT vbszz=vbsz1_minus_vbsxx
txa
eor #$ff
sec
adc {z1}
taz
//FRAGMENT vbszz=vbsz1_minus_vbsyy
tya
eor #$ff
sec
adc {z1}
taz
//FRAGMENT vbszz=vbsz1_minus_vbszz
tza
eor #$ff
sec
adc {z1}
taz
//FRAGMENT vbsz1=vbsxx_minus_vbsz2
txa
sec
@ -1005,32 +745,6 @@ stz $ff
sec
sbc $ff
tax
//FRAGMENT vbszz=vbsxx_minus_vbsz1
txa
sec
sbc {z1}
taz
//FRAGMENT vbszz=vbsxx_minus_vbsaa
sta $ff
txa
sec
sbc $ff
taz
//FRAGMENT vbszz=vbsxx_minus_vbsxx
lda #0
taz
//FRAGMENT vbszz=vbsxx_minus_vbsyy
txa
sty $ff
sec
sbc $ff
taz
//FRAGMENT vbszz=vbsxx_minus_vbszz
txa
stz $ff
sec
sbc $ff
taz
//FRAGMENT vbsz1=vbsyy_minus_vbsz2
tya
sec
@ -1083,32 +797,6 @@ stz $ff
sec
sbc $ff
tax
//FRAGMENT vbszz=vbsyy_minus_vbsz1
tya
sec
sbc {z1}
taz
//FRAGMENT vbszz=vbsyy_minus_vbsaa
sta $ff
tya
sec
sbc $ff
taz
//FRAGMENT vbszz=vbsyy_minus_vbsxx
tya
stx $ff
sec
sbc $ff
taz
//FRAGMENT vbszz=vbsyy_minus_vbsyy
lda #0
taz
//FRAGMENT vbszz=vbsyy_minus_vbszz
tya
stz $ff
sec
sbc $ff
taz
//FRAGMENT vbsz1=vbszz_minus_vbsz2
tza
sec
@ -1165,34 +853,6 @@ tax
tza
lda #0
tax
//FRAGMENT vbszz=vbszz_minus_vbsz1
tza
sec
sbc {z1}
taz
//FRAGMENT vbszz=vbszz_minus_vbsaa
tay
tza
sty $ff
sec
sbc $ff
taz
//FRAGMENT vbszz=vbszz_minus_vbsxx
tza
stx $ff
sec
sbc $ff
taz
//FRAGMENT vbszz=vbszz_minus_vbsyy
tza
sty $ff
sec
sbc $ff
taz
//FRAGMENT vbszz=vbszz_minus_vbszz
tza
lda #0
taz
//FRAGMENT vbsxx_ge_0_then_la1
cpx #0
bpl {la1}
@ -2220,6 +1880,8 @@ cpx {z1}
bcs {la1}
//FRAGMENT vbuxx=vbuc1
ldx #{c1}
//FRAGMENT vbuzz=vbuc1
ldz #{c1}
//FRAGMENT vbuzz=vbuz1
ldz {z1}
//FRAGMENT vbuz1=vbuzz
@ -2234,6 +1896,8 @@ inx
ldy #{c1}
//FRAGMENT vbuyy=_inc_vbuyy
iny
//FRAGMENT vbuzz=_inc_vbuzz
inz
//FRAGMENT vbuz1_ge_vbuxx_then_la1
lda {z1}
stx $ff
@ -2290,6 +1954,9 @@ bcc {la1}
cpy #{c1}
bcc {la1}
beq {la1}
//FRAGMENT vbuzz_lt_vbuc1_then_la1
cpz #{c1}
bcc {la1}
//FRAGMENT vbuzz_le_vbuc1_then_la1
cpz #{c1}
bcc {la1}
@ -2320,17 +1987,9 @@ taz
//FRAGMENT vbuyy_eq_vbuc1_then_la1
cpy #{c1}
beq {la1}
//FRAGMENT pbuz1_derefidx_vbuz2=vbuyy
tya
ldy {z2}
sta ({z1}),y
//FRAGMENT vbuzz_eq_vbuc1_then_la1
cpz #{c1}
beq {la1}
//FRAGMENT pbuz1_derefidx_vbuz2=vbuzz
tza
ldz {z2}
sta ({z1}),z
//FRAGMENT vbuz1_lt_vbuxx_then_la1
cpx {z1}
beq !+
@ -2519,3 +2178,236 @@ sta {z1}+1
asw {z1}
asw {z1}
asw {z1}
//FRAGMENT pbuc1_derefidx_vbuzz=vbuzz
tza
tax
sta {c1},x
//FRAGMENT vbsz1=_deref_pbsc1
lda {c1}
sta {z1}
//FRAGMENT vbsz1=_neg_vbsz2
lda {z2}
neg
sta {z1}
//FRAGMENT _deref_pbsc1=vbsz1
lda {z1}
sta {c1}
//FRAGMENT vbsz1=vbsz2_ror_2
lda {z2}
asr
asr
sta {z1}
//FRAGMENT vbsaa=_deref_pbsc1
lda {c1}
//FRAGMENT vbsxx=_deref_pbsc1
ldx {c1}
//FRAGMENT vbsz1=_neg_vbsaa
neg
sta {z1}
//FRAGMENT vbsz1=_neg_vbsxx
txa
neg
sta {z1}
//FRAGMENT vbsz1=_neg_vbsyy
tya
neg
sta {z1}
//FRAGMENT vbsz1=_neg_vbszz
tza
neg
sta {z1}
//FRAGMENT vbsaa=_neg_vbsz1
lda {z1}
neg
//FRAGMENT vbsaa=_neg_vbsaa
neg
//FRAGMENT vbsaa=_neg_vbsxx
txa
neg
//FRAGMENT vbsaa=_neg_vbsyy
tya
neg
//FRAGMENT vbsaa=_neg_vbszz
tza
neg
//FRAGMENT vbsxx=_neg_vbsz1
lda {z1}
neg
tax
//FRAGMENT vbsxx=_neg_vbsaa
neg
tax
//FRAGMENT vbsxx=_neg_vbsxx
txa
neg
tax
//FRAGMENT vbsxx=_neg_vbsyy
tya
neg
tax
//FRAGMENT vbsxx=_neg_vbszz
tza
neg
tax
//FRAGMENT vbsyy=_neg_vbsz1
lda {z1}
neg
tay
//FRAGMENT vbsyy=_neg_vbsaa
neg
tay
//FRAGMENT vbsyy=_neg_vbsxx
txa
neg
tay
//FRAGMENT vbsyy=_neg_vbsyy
tya
neg
tay
//FRAGMENT vbsyy=_neg_vbszz
tza
neg
tay
//FRAGMENT vbszz=_neg_vbsz1
lda {z1}
neg
taz
//FRAGMENT vbszz=_neg_vbsaa
neg
taz
//FRAGMENT vbszz=_neg_vbsxx
txa
neg
taz
//FRAGMENT vbszz=_neg_vbsyy
tya
neg
taz
//FRAGMENT vbszz=_neg_vbszz
tza
neg
taz
//FRAGMENT _deref_pbsc1=vbsaa
sta {c1}
//FRAGMENT vbsz1=vbsaa_ror_2
asr
asr
sta {z1}
//FRAGMENT vbsz1=vbsxx_ror_2
txa
asr
asr
sta {z1}
//FRAGMENT vbsz1=vbsyy_ror_2
tya
asr
asr
sta {z1}
//FRAGMENT vbsz1=vbszz_ror_2
tza
asr
asr
sta {z1}
//FRAGMENT vbsaa=vbsz1_ror_2
lda {z1}
asr
asr
//FRAGMENT vbsaa=vbsaa_ror_2
asr
asr
//FRAGMENT vbsaa=vbsxx_ror_2
txa
asr
asr
//FRAGMENT vbsaa=vbsyy_ror_2
tya
asr
asr
//FRAGMENT vbsaa=vbszz_ror_2
tza
asr
asr
//FRAGMENT vbsxx=vbsz1_ror_2
lda {z1}
asr
asr
tax
//FRAGMENT vbsxx=vbsaa_ror_2
asr
asr
tax
//FRAGMENT vbsxx=vbsxx_ror_2
txa
asr
asr
tax
//FRAGMENT vbsxx=vbsyy_ror_2
tya
asr
asr
tax
//FRAGMENT vbsxx=vbszz_ror_2
tza
asr
asr
tax
//FRAGMENT vbsyy=vbsz1_ror_2
lda {z1}
asr
asr
tay
//FRAGMENT vbsyy=vbsaa_ror_2
asr
asr
tay
//FRAGMENT vbsyy=vbsxx_ror_2
txa
asr
asr
tay
//FRAGMENT vbsyy=vbsyy_ror_2
tya
asr
asr
tay
//FRAGMENT vbsyy=vbszz_ror_2
tza
asr
asr
tay
//FRAGMENT vbszz=vbsz1_ror_2
lda {z1}
asr
asr
taz
//FRAGMENT vbszz=vbsaa_ror_2
asr
asr
taz
//FRAGMENT vbszz=vbsxx_ror_2
txa
asr
asr
taz
//FRAGMENT vbszz=vbsyy_ror_2
tya
asr
asr
taz
//FRAGMENT vbszz=vbszz_ror_2
tza
asr
asr
taz
//FRAGMENT vbsyy=_deref_pbsc1
ldy {c1}
//FRAGMENT vbszz=_deref_pbsc1
lda {c1}
taz
//FRAGMENT _deref_pbsc1=vbsxx
stx {c1}
//FRAGMENT _deref_pbsc1=vbsyy
sty {c1}
//FRAGMENT _deref_pbsc1=vbszz
tza
sta {c1}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE 140bf2a915 140bf2c716
//KICKC FRAGMENT CACHE 149935006b 1499351e94
//FRAGMENT vbuz1=vbuc1
lda #{c1}
sta {z1}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,273 @@
//KICKC FRAGMENT CACHE 140bf2a915 140bf2c716
//KICKC FRAGMENT CACHE 149935006b 1499351e94
//FRAGMENT vwuz1=vwuc1
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1
//FRAGMENT isr_rom_sys_cx16_entry
//FRAGMENT vwuz1=_inc_vwuz1
inc {z1}
bne !+
inc {z1}+1
!:
//FRAGMENT vwuz1_neq_vbuc1_then_la1
NO_SYNTHESIS
//FRAGMENT vwuz1_neq_vwuc1_then_la1
lda {z1}+1
cmp #>{c1}
bne {la1}
lda {z1}
cmp #<{c1}
bne {la1}
//FRAGMENT vwuz1=vbuc1
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1
//FRAGMENT vwuz1=_dec_vwuz1
lda {z1}
bne !+
dec {z1}+1
!:
dec {z1}
//FRAGMENT vwuz1=vwuz2
lda {z2}
sta {z1}
lda {z2}+1
sta {z1}+1
//FRAGMENT pbuz1=pbuc1
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1
//FRAGMENT vbuz1=vbuc1
lda #{c1}
sta {z1}
//FRAGMENT vbuz1_lt_vbuc1_then_la1
lda {z1}
cmp #{c1}
bcc {la1}
//FRAGMENT _deref_pbuc1=vbuc2
lda #{c2}
sta {c1}
//FRAGMENT isr_rom_sys_cx16_exit
jmp $e034
//FRAGMENT vwuz1=vwuz2_rol_1
lda {z2}
asl
sta {z1}
lda {z2}+1
rol
sta {z1}+1
//FRAGMENT pwuz1=pwuc1_plus_vwuz2
clc
lda {z2}
adc #<{c1}
sta {z1}
lda {z2}+1
adc #>{c1}
sta {z1}+1
//FRAGMENT _deref_pwuc1=_deref_pwuz1
ldy #0
lda ({z1}),y
sta {c1}
iny
lda ({z1}),y
sta {c1}+1
//FRAGMENT pvoz1=pvoz2
lda {z2}
sta {z1}
lda {z2}+1
sta {z1}+1
//FRAGMENT pvoz1=pvoc1
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1
//FRAGMENT pbuz1=pbuz1_plus_vbuc1
lda #{c1}
clc
adc {z1}
sta {z1}
bcc !+
inc {z1}+1
!:
//FRAGMENT vwuz1=vwuz1_plus_vbuc1
lda #{c1}
clc
adc {z1}
sta {z1}
bcc !+
inc {z1}+1
!:
//FRAGMENT vwuz1_lt_vbuc1_then_la1
lda {z1}+1
bne !+
lda {z1}
cmp #{c1}
bcc {la1}
!:
//FRAGMENT vwuz1=vwuz1_minus_vbuc1
sec
lda {z1}
sbc #{c1}
sta {z1}
lda {z1}+1
sbc #0
sta {z1}+1
//FRAGMENT vbuz1=_inc_vbuz1
inc {z1}
//FRAGMENT _deref_pbuc1=_deref_pbuc1_band_vbuc2
lda #{c2}
and {c1}
sta {c1}
//FRAGMENT _deref_pbuc1=_deref_pbuc1_bor_vbuc2
lda #{c2}
ora {c1}
sta {c1}
//FRAGMENT _deref_qprc1=pprc2
lda #<{c2}
sta {c1}
lda #>{c2}
sta {c1}+1
//FRAGMENT _deref_pwuc1=_deref_pwuc1_plus_vbuc2
NO_SYNTHESIS
//FRAGMENT _deref_pwuc1=_deref_pwuc1_plus_vbsc2
NO_SYNTHESIS
//FRAGMENT _deref_pwuc1=_deref_pwuc1_plus_vwuc2
lda #<{c2}
clc
adc {c1}
sta {c1}
lda #>{c2}
adc {c1}+1
sta {c1}+1
//FRAGMENT vbuz1=_lo_pvoz2
lda {z2}
sta {z1}
//FRAGMENT _deref_pbuc1=vbuz1
lda {z1}
sta {c1}
//FRAGMENT vbuz1=_hi_pvoz2
lda {z2}+1
sta {z1}
//FRAGMENT vbuz1=vbuc1_bor_vbuz2
lda #{c1}
ora {z2}
sta {z1}
//FRAGMENT pbuz1=pbuz2_plus_vwuz3
lda {z2}
clc
adc {z3}
sta {z1}
lda {z2}+1
adc {z3}+1
sta {z1}+1
//FRAGMENT pbuz1=pbuz2
lda {z2}
sta {z1}
lda {z2}+1
sta {z1}+1
//FRAGMENT pbuz1_neq_pbuz2_then_la1
lda {z1}+1
cmp {z2}+1
bne {la1}
lda {z1}
cmp {z2}
bne {la1}
//FRAGMENT _deref_pbuc1=_deref_pbuz1
ldy #0
lda ({z1}),y
sta {c1}
//FRAGMENT pbuz1=_inc_pbuz1
inc {z1}
bne !+
inc {z1}+1
!:
//FRAGMENT vbuaa_lt_vbuc1_then_la1
cmp #{c1}
bcc {la1}
//FRAGMENT vbuaa=_lo_pvoz1
lda {z1}
//FRAGMENT vbuxx=_lo_pvoz1
ldx {z1}
//FRAGMENT _deref_pbuc1=vbuaa
sta {c1}
//FRAGMENT vbuaa=_hi_pvoz1
lda {z1}+1
//FRAGMENT vbuxx=_hi_pvoz1
ldx {z1}+1
//FRAGMENT vbuaa=vbuc1_bor_vbuz1
lda #{c1}
ora {z1}
//FRAGMENT vbuxx=vbuc1_bor_vbuz1
lda #{c1}
ora {z1}
tax
//FRAGMENT vbuyy=vbuc1_bor_vbuz1
lda #{c1}
ora {z1}
tay
//FRAGMENT vbuz1=vbuc1_bor_vbuxx
txa
ora #{c1}
sta {z1}
//FRAGMENT vbuaa=vbuc1_bor_vbuxx
txa
ora #{c1}
//FRAGMENT vbuxx=vbuc1_bor_vbuxx
txa
ora #{c1}
tax
//FRAGMENT vbuyy=vbuc1_bor_vbuxx
txa
ora #{c1}
tay
//FRAGMENT vbuz1=vbuc1_bor_vbuyy
tya
ora #{c1}
sta {z1}
//FRAGMENT vbuaa=vbuc1_bor_vbuyy
tya
ora #{c1}
//FRAGMENT vbuxx=vbuc1_bor_vbuyy
tya
ora #{c1}
tax
//FRAGMENT vbuyy=vbuc1_bor_vbuyy
tya
ora #{c1}
tay
//FRAGMENT vbuxx_lt_vbuc1_then_la1
cpx #{c1}
bcc {la1}
//FRAGMENT _deref_pbuc1=vbuxx
stx {c1}
//FRAGMENT vbuyy=_lo_pvoz1
ldy {z1}
//FRAGMENT _deref_pbuc1=vbuyy
sty {c1}
//FRAGMENT vbuyy=_hi_pvoz1
ldy {z1}+1
//FRAGMENT vbuxx=vbuc1
ldx #{c1}
//FRAGMENT pbuz1=pbuz2_plus_vwuz1
lda {z1}
clc
adc {z2}
sta {z1}
lda {z1}+1
adc {z2}+1
sta {z1}+1
//FRAGMENT pwuz1=pwuc1_plus_vwuz1
clc
lda {z1}
adc #<{c1}
sta {z1}
lda {z1}+1
adc #>{c1}
sta {z1}+1
//FRAGMENT vbuz1=_deref_pbuc1
lda {c1}
sta {z1}
@ -6,9 +275,6 @@ sta {z1}
lda {z2}
inc
sta {z1}
//FRAGMENT _deref_pbuc1=vbuz1
lda {z1}
sta {c1}
//FRAGMENT vbuaa=_deref_pbuc1
lda {c1}
//FRAGMENT vbuxx=_deref_pbuc1
@ -19,8 +285,6 @@ sta {z1}
//FRAGMENT vbuz1=vbuxx_plus_1
inx
stx {z1}
//FRAGMENT _deref_pbuc1=vbuaa
sta {c1}
//FRAGMENT vbuyy=_deref_pbuc1
ldy {c1}
//FRAGMENT vbuz1=vbuyy_plus_1
@ -40,8 +304,6 @@ inc
//FRAGMENT vbuxx=vbuz1_plus_1
ldx {z1}
inx
//FRAGMENT _deref_pbuc1=vbuxx
stx {c1}
//FRAGMENT vbuxx=vbuaa_plus_1
tax
inx
@ -54,8 +316,6 @@ tax
//FRAGMENT vbuyy=vbuz1_plus_1
ldy {z1}
iny
//FRAGMENT _deref_pbuc1=vbuyy
sty {c1}
//FRAGMENT vbuyy=vbuaa_plus_1
tay
iny
@ -65,24 +325,92 @@ inc
tay
//FRAGMENT vbuyy=vbuyy_plus_1
iny
//FRAGMENT vbuz1=vbuc1
lda #{c1}
//FRAGMENT 0_neq_pbuc1_derefidx_vbuz1_then_la1
ldy {z1}
lda {c1},y
cmp #0
bne {la1}
//FRAGMENT vbuz1=pbuc1_derefidx_vbuz2
ldy {z2}
lda {c1},y
sta {z1}
//FRAGMENT _deref_pbuc1=_deref_pbuc1_bor_vbuc2
lda #{c2}
ora {c1}
sta {c1}
//FRAGMENT _deref_pbuc1=_deref_pbuc1_band_vbuc2
lda #{c2}
and {c1}
sta {c1}
//FRAGMENT pbuz1=_inc_pbuz2
clc
lda {z2}
adc #1
sta {z1}
lda {z2}+1
adc #0
sta {z1}+1
//FRAGMENT pbuz1_neq_pbuc1_then_la1
lda {z1}+1
cmp #>{c1}
bne {la1}
lda {z1}
cmp #<{c1}
bne {la1}
//FRAGMENT vbuz1=_lo_pbuz2
lda {z2}
sta {z1}
//FRAGMENT vbuz1=_hi_pbuz2
lda {z2}+1
sta {z1}
//FRAGMENT 0_neq_pbuc1_derefidx_vbuaa_then_la1
tay
lda {c1},y
cmp #0
bne {la1}
//FRAGMENT 0_neq_pbuc1_derefidx_vbuxx_then_la1
lda {c1},x
cmp #0
bne {la1}
//FRAGMENT 0_neq_pbuc1_derefidx_vbuyy_then_la1
lda {c1},y
cmp #0
bne {la1}
//FRAGMENT vbuz1=pbuc1_derefidx_vbuxx
lda {c1},x
sta {z1}
//FRAGMENT vbuz1=pbuc1_derefidx_vbuyy
lda {c1},y
sta {z1}
//FRAGMENT vbuaa=pbuc1_derefidx_vbuz1
ldy {z1}
lda {c1},y
//FRAGMENT vbuaa=pbuc1_derefidx_vbuxx
lda {c1},x
//FRAGMENT vbuaa=pbuc1_derefidx_vbuyy
lda {c1},y
//FRAGMENT vbuxx=pbuc1_derefidx_vbuz1
ldy {z1}
ldx {c1},y
//FRAGMENT vbuaa=_lo_pbuz1
lda {z1}
//FRAGMENT vbuxx=_lo_pbuz1
ldx {z1}
//FRAGMENT vbuaa=_hi_pbuz1
lda {z1}+1
//FRAGMENT vbuxx=_hi_pbuz1
ldx {z1}+1
//FRAGMENT vbuyy=_lo_pbuz1
ldy {z1}
//FRAGMENT vbuyy=_hi_pbuz1
ldy {z1}+1
//FRAGMENT vbuyy=pbuc1_derefidx_vbuz1
ldx {z1}
ldy {c1},x
//FRAGMENT vbuyy=vbuc1
ldy #{c1}
//FRAGMENT vbuxx=pbuc1_derefidx_vbuyy
ldx {c1},y
//FRAGMENT vbuyy=_inc_vbuyy
iny
//FRAGMENT isr_rom_min_cx16_entry
//FRAGMENT vbuz1_neq_vbuc1_then_la1
lda #{c1}
cmp {z1}
bne {la1}
//FRAGMENT _deref_pbuc1=vbuc2
lda #{c2}
sta {c1}
//FRAGMENT vbuz1=_dec_vbuz1
dec {z1}
//FRAGMENT vbuz1_neq_0_then_la1
@ -93,64 +421,11 @@ bne {la1}
lda {z1}
cmp #{c1}
bcs {la1}
//FRAGMENT vbuz1=_inc_vbuz1
inc {z1}
//FRAGMENT _deref_pbuc1=pbuc2_derefidx_vbuz1
ldy {z1}
lda {c2},y
sta {c1}
//FRAGMENT vbuz1_lt_vbuc1_then_la1
lda {z1}
cmp #{c1}
bcc {la1}
//FRAGMENT _deref_qprc1=pprc2
lda #<{c2}
sta {c1}
lda #>{c2}
sta {c1}+1
//FRAGMENT vbuaa_neq_vbuc1_then_la1
cmp #{c1}
bne {la1}
//FRAGMENT _deref_pbuc1=pbuc2_derefidx_vbuaa
tay
lda {c2},y
sta {c1}
//FRAGMENT _deref_pbuc1=pbuc2_derefidx_vbuxx
lda {c2},x
sta {c1}
//FRAGMENT _deref_pbuc1=pbuc2_derefidx_vbuyy
lda {c2},y
sta {c1}
//FRAGMENT vbuaa_lt_vbuc1_then_la1
cmp #{c1}
bcc {la1}
//FRAGMENT vbuxx_neq_vbuc1_then_la1
cpx #{c1}
bne {la1}
//FRAGMENT vbuaa=vbuc1
lda #{c1}
//FRAGMENT vbuaa=_inc_vbuaa
inc
//FRAGMENT vbuxx=vbuc1
ldx #{c1}
//FRAGMENT vbuxx_lt_vbuc1_then_la1
cpx #{c1}
bcc {la1}
//FRAGMENT vbuxx=_inc_vbuxx
inx
//FRAGMENT vbuyy=vbuc1
ldy #{c1}
//FRAGMENT vbuyy_lt_vbuc1_then_la1
cpy #{c1}
bcc {la1}
//FRAGMENT vbuyy=_inc_vbuyy
iny
//FRAGMENT vbuyy_neq_vbuc1_then_la1
cpy #{c1}
bne {la1}
//FRAGMENT vbuz1=vbuz2
lda {z2}
sta {z1}
//FRAGMENT isr_rom_min_cx16_exit
jmp $e049
//FRAGMENT pbuz1=pbuc1_plus_pbuc2_derefidx_vbuz2
ldy {z2}
lda {c2},y
@ -169,27 +444,17 @@ sta {z1}
ldy {z2}
lda {c1},y
sta ({z1}),y
//FRAGMENT pbuz1=pbuc1
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1
//FRAGMENT pbuz1_neq_pbuc1_then_la1
lda {z1}+1
cmp #>{c1}
bne {la1}
lda {z1}
cmp #<{c1}
bne {la1}
//FRAGMENT _deref_pbuc1=pbuc2_derefidx_vbuz1
ldy {z1}
lda {c2},y
sta {c1}
//FRAGMENT _deref_pbuz1=vbuc1
lda #{c1}
ldy #0
sta ({z1}),y
//FRAGMENT pbuz1=_inc_pbuz1
inc {z1}
bne !+
inc {z1}+1
!:
//FRAGMENT vbuaa_neq_vbuc1_then_la1
cmp #{c1}
bne {la1}
//FRAGMENT vbuaa=vbuz1
lda {z1}
//FRAGMENT vbuxx=vbuz1
@ -241,232 +506,28 @@ sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuyy=pbuc1_derefidx_vbuyy
lda {c1},y
sta ({z1}),y
//FRAGMENT 0_neq_pbuc1_derefidx_vbuz1_then_la1
ldy {z1}
lda {c1},y
cmp #0
bne {la1}
//FRAGMENT pbuz1=pbuz2
lda {z2}
sta {z1}
lda {z2}+1
sta {z1}+1
//FRAGMENT vbuz1=pbuc1_derefidx_vbuz2
ldy {z2}
lda {c1},y
sta {z1}
//FRAGMENT pbuz1=_inc_pbuz2
clc
lda {z2}
adc #1
sta {z1}
lda {z2}+1
adc #0
sta {z1}+1
//FRAGMENT vbuz1=_lo_pbuz2
lda {z2}
sta {z1}
//FRAGMENT vbuz1=_hi_pbuz2
lda {z2}+1
sta {z1}
//FRAGMENT 0_neq_pbuc1_derefidx_vbuaa_then_la1
//FRAGMENT _deref_pbuc1=pbuc2_derefidx_vbuaa
tay
lda {c1},y
cmp #0
bne {la1}
//FRAGMENT 0_neq_pbuc1_derefidx_vbuxx_then_la1
lda {c1},x
cmp #0
bne {la1}
//FRAGMENT 0_neq_pbuc1_derefidx_vbuyy_then_la1
lda {c1},y
cmp #0
bne {la1}
//FRAGMENT vbuz1=pbuc1_derefidx_vbuxx
lda {c1},x
sta {z1}
//FRAGMENT vbuz1=pbuc1_derefidx_vbuyy
lda {c1},y
sta {z1}
//FRAGMENT vbuaa=pbuc1_derefidx_vbuz1
ldy {z1}
lda {c1},y
//FRAGMENT vbuaa=pbuc1_derefidx_vbuxx
lda {c1},x
//FRAGMENT vbuaa=pbuc1_derefidx_vbuyy
lda {c1},y
//FRAGMENT vbuxx=pbuc1_derefidx_vbuz1
ldy {z1}
ldx {c1},y
//FRAGMENT vbuaa=_lo_pbuz1
lda {z1}
//FRAGMENT vbuxx=_lo_pbuz1
ldx {z1}
//FRAGMENT vbuaa=_hi_pbuz1
lda {z1}+1
//FRAGMENT vbuxx=_hi_pbuz1
ldx {z1}+1
//FRAGMENT vbuyy=_lo_pbuz1
ldy {z1}
//FRAGMENT vbuyy=_hi_pbuz1
ldy {z1}+1
//FRAGMENT vbuyy=pbuc1_derefidx_vbuz1
ldx {z1}
ldy {c1},x
//FRAGMENT vbuxx=pbuc1_derefidx_vbuyy
ldx {c1},y
//FRAGMENT vwuz1=vwuc1
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1
//FRAGMENT vwuz1=_inc_vwuz1
inc {z1}
bne !+
inc {z1}+1
!:
//FRAGMENT vwuz1_neq_vbuc1_then_la1
NO_SYNTHESIS
//FRAGMENT vwuz1_neq_vwuc1_then_la1
lda {z1}+1
cmp #>{c1}
bne {la1}
lda {z1}
cmp #<{c1}
bne {la1}
//FRAGMENT vwuz1=vbuc1
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1
//FRAGMENT vwuz1=_dec_vwuz1
lda {z1}
bne !+
dec {z1}+1
!:
dec {z1}
//FRAGMENT vwuz1=vwuz2_rol_1
lda {z2}
asl
sta {z1}
lda {z2}+1
rol
sta {z1}+1
//FRAGMENT pwuz1=pwuc1_plus_vwuz2
clc
lda {z2}
adc #<{c1}
sta {z1}
lda {z2}+1
adc #>{c1}
sta {z1}+1
//FRAGMENT _deref_pwuc1=_deref_pwuz1
ldy #0
lda ({z1}),y
lda {c2},y
sta {c1}
iny
lda ({z1}),y
sta {c1}+1
//FRAGMENT pvoz1=pvoc1
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1
//FRAGMENT vbuz1=_lo_pvoz2
lda {z2}
sta {z1}
//FRAGMENT vbuz1=_hi_pvoz2
lda {z2}+1
sta {z1}
//FRAGMENT vbuz1=vbuc1_bor_vbuz2
lda #{c1}
ora {z2}
sta {z1}
//FRAGMENT pbuz1=pbuz2_plus_vwuz3
lda {z2}
clc
adc {z3}
sta {z1}
lda {z2}+1
adc {z3}+1
sta {z1}+1
//FRAGMENT pbuz1_neq_pbuz2_then_la1
lda {z1}+1
cmp {z2}+1
bne {la1}
lda {z1}
cmp {z2}
bne {la1}
//FRAGMENT _deref_pbuc1=_deref_pbuz1
ldy #0
lda ({z1}),y
//FRAGMENT _deref_pbuc1=pbuc2_derefidx_vbuxx
lda {c2},x
sta {c1}
//FRAGMENT vbuaa=_lo_pvoz1
lda {z1}
//FRAGMENT vbuxx=_lo_pvoz1
ldx {z1}
//FRAGMENT vbuaa=_hi_pvoz1
lda {z1}+1
//FRAGMENT vbuxx=_hi_pvoz1
ldx {z1}+1
//FRAGMENT vbuaa=vbuc1_bor_vbuz1
//FRAGMENT _deref_pbuc1=pbuc2_derefidx_vbuyy
lda {c2},y
sta {c1}
//FRAGMENT vbuxx_neq_vbuc1_then_la1
cpx #{c1}
bne {la1}
//FRAGMENT vbuxx=_inc_vbuxx
inx
//FRAGMENT vbuyy_lt_vbuc1_then_la1
cpy #{c1}
bcc {la1}
//FRAGMENT vbuaa=vbuc1
lda #{c1}
ora {z1}
//FRAGMENT vbuxx=vbuc1_bor_vbuz1
lda #{c1}
ora {z1}
tax
//FRAGMENT vbuyy=vbuc1_bor_vbuz1
lda #{c1}
ora {z1}
tay
//FRAGMENT vbuz1=vbuc1_bor_vbuxx
txa
ora #{c1}
sta {z1}
//FRAGMENT vbuaa=vbuc1_bor_vbuxx
txa
ora #{c1}
//FRAGMENT vbuxx=vbuc1_bor_vbuxx
txa
ora #{c1}
tax
//FRAGMENT vbuyy=vbuc1_bor_vbuxx
txa
ora #{c1}
tay
//FRAGMENT vbuz1=vbuc1_bor_vbuyy
tya
ora #{c1}
sta {z1}
//FRAGMENT vbuaa=vbuc1_bor_vbuyy
tya
ora #{c1}
//FRAGMENT vbuxx=vbuc1_bor_vbuyy
tya
ora #{c1}
tax
//FRAGMENT vbuyy=vbuc1_bor_vbuyy
tya
ora #{c1}
tay
//FRAGMENT vbuyy=_lo_pvoz1
ldy {z1}
//FRAGMENT vbuyy=_hi_pvoz1
ldy {z1}+1
//FRAGMENT pbuz1=pbuz2_plus_vwuz1
lda {z1}
clc
adc {z2}
sta {z1}
lda {z1}+1
adc {z2}+1
sta {z1}+1
//FRAGMENT pwuz1=pwuc1_plus_vwuz1
clc
lda {z1}
adc #<{c1}
sta {z1}
lda {z1}+1
adc #>{c1}
sta {z1}+1
//FRAGMENT vbuaa=_inc_vbuaa
inc
//FRAGMENT vbuyy_neq_vbuc1_then_la1
cpy #{c1}
bne {la1}

View File

@ -0,0 +1,4 @@
pha
phx
phy
phz

View File

@ -0,0 +1,5 @@
plz
ply
plx
pla
rti

View File

@ -0,0 +1,5 @@
pha
txa
pha
tya
pha

View File

@ -0,0 +1,6 @@
pla
tay
pla
tax
pla
rti

View File

@ -0,0 +1 @@
pha

View File

@ -0,0 +1,2 @@
pla
rti

View File

@ -0,0 +1,3 @@
pha
txa
pha

View File

@ -0,0 +1,4 @@
pla
tax
pla
rti

View File

@ -0,0 +1,3 @@
pha
tya
pha

View File

@ -0,0 +1,4 @@
pla
tay
pla
rti

View File

@ -0,0 +1 @@
rti

View File

@ -0,0 +1 @@
jmp $ea81

View File

@ -0,0 +1 @@
jmp $e049

View File

@ -0,0 +1 @@
jmp $ea31

View File

@ -0,0 +1 @@
jmp $e034

View File

@ -0,0 +1,3 @@
sta rega+1
stx regx+1
sty regy+1

View File

@ -0,0 +1,4 @@
rega: lda #0
regx: ldx #0
regy: ldy #0
rti

View File

@ -0,0 +1,2 @@
sta rega+1
stx regx+1

View File

@ -0,0 +1,3 @@
rega: lda #0
regx: ldx #0
rti

View File

@ -0,0 +1,2 @@
sta rega+1
sty regy+1

View File

@ -0,0 +1,3 @@
rega: lda #0
regy: ldy #0
rti

View File

@ -0,0 +1,2 @@
pha
phx

View File

@ -0,0 +1,3 @@
plx
pla
rti

View File

@ -0,0 +1,2 @@
pha
phy

View File

@ -0,0 +1,3 @@
ply
pla
rti

View File

@ -0,0 +1 @@
phx

View File

@ -0,0 +1,2 @@
plx
rti

View File

@ -0,0 +1,3 @@
pha
phx
phy

View File

@ -0,0 +1,4 @@
ply
plx
pla
rti

View File

@ -176,7 +176,10 @@ public class Compiler {
if(encoding==null)
encoding = StringEncoding.SCREENCODE_MIXED;
Pass0GenerateStatementSequence pass0GenerateStatementSequence = new Pass0GenerateStatementSequence(cParser, cFileContext, program, callingConvention, encoding);
// Find default interrupt type
String interruptType = program.getTargetPlatform().getInterruptType();
Pass0GenerateStatementSequence pass0GenerateStatementSequence = new Pass0GenerateStatementSequence(cParser, cFileContext, program, callingConvention, encoding, interruptType);
pass0GenerateStatementSequence.generate();
pass1GenerateSSA();

View File

@ -156,7 +156,7 @@ public class AsmFragmentInstanceSpec {
SymbolType nextVariationValue = variationIterator.next();
// Find the next name
String variationConstName = "c" + variationCurrentName.substring(variationCurrentName.length() - 1);
String variationNextName = AsmFragmentInstanceSpecFactory.getTypePrefix(nextVariationValue) + variationConstName;
String variationNextName = AsmFragmentInstanceSpecBuilder.getTypePrefix(nextVariationValue) + variationConstName;
// Update bindings
Value constValue = bindings.get(variationCurrentName);
bindings.remove(variationCurrentName);

View File

@ -16,52 +16,107 @@ import dk.camelot64.kickc.model.types.*;
import dk.camelot64.kickc.model.values.*;
import java.lang.InternalError;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* A fragment specification generated from a {@link Statement} used to load/synthesize an {@link AsmFragmentInstance} for creating ASM code for the statement
*/
public class AsmFragmentInstanceSpecFactory {
public class AsmFragmentInstanceSpecBuilder {
/**
* The symbol table.
*/
private Program program;
private final Program program;
/**
* Binding of named values in the fragment to values (constants, variables, ...) .
*/
private Map<String, Value> bindings;
private final Map<String, Value> bindings;
/**
* The created ASM fragment instance specification
*/
private AsmFragmentInstanceSpec asmFragmentInstanceSpec;
private final AsmFragmentInstanceSpec asmFragmentInstanceSpec;
/** Indexing for zeropages/constants/labels */
private int nextZpIdx = 1;
private int nextMemIdx = 1;
private int nextConstIdx = 1;
private int nextLabelIdx = 1;
public Map<String, Value> getBindings() {
return bindings;
/**
* Create a fragment instance spec factory for an interrupt routine (entry or exit)
*
* @param interruptTypeComplete The interrupt routine handler name - including "isr_" and "_entry"/_exit"
* @param program The program
* @return the fragment instance spec factory
*/
public static AsmFragmentInstanceSpecBuilder interrupt(String interruptTypeComplete, Program program) {
Map<String, Value> bindings = new HashMap<>();
String signature = interruptTypeComplete;
ScopeRef codeScope = program.getScope().getRef();
final AsmFragmentInstanceSpec fragmentInstanceSpec = new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
return new AsmFragmentInstanceSpecBuilder(program, bindings, fragmentInstanceSpec);
}
public AsmFragmentInstanceSpecFactory(
/**
* Create a fragment instance spec factory for an interrupt routine entry
*
* @param interruptType The interrupt routine handle name
* @param program The program
* @return the fragment instance spec factory
*/
public static AsmFragmentInstanceSpecBuilder interruptEntry(String interruptType, Program program) {
Map<String, Value> bindings = new HashMap<>();
String signature = "isr_" + interruptType + "_entry";
ScopeRef codeScope = program.getScope().getRef();
final AsmFragmentInstanceSpec fragmentInstanceSpec = new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
return new AsmFragmentInstanceSpecBuilder(program, bindings, fragmentInstanceSpec);
}
/**
* Create a fragment instance spec factory for an interrupt routine exit
*
* @param interruptType The interrupt routine handle name
* @param program The program
* @return the fragment instance spec factory
*/
public static AsmFragmentInstanceSpecBuilder interruptExit(String interruptType, Program program) {
Map<String, Value> bindings = new HashMap<>();
String signature = "isr_" + interruptType + "_exit";
ScopeRef codeScope = program.getScope().getRef();
final AsmFragmentInstanceSpec fragmentInstanceSpec = new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
return new AsmFragmentInstanceSpecBuilder(program, bindings, fragmentInstanceSpec);
}
private AsmFragmentInstanceSpecBuilder(Program program, Map<String, Value> bindings, AsmFragmentInstanceSpec asmFragmentInstanceSpec) {
this.program = program;
this.bindings = bindings;
this.asmFragmentInstanceSpec = asmFragmentInstanceSpec;
}
public static AsmFragmentInstanceSpecBuilder conditionalJump(StatementConditionalJump conditionalJump, ControlFlowBlock block, Program program) {
return new AsmFragmentInstanceSpecBuilder(conditionalJump, block, program);
}
private AsmFragmentInstanceSpecBuilder(
StatementConditionalJump conditionalJump,
ControlFlowBlock block,
Program program,
ControlFlowGraph graph) {
Program program) {
this.program = program;
this.bindings = new LinkedHashMap<>();
ScopeRef codeScope = program.getStatementInfos().getBlock(conditionalJump).getScope();
String signature = conditionalJumpSignature(conditionalJump, block, graph);
String signature = conditionalJumpSignature(conditionalJump, block, program.getGraph());
this.asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
}
public AsmFragmentInstanceSpecFactory(StatementExprSideEffect exprSideEffect, Program program) {
public static AsmFragmentInstanceSpecBuilder exprSideEffect(StatementExprSideEffect exprSideEffect, Program program) {
return new AsmFragmentInstanceSpecBuilder(exprSideEffect, program);
}
private AsmFragmentInstanceSpecBuilder(StatementExprSideEffect exprSideEffect, Program program) {
this.program = program;
this.bindings = new LinkedHashMap<>();
ScopeRef codeScope = program.getStatementInfos().getBlock(exprSideEffect).getScope();
@ -69,7 +124,11 @@ public class AsmFragmentInstanceSpecFactory {
this.asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
}
public AsmFragmentInstanceSpecFactory(StatementAssignment assignment, Program program) {
public static AsmFragmentInstanceSpecBuilder assignment(StatementAssignment assignment, Program program) {
return new AsmFragmentInstanceSpecBuilder(assignment, program);
}
private AsmFragmentInstanceSpecBuilder(StatementAssignment assignment, Program program) {
this.program = program;
this.bindings = new LinkedHashMap<>();
ScopeRef codeScope = program.getStatementInfos().getBlock(assignment).getScope();
@ -81,14 +140,22 @@ public class AsmFragmentInstanceSpecFactory {
this.asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
}
public AsmFragmentInstanceSpecFactory(LValue lValue, RValue rValue, Program program, ScopeRef codeScopeRef) {
public static AsmFragmentInstanceSpecBuilder assignment(LValue lValue, RValue rValue, Program program, ScopeRef codeScopeRef) {
return new AsmFragmentInstanceSpecBuilder(lValue, rValue, program, codeScopeRef);
}
private AsmFragmentInstanceSpecBuilder(LValue lValue, RValue rValue, Program program, ScopeRef codeScopeRef) {
this.program = program;
this.bindings = new LinkedHashMap<>();
String signature = assignmentSignature(lValue, null, null, rValue);
this.asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(program, signature, bindings, codeScopeRef);
}
public AsmFragmentInstanceSpecFactory(StatementAssignment assignment, StatementAssignment assignmentAlu, Program program) {
public static AsmFragmentInstanceSpecBuilder assignmentAlu(StatementAssignment assignment, StatementAssignment assignmentAlu, Program program) {
return new AsmFragmentInstanceSpecBuilder(assignment, assignmentAlu, program);
}
private AsmFragmentInstanceSpecBuilder(StatementAssignment assignment, StatementAssignment assignmentAlu, Program program) {
this.program = program;
this.bindings = new LinkedHashMap<>();
ScopeRef codeScope = program.getStatementInfos().getBlock(assignment).getScope();
@ -96,6 +163,10 @@ public class AsmFragmentInstanceSpecFactory {
this.asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
}
public Map<String, Value> getBindings() {
return bindings;
}
/**
* Get the created ASM fragment instance specification
*
@ -495,7 +566,7 @@ public class AsmFragmentInstanceSpecFactory {
if(Registers.RegisterType.ZP_MEM.equals(register.getType())) {
// Examine if the ZP register is already bound
Registers.RegisterZpMem registerZp = (Registers.RegisterZpMem) register;
String zpNameIdx = null;
String memNameIdx = null;
for(String boundName : bindings.keySet()) {
Value boundValue = bindings.get(boundName);
if(boundValue instanceof Variable && ((Variable) boundValue).isVariable()) {
@ -505,17 +576,17 @@ public class AsmFragmentInstanceSpecFactory {
Registers.RegisterZpMem boundRegisterZp = (Registers.RegisterZpMem) boundRegister;
if(registerZp.getZp() == boundRegisterZp.getZp()) {
// Found other register with same ZP address!
zpNameIdx = boundName.substring(boundName.length() - 1);
memNameIdx = boundName.substring(boundName.length() - 1);
break;
}
}
}
}
// If not create a new one
if(zpNameIdx == null) {
zpNameIdx = Integer.toString(nextZpIdx++);
if(memNameIdx == null) {
memNameIdx = Integer.toString(nextMemIdx++);
}
return "z" + zpNameIdx;
return "z" + memNameIdx;
} else if(Registers.RegisterType.MAIN_MEM.equals(register.getType())) {
String memNameIdx = null;
for(String boundName : bindings.keySet()) {
@ -532,7 +603,7 @@ public class AsmFragmentInstanceSpecFactory {
}
}
if(memNameIdx == null) {
memNameIdx = Integer.toString(nextZpIdx++);
memNameIdx = Integer.toString(nextMemIdx++);
}
return "m" + memNameIdx;
} else if(Registers.RegisterType.REG_A.equals(register.getType())) {
@ -564,5 +635,4 @@ public class AsmFragmentInstanceSpecFactory {
return "c" + nextConstIdx++;
}
}
}

View File

@ -111,8 +111,8 @@ public class AsmFragmentTemplateSynthesizer {
double minScore = Double.MAX_VALUE;
for(AsmFragmentTemplate candidateTemplate : candidates) {
double score = candidateTemplate.getCycles();
if(candidateTemplate.getClobber().isClobberZ()) score += 0.25;
if(candidateTemplate.getClobber().isClobberA()) score += 0.5;
if(candidateTemplate.getClobber().isClobberZ()) score += 1.0;
if(candidateTemplate.getClobber().isClobberY()) score += 1.0;
if(candidateTemplate.getClobber().isClobberX()) score += 1.5;
if(score < minScore) {
@ -531,7 +531,6 @@ public class AsmFragmentTemplateSynthesizer {
} else {
CharStream fragmentCharStream = CharStreams.fromStream(fragmentStream);
body = fixNewlines(fragmentCharStream.toString());
}
return new AsmFragmentTemplate(signature, body, targetCpu, false);
} catch(IOException e) {

View File

@ -103,10 +103,10 @@ public class Directive {
/** Function declared interrupt. */
public static class Interrupt extends Directive {
public Procedure.InterruptType interruptType;
public String interruptType;
public Interrupt(Procedure.InterruptType interruptType) {
super(interruptType.name());
public Interrupt(String interruptType) {
super(interruptType);
this.interruptType = interruptType;
}
}

View File

@ -49,6 +49,9 @@ public class TargetPlatform {
/** Configuration for the variable builder. */
private VariableBuilderConfig variableBuilderConfig;
/** Default interrupt type. */
private String interruptType = "hardware_all";
public TargetPlatform(String name) {
this.name = name;
@ -151,4 +154,11 @@ public class TargetPlatform {
this.encoding = encoding;
}
public void setInterruptType(String interruptType) {
this.interruptType = interruptType;
}
public String getInterruptType() {
return interruptType;
}
}

View File

@ -23,7 +23,7 @@ public class Procedure extends Scope {
/** True if the procedure is declared intrinsic. */
private boolean declaredIntrinsic;
/** The type of interrupt that the procedure serves. Null for all procedures not serving an interrupt. */
private InterruptType interruptType;
private String interruptType;
/** Comments preceding the procedure in the source code. */
private List<Comment> comments;
/** Reserved zeropage addresses. */
@ -176,11 +176,11 @@ public class Procedure extends Scope {
this.declaredInline = declaredInline;
}
public InterruptType getInterruptType() {
public String getInterruptType() {
return interruptType;
}
public void setInterruptType(InterruptType interruptType) {
public void setInterruptType(String interruptType) {
this.interruptType = interruptType;
}
@ -218,26 +218,6 @@ public class Procedure extends Scope {
isConstructor = constructor;
}
/** The different types of supported interrupts. */
public enum InterruptType {
/** Interrupt served by the kernel called through $0314-5. Will exit through the kernel using $ea31. */
KERNEL_KEYBOARD,
/** Interrupt served by the kernel called through $0314-5. Will exit through the kernel using $ea81. */
KERNEL_MIN,
/** Interrupt served directly from hardware through $fffe-f. Will exit through RTI and will save NO registers. */
HARDWARE_NONE,
/** Interrupt served directly from hardware through $fffe-f. Will exit through RTI and will save ALL registers. */
HARDWARE_ALL,
/** Interrupt served directly from hardware through $fffe-f. Will exit through RTI and will save ALL registers using the stack. */
HARDWARE_STACK,
/** Interrupt served directly from hardware through $fffe-f. Will exit through RTI and will save necessary registers based on clobber. */
HARDWARE_CLOBBER;
/** The default interrupt type if none is explicitly declared (KERNEL_MIN). */
public static InterruptType DEFAULT = InterruptType.KERNEL_MIN;
}
@Override
public String toString() {
return toString(null);
@ -256,7 +236,7 @@ public class Procedure extends Scope {
res.append(getCallingConvention().getName()).append(" ");
}
if(interruptType != null) {
res.append("interrupt(").append(interruptType).append(") ");
res.append("__interrupt(").append(interruptType).append(") ");
}
res.append(returnType.getTypeName()).append(" ").append(getFullName()).append("(");
boolean first = true;
@ -287,7 +267,7 @@ public class Procedure extends Scope {
return declaredInline == procedure.declaredInline &&
Objects.equals(returnType, procedure.returnType) &&
Objects.equals(parameterNames, procedure.parameterNames) &&
interruptType == procedure.interruptType &&
Objects.equals(interruptType, procedure.interruptType) &&
Objects.equals(comments, procedure.comments) &&
Objects.equals(reservedZps, procedure.reservedZps) &&
Objects.equals(codeSegment, procedure.codeSegment) &&

View File

@ -43,6 +43,7 @@ public class CParser {
public static final String PRAGMA_CALLING = "calling";
public static final String PRAGMA_ZP_RESERVE = "zp_reserve";
public static final String PRAGMA_CONSTRUCTOR_FOR = "constructor_for";
public static final String PRAGMA_INTERRUPT = "interrupt";
/** The Program. */
private Program program;

View File

@ -33,6 +33,11 @@ public class CTargetPlatformParser {
final JsonReader jsonReader = Json.createReader(new BufferedInputStream(new FileInputStream(platformFile)));
final JsonObject platformJson = jsonReader.readObject();
TargetPlatform targetPlatform = new TargetPlatform(platformName);
{
final String interruptType = platformJson.getString("interrupt", null);
if(interruptType != null)
targetPlatform.setInterruptType(interruptType);
}
{
final String cpuName = platformJson.getString("cpu", null);
if(cpuName != null)

View File

@ -69,7 +69,7 @@ ALIGN: 'align' ;
INLINE: 'inline' ;
VOLATILE: 'volatile' ;
STATIC: 'static' ;
INTERRUPT: 'interrupt' ;
INTERRUPT: '__interrupt' ;
REGISTER: 'register' ;
LOCAL_RESERVE: '__zp_reserve' ;
ADDRESS: '__address' ;

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -178,7 +178,7 @@ IMPORT_COMMENT_BLOCK=153
'inline'=44
'volatile'=45
'static'=46
'interrupt'=47
'__interrupt'=47
'register'=48
'__zp_reserve'=49
'__address'=50

View File

@ -46,7 +46,7 @@ null
'inline'
'volatile'
'static'
'interrupt'
'__interrupt'
'register'
'__zp_reserve'
'__address'

View File

@ -84,7 +84,7 @@ public class KickCParser extends Parser {
"'--'", "'&'", "'~'", "'^'", "'|'", null, null, "'=='", "'!='", null,
"'<='", "'>='", null, "'&&'", "'||'", "'='", null, "'typedef'", "'const'",
"'extern'", "'export'", "'align'", "'inline'", "'volatile'", "'static'",
"'interrupt'", "'register'", "'__zp_reserve'", "'__address'", "'__zp'",
"'__interrupt'", "'register'", "'__zp_reserve'", "'__address'", "'__zp'",
"'__mem'", "'__ssa'", "'__ma'", "'__intrinsic'", null, "'if'", "'else'",
"'while'", "'do'", "'for'", "'switch'", "'return'", "'break'", "'continue'",
"'asm'", "'default'", "'case'", "'struct'", "'enum'", "'sizeof'", "'typeid'",

View File

@ -178,7 +178,7 @@ IMPORT_COMMENT_BLOCK=153
'inline'=44
'volatile'=45
'static'=46
'interrupt'=47
'__interrupt'=47
'register'=48
'__zp_reserve'=49
'__address'=50

View File

@ -34,27 +34,26 @@ import java.util.stream.Collectors;
public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Object> {
/** The C parser keeping track of C-files and lexers */
private CParser cParser;
private final CParser cParser;
/** The source ANTLR parse tree of the source file. */
private KickCParser.FileContext fileCtx;
private final KickCParser.FileContext fileCtx;
/** The program containing all compile structures. */
private Program program;
private final Program program;
/** Used to build the scopes of the source file. */
private Stack<Scope> scopeStack;
/** The memory area used by default for variables. */
private Variable.MemoryArea defaultMemoryArea;
private final Stack<Scope> scopeStack;
/** All #pragma constructor_for() statements. Collected during parsing and handled by {@link #generate()} before returning. */
private List<KickCParser.PragmaContext> pragmaConstructorFors;
private final List<KickCParser.PragmaContext> pragmaConstructorFors;
public Pass0GenerateStatementSequence(CParser cParser, KickCParser.FileContext fileCtx, Program program, Procedure.CallingConvention initialCallingConvention, StringEncoding defaultEncoding) {
public Pass0GenerateStatementSequence(CParser cParser, KickCParser.FileContext fileCtx, Program program, Procedure.CallingConvention initialCallingConvention, StringEncoding defaultEncoding, String defaultInterruptType) {
this.cParser = cParser;
this.fileCtx = fileCtx;
this.program = program;
this.scopeStack = new Stack<>();
this.defaultMemoryArea = Variable.MemoryArea.ZEROPAGE_MEMORY;
this.currentCallingConvention = initialCallingConvention;
this.currentEncoding = defaultEncoding;
this.pragmaConstructorFors = new ArrayList();
this.currentInterruptType = defaultInterruptType;
scopeStack.push(program.getScope());
}
@ -250,6 +249,9 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
case CParser.PRAGMA_CALLING:
currentCallingConvention = pragmaParamCallingConvention(pragmaParamSingle(ctx));
break;
case CParser.PRAGMA_INTERRUPT:
this.currentInterruptType = pragmaParamName(pragmaParamSingle(ctx));
break;
case CParser.PRAGMA_ZP_RESERVE:
List<Integer> reservedZps = pragmaParamRanges(ctx.pragmaParam());
program.addReservedZps(reservedZps);
@ -372,12 +374,15 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
/** The current calling convention for procedures. */
private Procedure.CallingConvention currentCallingConvention;
/** The current code segment - if null the default segment is used. */
/** The current code segment. */
private String currentCodeSegment = Scope.SEGMENT_CODE_DEFAULT;
/** The current data segment - if null the default segment is used. */
/** The current data segment. */
private String currentDataSegment = Scope.SEGMENT_DATA_DEFAULT;
/** The current default interrupt type. */
private String currentInterruptType;
@Override
public Object visitDeclFunction(KickCParser.DeclFunctionContext ctx) {
this.visit(ctx.declType());
@ -1215,13 +1220,11 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
public Object visitDirectiveInterrupt(KickCParser.DirectiveInterruptContext ctx) {
String interruptType;
if(ctx.getChildCount() > 1) {
interruptType = ctx.getChild(2).getText().toUpperCase(Locale.ENGLISH);
interruptType = ctx.getChild(2).getText().toLowerCase(Locale.ENGLISH);
} else {
// The default interrupt type
interruptType = Procedure.InterruptType.DEFAULT.name();
interruptType = currentInterruptType;
}
Procedure.InterruptType type = Procedure.InterruptType.valueOf(interruptType);
return new Directive.Interrupt(type);
return new Directive.Interrupt(interruptType);
}
@Override
@ -1435,7 +1438,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
}
/** The loops being generated. */
private Stack<Loop> loopStack = new Stack<>();
private final Stack<Loop> loopStack = new Stack<>();
@Override
public Void visitStmtWhile(KickCParser.StmtWhileContext ctx) {

View File

@ -32,14 +32,14 @@ public class Pass4CodeGeneration {
boolean warnFragmentMissing;
/** The program being generated. */
private Program program;
private final Program program;
/**
* Keeps track of the phi transitions into blocks during code generation.
* Used to ensure that duplicate transitions are only code generated once.
* Maps to-blocks to the transition information for the block
*/
private Map<PhiTransitions.PhiTransition, Boolean> transitionsGenerated = new LinkedHashMap<>();
private final Map<PhiTransitions.PhiTransition, Boolean> transitionsGenerated = new LinkedHashMap<>();
/**
* Determines if a phi-transition has already been code-generated
@ -97,7 +97,7 @@ public class Pass4CodeGeneration {
String entryName = program.getStartProcedure().getFullName();
linkScriptBody = linkScriptBody.replace("%E", entryName);
Number startAddress = program.getTargetPlatform().getStartAddress();
if(startAddress!=null)
if(startAddress != null)
linkScriptBody = linkScriptBody.replace("%P", AsmFormat.getAsmNumber(startAddress));
asm.addLine(new AsmInlineKickAsm(linkScriptBody, 0L, 0L));
@ -181,7 +181,7 @@ public class Pass4CodeGeneration {
// Name of the current data segment
private String currentCodeSegmentName = Scope.SEGMENT_CODE_DEFAULT;
// Name of the current code segment
private String currentDataSegmentName = Scope.SEGMENT_DATA_DEFAULT;
private final String currentDataSegmentName = Scope.SEGMENT_DATA_DEFAULT;
// Name of the current active segment
private String currentSegmentName = "";
@ -751,13 +751,13 @@ public class Pass4CodeGeneration {
}
}
} else if(value instanceof ConstantString) {
ConstantString stringValue = (ConstantString) value;
// Ensure encoding is good
String asmConstant = AsmFormat.getAsmConstant(program, stringValue, 99, scopeRef);
dataChunk.addDataString(asmConstant, getEncoding(stringValue));
if(stringValue.isZeroTerminated()) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, "0", null);
}
ConstantString stringValue = (ConstantString) value;
// Ensure encoding is good
String asmConstant = AsmFormat.getAsmConstant(program, stringValue, 99, scopeRef);
dataChunk.addDataString(asmConstant, getEncoding(stringValue));
if(stringValue.isZeroTerminated()) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, "0", null);
}
} else if(SymbolType.BYTE.equals(valueType) || SymbolType.SBYTE.equals(valueType)) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value));
} else if(SymbolType.WORD.equals(valueType) || SymbolType.SWORD.equals(valueType)) {
@ -838,9 +838,9 @@ public class Pass4CodeGeneration {
throw new AsmFragmentInstance.AluNotApplicableException();
}
StatementAssignment assignment = (StatementAssignment) statement;
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(assignment, assignmentAlu, program);
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
AsmFragmentInstanceSpecBuilder asmFragmentInstanceSpecBuilder = AsmFragmentInstanceSpecBuilder.assignmentAlu(assignment, assignmentAlu, program);
ensureEncoding(asm, asmFragmentInstanceSpecBuilder);
generateAsm(asm, asmFragmentInstanceSpecBuilder.getAsmFragmentInstanceSpec());
aluState.clear();
return;
}
@ -855,8 +855,7 @@ public class Pass4CodeGeneration {
Registers.Register lValRegister = program.getSymbolInfos().getVariable(lValueRef).getAllocation();
if(lValRegister.getType().equals(Registers.RegisterType.REG_ALU)) {
//asm.addComment(statement + " // ALU");
StatementAssignment assignmentAlu = assignment;
aluState.setAluAssignment(assignmentAlu);
aluState.setAluAssignment(assignment);
isAlu = true;
}
}
@ -864,15 +863,15 @@ public class Pass4CodeGeneration {
if(assignment.getOperator() == null && assignment.getrValue1() == null && isRegisterCopy(lValue, assignment.getrValue2())) {
//asm.addComment(lValue.toString(program) + " = " + assignment.getrValue2().toString(program) + " // register copy " + getRegister(lValue));
} else {
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(assignment, program);
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
AsmFragmentInstanceSpecBuilder asmFragmentInstanceSpecBuilder = AsmFragmentInstanceSpecBuilder.assignment(assignment, program);
ensureEncoding(asm, asmFragmentInstanceSpecBuilder);
generateAsm(asm, asmFragmentInstanceSpecBuilder.getAsmFragmentInstanceSpec());
}
}
} else if(statement instanceof StatementConditionalJump) {
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory((StatementConditionalJump) statement, block, program, getGraph());
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
AsmFragmentInstanceSpecBuilder asmFragmentInstanceSpecBuilder = AsmFragmentInstanceSpecBuilder.conditionalJump((StatementConditionalJump) statement, block, program);
ensureEncoding(asm, asmFragmentInstanceSpecBuilder);
generateAsm(asm, asmFragmentInstanceSpecBuilder.getAsmFragmentInstanceSpec());
} else if(statement instanceof StatementCall) {
StatementCall call = (StatementCall) statement;
Procedure procedure = getScope().getProcedure(call.getProcedure());
@ -895,9 +894,9 @@ public class Pass4CodeGeneration {
asm.getCurrentChunk().setFragment("jsr");
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
} else if(statement instanceof StatementExprSideEffect) {
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory((StatementExprSideEffect) statement, program);
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
AsmFragmentInstanceSpecBuilder asmFragmentInstanceSpecBuilder = AsmFragmentInstanceSpecBuilder.exprSideEffect((StatementExprSideEffect) statement, program);
ensureEncoding(asm, asmFragmentInstanceSpecBuilder);
generateAsm(asm, asmFragmentInstanceSpecBuilder.getAsmFragmentInstanceSpec());
} else if(statement instanceof StatementReturn) {
Procedure procedure = null;
ScopeRef scope = block.getScope();
@ -907,7 +906,7 @@ public class Pass4CodeGeneration {
if(procedure == null || procedure.getInterruptType() == null) {
asm.addInstruction("rts", CpuAddressingMode.NON, null, false);
} else {
generateInterruptExit(asm, statement, procedure.getInterruptType());
generateInterruptExit(asm, procedure);
}
} else if(statement instanceof StatementAsm) {
StatementAsm statementAsm = (StatementAsm) statement;
@ -1025,30 +1024,21 @@ public class Pass4CodeGeneration {
* @param procedure The interrupt procedure
*/
private void generateInterruptEntry(AsmProgram asm, Procedure procedure) {
Procedure.InterruptType interruptType = procedure.getInterruptType();
asm.startChunk(procedure.getRef(), null, "entry interrupt(" + interruptType.name() + ")");
if(Procedure.InterruptType.KERNEL_MIN.equals(interruptType)) {
// No entry ASM needed
} else if(Procedure.InterruptType.KERNEL_KEYBOARD.equals(interruptType)) {
// No entry ASM needed
} else if(Procedure.InterruptType.HARDWARE_ALL.equals(interruptType)) {
asm.addInstruction("sta", CpuAddressingMode.ABS, "rega+1", false).setDontOptimize(true);
asm.addInstruction("stx", CpuAddressingMode.ABS, "regx+1", false).setDontOptimize(true);
asm.addInstruction("sty", CpuAddressingMode.ABS, "regy+1", false).setDontOptimize(true);
} else if(Procedure.InterruptType.HARDWARE_STACK.equals(interruptType)) {
asm.addInstruction("pha", CpuAddressingMode.NON, null, false).setDontOptimize(true);
asm.addInstruction("txa", CpuAddressingMode.NON, null, false).setDontOptimize(true);
asm.addInstruction("pha", CpuAddressingMode.NON, null, false).setDontOptimize(true);
asm.addInstruction("tya", CpuAddressingMode.NON, null, false).setDontOptimize(true);
asm.addInstruction("pha", CpuAddressingMode.NON, null, false).setDontOptimize(true);
} else if(Procedure.InterruptType.HARDWARE_NONE.equals(interruptType)) {
// No entry ASM needed
} else if(Procedure.InterruptType.HARDWARE_CLOBBER.equals(interruptType)) {
asm.addInstruction("sta", CpuAddressingMode.ABS, "rega+1", false).setDontOptimize(true);
asm.addInstruction("stx", CpuAddressingMode.ABS, "regx+1", false).setDontOptimize(true);
asm.addInstruction("sty", CpuAddressingMode.ABS, "regy+1", false).setDontOptimize(true);
final String interruptType = procedure.getInterruptType().toLowerCase();
AsmFragmentInstanceSpecBuilder entryFragment;
String entryName;
if(interruptType.contains("clobber")) {
entryFragment = AsmFragmentInstanceSpecBuilder.interruptEntry(interruptType.replace("clobber", "all"), program);
entryName = entryFragment.getAsmFragmentInstanceSpec().getSignature().replace("all", "clobber");
} else {
throw new RuntimeException("Interrupt Type not supported " + interruptType.name());
entryFragment = AsmFragmentInstanceSpecBuilder.interruptEntry(interruptType, program);
entryName = entryFragment.getAsmFragmentInstanceSpec().getSignature();
}
try {
asm.startChunk(procedure.getRef(), null, "interrupt(" + entryName+ ")");
generateAsm(asm, entryFragment.getAsmFragmentInstanceSpec());
} catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) {
throw new CompileError("Interrupt type not supported " + procedure.getInterruptType() + " int " + procedure.toString() + "\n" + e.getMessage());
}
}
@ -1056,42 +1046,28 @@ public class Pass4CodeGeneration {
* Generate exit-code for ending an interrupt procedure based on the interrupt type
*
* @param asm The assembler to generate code into
* @param statement The return statement
* @param interruptType The type of interrupt to generate
* @param procedure The procedure
*/
private void generateInterruptExit(AsmProgram asm, Statement statement, Procedure.InterruptType interruptType) {
asm.getCurrentChunk().setSource(asm.getCurrentChunk().getSource() + " - exit interrupt(" + interruptType.name() + ")");
if(Procedure.InterruptType.KERNEL_MIN.equals(interruptType)) {
asm.addInstruction("jmp", CpuAddressingMode.ABS, "$ea81", false);
} else if(Procedure.InterruptType.KERNEL_KEYBOARD.equals(interruptType)) {
asm.addInstruction("jmp", CpuAddressingMode.ABS, "$ea31", false);
} else if(Procedure.InterruptType.HARDWARE_ALL.equals(interruptType)) {
asm.addLabel("rega").setDontOptimize(true);
asm.addInstruction("lda", CpuAddressingMode.IMM, "00", false).setDontOptimize(true);
asm.addLabel("regx").setDontOptimize(true);
asm.addInstruction("ldx", CpuAddressingMode.IMM, "00", false).setDontOptimize(true);
asm.addLabel("regy").setDontOptimize(true);
asm.addInstruction("ldy", CpuAddressingMode.IMM, "00", false).setDontOptimize(true);
asm.addInstruction("rti", CpuAddressingMode.NON, null, false);
} else if(Procedure.InterruptType.HARDWARE_STACK.equals(interruptType)) {
asm.addInstruction("pla", CpuAddressingMode.NON, null, false).setDontOptimize(true);
asm.addInstruction("tay", CpuAddressingMode.NON, null, false).setDontOptimize(true);
asm.addInstruction("pla", CpuAddressingMode.NON, null, false).setDontOptimize(true);
asm.addInstruction("tax", CpuAddressingMode.NON, null, false).setDontOptimize(true);
asm.addInstruction("pla", CpuAddressingMode.NON, null, false).setDontOptimize(true);
asm.addInstruction("rti", CpuAddressingMode.NON, null, false);
} else if(Procedure.InterruptType.HARDWARE_NONE.equals(interruptType)) {
asm.addInstruction("rti", CpuAddressingMode.NON, null, false);
} else if(Procedure.InterruptType.HARDWARE_CLOBBER.equals(interruptType)) {
asm.addLabel("rega").setDontOptimize(true);
asm.addInstruction("lda", CpuAddressingMode.IMM, "00", false).setDontOptimize(true);
asm.addLabel("regx").setDontOptimize(true);
asm.addInstruction("ldx", CpuAddressingMode.IMM, "00", false).setDontOptimize(true);
asm.addLabel("regy").setDontOptimize(true);
asm.addInstruction("ldy", CpuAddressingMode.IMM, "00", false).setDontOptimize(true);
asm.addInstruction("rti", CpuAddressingMode.NON, null, false);
private void generateInterruptExit(AsmProgram asm, Procedure procedure) {
final String interruptType = procedure.getInterruptType().toLowerCase();
AsmFragmentInstanceSpecBuilder entryFragment;
String entryName;
if(interruptType.contains("clobber")) {
entryFragment = AsmFragmentInstanceSpecBuilder.interruptExit(interruptType.replace("clobber", "all"), program);
entryName = entryFragment.getAsmFragmentInstanceSpec().getSignature().replace("all", "clobber");
} else {
throw new RuntimeException("Interrupt Type not supported " + statement);
entryFragment = AsmFragmentInstanceSpecBuilder.interruptExit(interruptType, program);
entryName = entryFragment.getAsmFragmentInstanceSpec().getSignature();
}
asm.startChunk(procedure.getRef(), null, "interrupt(" + entryName + ")");
try {
generateAsm(asm, entryFragment.getAsmFragmentInstanceSpec());
} catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) {
throw new CompileError("Interrupt type not supported " + procedure.getInterruptType() + " int " + procedure.toString() + "\n" + e.getMessage());
}
// Mark labels as don't optimize
for(AsmLine asmLine : asm.getCurrentChunk().getLines()) {
if(asmLine instanceof AsmLabel) ((AsmLabel) asmLine).setDontOptimize(true);
}
}
@ -1168,9 +1144,9 @@ public class Pass4CodeGeneration {
if(isRegisterCopy(lValue, rValue)) {
asm.getCurrentChunk().setFragment("register_copy");
} else {
AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(lValue, rValue, program, scope);
ensureEncoding(asm, asmFragmentInstanceSpecFactory);
generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec());
AsmFragmentInstanceSpecBuilder asmFragmentInstanceSpecBuilder = AsmFragmentInstanceSpecBuilder.assignment(lValue, rValue, program, scope);
ensureEncoding(asm, asmFragmentInstanceSpecBuilder);
generateAsm(asm, asmFragmentInstanceSpecBuilder.getAsmFragmentInstanceSpec());
}
}
transitionSetGenerated(transition);
@ -1186,7 +1162,7 @@ public class Pass4CodeGeneration {
* @param asm The ASM program (where any .encoding directive will be emitted)
* @param asmFragmentInstance The ASM fragment to be emitted
*/
private static void ensureEncoding(AsmProgram asm, AsmFragmentInstanceSpecFactory asmFragmentInstance) {
private static void ensureEncoding(AsmProgram asm, AsmFragmentInstanceSpecBuilder asmFragmentInstance) {
asm.ensureEncoding(getEncoding(asmFragmentInstance));
}
@ -1222,7 +1198,7 @@ public class Pass4CodeGeneration {
* @param asmFragmentInstance The asm fragment instance to examine
* @return Any encoding found inside the constant
*/
private static Set<StringEncoding> getEncoding(AsmFragmentInstanceSpecFactory asmFragmentInstance) {
private static Set<StringEncoding> getEncoding(AsmFragmentInstanceSpecBuilder asmFragmentInstance) {
LinkedHashSet<StringEncoding> encodings = new LinkedHashSet<>();
Map<String, Value> bindings = asmFragmentInstance.getBindings();
for(Value boundValue : bindings.values()) {

View File

@ -1,21 +1,20 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.asm.AsmChunk;
import dk.camelot64.cpufamily6502.CpuClobber;
import dk.camelot64.kickc.asm.AsmLine;
import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.asm.*;
import dk.camelot64.kickc.fragment.AsmFragmentInstance;
import dk.camelot64.kickc.fragment.AsmFragmentInstanceSpecBuilder;
import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
import dk.camelot64.kickc.model.CallGraph;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.values.ProcedureRef;
import dk.camelot64.kickc.model.values.ScopeRef;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
/*** Ensure that all interrupt procedures with type {@link Procedure.InterruptType#HARDWARE_CLOBBER } only saves the necessary registers. */
/*** Ensure that all interrupt procedures with CLOBBER type only saves the necessary registers. */
public class Pass4InterruptClobberFix extends Pass2Base {
public Pass4InterruptClobberFix(Program program) {
@ -28,44 +27,38 @@ public class Pass4InterruptClobberFix extends Pass2Base {
public void fix() {
Collection<Procedure> procedures = getProgram().getScope().getAllProcedures(true);
for(Procedure procedure : procedures) {
if(Procedure.InterruptType.HARDWARE_CLOBBER.equals(procedure.getInterruptType())) {
if(procedure.getInterruptType() != null && procedure.getInterruptType().toLowerCase().contains("clobber")) {
// Find the interrupt routine clobber
CpuClobber procClobber = getProcedureClobber(procedure);
getLog().append("Interrupt procedure "+procedure.getFullName()+" clobbers "+procClobber.toString());
getLog().append("Interrupt procedure " + procedure.getFullName() + " clobbers " + procClobber.toString());
// Find the entry/exit blocks for the interrupt
AsmChunk interruptEntry = null;
AsmChunk interruptExit = null;
for(AsmChunk asmChunk : getProgram().getAsm().getChunks()) {
if(procedure.getFullName().equals(asmChunk.getScopeLabel())) {
if(asmChunk.getSource().contains(Procedure.InterruptType.HARDWARE_CLOBBER.name())) {
if(asmChunk.getSource().contains("entry interrupt")) {
if(asmChunk.getSource().contains("clobber")) {
if(asmChunk.getSource().endsWith("_entry)")) {
interruptEntry = asmChunk;
} else if(asmChunk.getSource().contains("exit interrupt")) {
} else if(asmChunk.getSource().endsWith("_exit)")) {
interruptExit = asmChunk;
} else {
throw new RuntimeException("Unknown interrupt ASM chunk "+ asmChunk.getSource());
throw new RuntimeException("Unknown interrupt ASM chunk " + asmChunk.getSource());
}
continue;
}
}
}
if(interruptEntry==null || interruptExit==null) {
throw new RuntimeException("Cannot find interrupt entry/exit for interrupt "+procedure.getFullName());
if(interruptEntry == null || interruptExit == null) {
throw new RuntimeException("Cannot find interrupt entry/exit for interrupt " + procedure.getFullName());
}
List<String> notClobberedRegisters = getNonClobberedRegisterNames(procClobber);
if(notClobberedRegisters.isEmpty()) {
// All registers clobbered - no need to fix anything
continue;
}
// Remove all lines saving/restoring non-clobbered registers in entry
pruneNonClobberedInterruptLines(interruptEntry, notClobberedRegisters);
// Remove all lines saving/restoring non-clobbered registers in entry
pruneNonClobberedInterruptLines(interruptExit, notClobberedRegisters);
String clobberedRegisters = getClobberedRegisterNames(procClobber);
// Update the interrupt entry ASM with the proper clobber fragment
updateClobberFragment(interruptEntry, clobberedRegisters);
// Update the interrupt exit ASM with the proper clobber fragment
updateClobberFragment(interruptExit, clobberedRegisters);
}
}
}
private CpuClobber getProcedureClobber(Procedure procedure) {
@ -73,7 +66,7 @@ public class Pass4InterruptClobberFix extends Pass2Base {
CpuClobber procClobber = CpuClobber.CLOBBER_NONE;
for(AsmChunk asmChunk : asm.getChunks()) {
if(procedure.getFullName().equals(asmChunk.getScopeLabel())) {
if(asmChunk.getSource().contains(Procedure.InterruptType.HARDWARE_CLOBBER.name())) {
if(asmChunk.getSource().contains("clobber")) {
// Do not count clobber in the entry/exit
continue;
}
@ -96,33 +89,76 @@ public class Pass4InterruptClobberFix extends Pass2Base {
return procClobber;
}
private List<String> getNonClobberedRegisterNames(CpuClobber procClobber) {
List<String> notClobberedRegisters = new ArrayList<>();
if(!procClobber.isRegisterA()) {
notClobberedRegisters.add("a");
/**
* Get the clobbered registers
*
* @param procClobber CPU clobber from running the interrupt routine
* @return The clobbered registers as a string. "axyz" is all registers, "" is none.
*/
private String getClobberedRegisterNames(CpuClobber procClobber) {
String clobberedRegisters = "";
if(procClobber.isRegisterA()) {
clobberedRegisters += "a";
}
if(!procClobber.isRegisterX()) {
notClobberedRegisters.add("x");
if(procClobber.isRegisterX()) {
clobberedRegisters += "x";
}
if(!procClobber.isRegisterY()) {
notClobberedRegisters.add("y");
if(procClobber.isRegisterY()) {
clobberedRegisters += "y";
}
return notClobberedRegisters;
if(procClobber.isRegisterZ()) {
clobberedRegisters += "z";
}
return clobberedRegisters;
}
private void pruneNonClobberedInterruptLines(AsmChunk interruptEntryExit, List<String> notClobberedRegisters) {
ListIterator<AsmLine> entryLines = interruptEntryExit.getLines().listIterator();
while(entryLines.hasNext()) {
AsmLine line = entryLines.next();
for(String notClobberedReg : notClobberedRegisters) {
final String lineAsm = line.getAsm();
if(lineAsm.contains("ld"+notClobberedReg) || lineAsm.contains("st"+notClobberedReg) || lineAsm.contains("reg"+notClobberedReg)) {
// Found an A/X/Y in the asm where A/X/Y is not clobbered - remove the line
getLog().append("Removing interrupt register storage "+line.toString()+" in "+interruptEntryExit.getIndex()+" "+interruptEntryExit.getSource());
entryLines.remove();
}
/**
* Replace the current code with the proper version handling only the clobbered registers
*
* @param interruptAsmChunk The AsmFragment representing an interrupt entry/exit
* @param clobberedRegisters The clobbered registers
*/
private void updateClobberFragment(AsmChunk interruptAsmChunk, String clobberedRegisters) {
// find the clobber fragment sub-name
String clobberName = "clob" + clobberedRegisters;
if(clobberedRegisters.equals(""))
clobberName = "none";
String allRegisters = "axy" + (getProgram().getTargetCpu().getCpu65xx().hasRegisterZ() ? "z" : "");
if(clobberedRegisters.equals(allRegisters))
clobberName = "all";
// Find the interrupt type name (including "isr_" and "_entry"/"_exit"
String interruptType = interruptAsmChunk.getSource();
interruptType = interruptType.substring(("interrupt(".length()), interruptType.length() - 1);
// Find the correct clobber name based on the clobbered registers
final String interruptSignatureFinal = interruptType.replace("clobber", clobberName);
AsmFragmentInstanceSpecBuilder interruptFragment = AsmFragmentInstanceSpecBuilder.interrupt(interruptSignatureFinal, getProgram());
String interruptFragmentName = interruptFragment.getAsmFragmentInstanceSpec().getSignature();
// Generate the fragment
final AsmFragmentTemplateSynthesizer cpuSynthesizer = getProgram().getAsmFragmentMasterSynthesizer().getSynthesizer(getProgram().getTargetCpu());
final AsmFragmentInstance fragmentInstance = cpuSynthesizer.getFragmentInstance(interruptFragment.getAsmFragmentInstanceSpec(), getProgram().getLog());
interruptAsmChunk.setFragment(fragmentInstance.getFragmentName());
final AsmProgram asmLines = new AsmProgram(getProgram().getTargetCpu());
asmLines.startChunk(getProgram().getScope().getRef(), interruptAsmChunk.getStatementIdx(), interruptAsmChunk.getSource());
fragmentInstance.generate(asmLines);
// Replace the chunk lines with the generated lines
final List<AsmLine> interruptAsmChunkLines = interruptAsmChunk.getLines();
int line_idx = interruptAsmChunkLines.get(0).getIndex();
boolean hasScopeEnd = interruptAsmChunkLines.get(interruptAsmChunkLines.size() - 1) instanceof AsmScopeEnd;
interruptAsmChunkLines.clear();
interruptAsmChunk.setSource("interrupt(" + interruptFragmentName+ ")");
for(AsmChunk chunk : asmLines.getChunks()) {
for(AsmLine line : chunk.getLines()) {
interruptAsmChunk.addLine(line);
line.setIndex(line_idx++);
if(line instanceof AsmLabel) ((AsmLabel) line).setDontOptimize(true);
}
}
if(hasScopeEnd)
interruptAsmChunkLines.add(new AsmScopeEnd());
}
}

View File

@ -3,6 +3,7 @@
"link": "asm6502.ld",
"start_address": "0x2000",
"cpu": "MOS6502X",
"interrupt": "hardware_all",
"emulator": "x64sc"
}

View File

@ -3,6 +3,7 @@
"extension": "a26",
"link": "atari2600.ld",
"cpu": "MOS6502X",
"interrupt": "hardware_all",
"zp_reserve": [ "0x00..0x7f" ],
"encoding": "screencode_atari",
"defines": {

View File

@ -1,6 +1,7 @@
{
"description": "Atari XL/XE executable XEX file with a single segment.",
"cpu": "MOS6502X",
"interrupt": "hardware_all",
"link": "atarixl.ld",
"start_address": "0x2000",
"zp_reserve": [ "0x00..0x7f" ],

View File

@ -4,6 +4,7 @@
"link": "c64.ld",
"start_address": "0x080d",
"cpu": "MOS6502X",
"interrupt": "rom_min_c64",
"emulator": "x64sc",
"defines": {
"__C64__": 1

View File

@ -3,6 +3,7 @@
"link": "c64basic.ld",
"start_address": "0x080d",
"cpu": "MOS6502X",
"interrupt": "rom_min_c64",
"emulator": "x64sc",
"defines": {
"__C64__": 1

View File

@ -4,6 +4,7 @@
"link": "cx16.ld",
"start_address": "0x080d",
"cpu": "WDC65C02",
"interrupt": "rom_min_cx16",
"emulator": "x16emu -debug -run -scale 2 -prg",
"defines": {
"__CX16__": 1

View File

@ -4,6 +4,7 @@
"link": "mega65.ld",
"start_address": "0x2017",
"cpu": "MEGA45GS02",
"interrupt": "rom_min_mega65",
"emulator": "xmega65 -prg",
"defines": {
"__MEGA65__": 1

View File

@ -4,6 +4,7 @@
"link": "mega65_c64.ld",
"start_address": "0x080d",
"cpu": "MEGA45GS02",
"interrupt": "rom_min_c64",
"emulator": "xmega65 -prg",
"defines": {
"__MEGA65__": 1,

View File

@ -2,10 +2,11 @@
"description": "Nintendo Entertainment System (NES) ROM (Mapper 0 NROM, Vertical Mirroring).",
"extension": "nes",
"link": "nes.ld",
"cpu": "MOS6502X",
"emulator": "Nestopia",
"cpu": "ROM6502X",
"interrupt": "hardware_all",
"zp_reserve": [ ],
"defines": {
"__NES__": 1
}
},
"emulator": "Nestopia"
}

View File

@ -4,6 +4,7 @@
"link": "plus4.ld",
"start_address": "0x100d",
"cpu": "MOS6502X",
"interrupt": "rom_min_plus4",
"emulator": "xplus4",
"defines": {
"__PLUS4__": 1

View File

@ -3,6 +3,7 @@
"link": "plus4basic.ld",
"start_address": "0x100d",
"cpu": "MOS6502X",
"interrupt": "rom_min_plus4",
"emulator": "xplus4",
"defines": {
"__PLUS4__": 1

View File

@ -4,6 +4,7 @@
"link": "vic20.ld",
"start_address": "0x100d",
"cpu": "MOS6502X",
"interrupt": "rom_min_vic20",
"emulator": "xvic",
"defines": {
"__VIC20__": 1

View File

@ -3,6 +3,7 @@
"link": "vic20basic.ld",
"start_address": "0x100d",
"cpu": "MOS6502X",
"interrupt": "rom_min_vic20",
"emulator": "xvic",
"defines": {
"__VIC20__": 1

View File

@ -3852,6 +3852,16 @@ public class TestPrograms {
compileAndCompare("irq-kernel-minimal.c");
}
@Test
public void testIrqUnknownType() throws IOException, URISyntaxException {
assertError("irq-unknown-type.c", "Interrupt type not supported unknown", false);
}
@Test
public void testIrqPragma() throws IOException, URISyntaxException {
compileAndCompare("irq-pragma.c");
}
@Test
public void testIrqHyperscreen() throws IOException, URISyntaxException {
compileAndCompare("examples/irq/irq-hyperscreen.c");

View File

@ -50,7 +50,7 @@ void init_irq() {
}
// Interrupt Routine counting frames
interrupt(hardware_clobber) void irq() {
__interrupt(hardware_clobber) void irq() {
*BG_COLOR = WHITE;
if(frame_cnt) frame_cnt++;
*BG_COLOR = BLACK;

View File

@ -57,7 +57,7 @@ void init_irq() {
}
// Interrupt Routine counting frames
interrupt(hardware_clobber) void irq() {
__interrupt(hardware_clobber) void irq() {
*BG_COLOR = WHITE;
if(frame_cnt) frame_cnt++;
*BG_COLOR = BLACK;

View File

@ -66,7 +66,7 @@ void init_irq() {
}
// Interrupt Routine counting frames
interrupt(hardware_clobber) void irq() {
__interrupt(hardware_clobber) void irq() {
*BG_COLOR = WHITE;
if(frame_cnt) frame_cnt++;
*BG_COLOR = BLACK;

View File

@ -12,7 +12,7 @@ void main() {
volatile byte irq_raster_next = 0;
interrupt(hardware_clobber) void irq() {
__interrupt(hardware_clobber) void irq() {
*BORDER_COLOR = DARK_GREY;
irq_raster_next += 21;
// Setup next interrupt

View File

@ -4,6 +4,7 @@
#pragma link("ataritempest.ld")
#pragma extension("bin")
#pragma cpu(ROM6502X)
char* const BG_COLOR = 0xc01a;
@ -17,7 +18,7 @@ void entryPoint() {
SCREEN[i] = MESSAGE[i];
}
void interrupt(HARDWARE_ALL) nmiHandler() {
void __interrupt(hardware_clobber) nmiHandler() {
(*BG_COLOR)++;
}

View File

@ -305,7 +305,7 @@ void setupRasterIrq(unsigned int raster, void()* irqRoutine) {
const char RASTER_IRQ_TOP = 0x30;
// Raster Interrupt at the top of the screen
interrupt(hardware_all) void irqTop() {
__interrupt(hardware_clobber) void irqTop() {
if(DEBUG) {
for( char i: 0..4) {}
*BORDER_COLOR = WHITE;
@ -325,7 +325,7 @@ interrupt(hardware_all) void irqTop() {
const char RASTER_IRQ_MIDDLE = 0xff;
// Raster Interrupt at the bottom of the screen
interrupt(hardware_all) void irqBottom() {
__interrupt(hardware_clobber) void irqBottom() {
if(DEBUG) {
for( char i: 0..4) {}
*BORDER_COLOR = WHITE;

View File

@ -91,7 +91,7 @@ volatile char scroll_y;
char * volatile vram_update_list;
// NMI Called when the PPU refreshes the screen (also known as the V-Blank period)
interrupt(hardware_stack) void vblank() {
__interrupt(hardware_clobber) void vblank() {
// Transfer any queued data to the PPU
lnListTransfer();
// DMA transfer the entire sprite buffer to the PPU

View File

@ -13,7 +13,7 @@ typedef unsigned short uword;
// RESET Called when the NES is reset, including when it is turned on.
void main();
// NMI Called when the PPU refreshes the screen (also known as the V-Blank period)
interrupt(hardware_stack) void vblank();
__interrupt(hardware_clobber) void vblank();
// Wait for next vblank
// flags: 0, lfBlank or lfSplit (see below)

View File

@ -129,7 +129,7 @@ int main(void)
}
// NMI Called when the PPU refreshes the screen (also known as the V-Blank period)
interrupt(hardware_stack) void vblank() {
__interrupt(hardware_clobber) void vblank() {
// Set scroll
PPU->PPUSCROLL = 0;
PPU->PPUSCROLL = scroll_y;

View File

@ -129,7 +129,7 @@ int main(void)
}
// NMI Called when the PPU refreshes the screen (also known as the V-Blank period)
interrupt(hardware_stack) void vblank() {
__interrupt(hardware_clobber) void vblank() {
// Set scroll
PPU->PPUSCROLL = 0;
PPU->PPUSCROLL = scroll_y;

View File

@ -125,7 +125,7 @@ void setup_irq() {
}
// Interrupt Routine 1: Just above last text line.
interrupt(kernel_min) void irq_bottom_1() {
__interrupt void irq_bottom_1() {
// Change border color
VICII->BORDER_COLOR = DARK_GREY;
// Show the cycle counter
@ -138,7 +138,7 @@ interrupt(kernel_min) void irq_bottom_1() {
}
// Interrupt Routine 2
interrupt(kernel_keyboard) void irq_bottom_2() {
__interrupt(rom_sys_c64) void irq_bottom_2() {
// Change border color
VICII->BORDER_COLOR = BLACK;
// Show the current canvas (unless a key is being pressed)

View File

@ -136,7 +136,7 @@ void plex_move() {
volatile bool frame_done = false;
// Show sprites from the multiplexer, rescheduling the IRQ as many times as needed
interrupt(kernel_min) void plex_irq() {
__interrupt void plex_irq() {
asm { sei }
//*BORDER_COLOR = WHITE;
// Show sprites until finding one that should not be shown until a few raster lines later

View File

@ -56,7 +56,7 @@ void sprites_irq_init() {
// Raster Interrupt Routine - sets up the sprites covering the playfield
// Repeats 10 timers every 2 lines from line IRQ_RASTER_FIRST
// Utilizes duplicated gfx in the sprites to allow for some leeway in updating the sprite pointers
interrupt(hardware_clobber) void sprites_irq() {
__interrupt(hardware_clobber) void sprites_irq() {
//(*BG_COLOR)++;
// Clear decimal flag (because it is used by the score algorithm)
asm { cld }

View File

@ -17,7 +17,7 @@ void main() {
}
// Interrupt Routine
interrupt(kernel_keyboard) void irq() {
__interrupt(rom_sys_c64) void irq() {
PLEX_SCREEN_PTR1[idx]++;
PLEX_SCREEN_PTR2[idx]++;
idx++;

View File

@ -1,7 +1,7 @@
// Example program for the Commander X16
// Displays raster bars in the border
#pragma target(cx16)
#pragma target(cx16)
#include <cx16.h>
#include <6502.h>
#include <string.h>
@ -42,7 +42,7 @@ volatile char cnt = 2;
volatile char sin_idx = 100;
// LINE Interrupt Routine
void irq_line() {
__interrupt void irq_line() {
// Update the border
*VERA_CTRL |= VERA_DCSEL;
*VERA_DC_HSTART = hstart;
@ -84,15 +84,4 @@ void irq_line() {
// Reset the LINE interrupt
*VERA_ISR = VERA_LINE;
// Exit CX16 KERNAL IRQ
asm {
// soft exit (keep kernal running)
// jmp $e034
// hard exit (no kernal activity)
ply
plx
pla
rti
}
}

View File

@ -7,7 +7,7 @@
#define NUM_SPRITES 32
// A 64*64 8bpp TUT sprite
// A 64*64 8bpp TUT sprite and palette
align(0x1000) char SPRITE_PIXELS[64*64+0x200] = kickasm(resource "tut.png") {{
.var pic = LoadPicture("tut.png")
// palette: rgb->idx
@ -16,8 +16,10 @@ align(0x1000) char SPRITE_PIXELS[64*64+0x200] = kickasm(resource "tut.png") {{
.var palList = List()
// Next palette index
.var nxt_idx = 0;
// Extract palette while outputting pixels as palete index values
.for (var y=0; y<64; y++) {
.for (var x=0;x<64; x++) {
// Find palette index (add if not known)
.var rgb = pic.getPixel(x,y);
.var idx = palette.get(rgb)
.if(idx==null) {
@ -25,11 +27,12 @@ align(0x1000) char SPRITE_PIXELS[64*64+0x200] = kickasm(resource "tut.png") {{
.eval palette.put(rgb,idx);
.eval palList.add(rgb)
}
// Output pixel index
// Output pixel as palette index
.byte idx
}
}
// Output sprite palette (offset 64*64 bytes)
.if(nxt_idx>256) .error "Image has too many colours "+nxt_idx
// Output sprite palette (at offset 64*64 bytes)
.for(var i=0;i<256;i++) {
.var rgb = palList.get(i)
.var red = floor(rgb / [256*256])
@ -40,7 +43,6 @@ align(0x1000) char SPRITE_PIXELS[64*64+0x200] = kickasm(resource "tut.png") {{
// bits bits 0-3 red
.byte red/16
}
}};
// Address to use for sprite pixels in VRAM
@ -90,7 +92,7 @@ volatile unsigned int sin_idx_x = 119;
volatile unsigned int sin_idx_y = 79;
// VSYNC Interrupt Routine
void irq_vsync() {
__interrupt(rom_sys_cx16) void irq_vsync() {
// Move the sprite around
if(++sin_idx_x==SINX_LEN) sin_idx_x = 0;
if(--sin_idx_y==0xffff) sin_idx_y = SINY_LEN-1;

View File

@ -5,7 +5,6 @@
#include <cx16.h>
void main() {
// Copy message to screen one char at a time
char MSG[] = "hello world!";
char* vaddr = DEFAULT_SCREEN;
@ -13,7 +12,6 @@ void main() {
vpoke(0, vaddr++, MSG[i]); // Message
vpoke(0, vaddr++, 0x21); // Red background, White foreground
}
// Copy message (and colors) to screen using memcpy_to_vram
char MSG2[] = "h e l l o w o r l d ! "; // Space is 0x20, red background black foreground
memcpy_to_vram(0, DEFAULT_SCREEN+0x100, MSG2, sizeof(MSG2));

View File

@ -24,7 +24,7 @@ void main() {
}
// Interrupt Routine 1
interrupt(hardware_stack) void irq_bottom_1() {
__interrupt(hardware_clobber) void irq_bottom_1() {
VICII->BORDER_COLOR = WHITE;
// Set screen height to 24 lines - this is done after the border should have started drawing - so it wont start
VICII->CONTROL1 &= ($ff^VIC_RSEL);
@ -37,7 +37,7 @@ interrupt(hardware_stack) void irq_bottom_1() {
}
// Interrupt Routine 2
interrupt(hardware_stack) void irq_bottom_2() {
__interrupt(hardware_clobber) void irq_bottom_2() {
VICII->BORDER_COLOR = WHITE;
// Set screen height back to 25 lines (preparing for the next screen)
VICII->CONTROL1 |= VIC_RSEL;

View File

@ -61,7 +61,7 @@ void main() {
}
// Raster IRQ routine
interrupt(hardware_stack) void irq() {
__interrupt(hardware_clobber) void irq() {
// Acknowledge the IRQ
VICII->IRQ_STATUS = IRQ_RASTER;
// Color border

View File

@ -102,7 +102,7 @@ volatile char greet_zoomx;
volatile char greet_idx;
// BIG INTERRUPT LOOP
interrupt(hardware_stack) void irq() {
__interrupt(hardware_clobber) void irq() {
// force NTSC every frame (hehe)
VICIV->RASLINE0 |= 0x80;
// Acknowledge the IRQ

View File

@ -28,7 +28,7 @@ void main() {
}
// Raster IRQ Routine playing music
interrupt(kernel_keyboard) void irq_play() {
__interrupt(rom_sys_c64) void irq_play() {
(VICII->BORDER_COLOR)++;
// Play SID
(*musicPlay)();

View File

@ -46,7 +46,7 @@ volatile char x_scroll;
volatile char y_scroll;
// NMI Called when the PPU refreshes the screen (also known as the V-Blank period)
interrupt(hardware_stack) void vblank() {
__interrupt void vblank() {
// Read controller 1
char joy = readJoy1();
if(joy&JOY_DOWN) {

View File

@ -30,7 +30,7 @@ void main() {
}
// NMI Called when the PPU refreshes the screen (also known as the V-Blank period)
interrupt(hardware_stack) void vblank() {
__interrupt void vblank() {
// Read controller 1
char joy = readJoy1();

View File

@ -31,7 +31,7 @@ volatile char x_sin_idx = 73;
volatile char x_sin_idx_2 = 82;
// NMI Called when the PPU refreshes the screen (also known as the V-Blank period)
interrupt(hardware_stack) void vblank() {
__interrupt void vblank() {
// Set scroll
PPU->PPUSCROLL = 0;
PPU->PPUSCROLL = 0;

View File

@ -32,7 +32,7 @@ void main() {
asm { cli }
}
interrupt(hardware_all) void nmi() {
__interrupt(hardware_clobber) void nmi() {
(VICII->BORDER_COLOR)++;
asm { lda CIA2_INTERRUPT }
SID->VOLUME_FILTER_MODE = *sample & $0f;
@ -40,7 +40,7 @@ interrupt(hardware_all) void nmi() {
(VICII->BORDER_COLOR)--;
}
interrupt(hardware_all) void nmi2() {
__interrupt(hardware_clobber) void nmi2() {
(VICII->BORDER_COLOR)++;
asm { lda CIA2_INTERRUPT }
SID->VOLUME_FILTER_MODE = *sample >> 4;

View File

@ -8,7 +8,7 @@ void main() {
*KERNEL_IRQ = &irq;
}
interrupt void irq() {
__interrupt void irq() {
SCREEN[40] = col1++;
SCREEN[41] = col2++;
}

View File

@ -19,7 +19,7 @@ void main() {
}
}
interrupt void irq() {
__interrupt void irq() {
// Acknowledge the IRQ
*IRQ_STATUS = 1;
asm { lda $dc0d }

Some files were not shown because too many files have changed in this diff Show More