From e25ef0e3f7a2d4285406e6ba479782e372004ab3 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sun, 5 Jul 2020 21:58:53 +0200 Subject: [PATCH] Fixed ASM error in fragment. Improved fragment synthesis. Working on lazynes (there seems to be an issue with waiting for vblank using lnSync(0) ). --- .../fragment/cache/fragment-cache-mos6502.asm | 2 +- .../cache/fragment-cache-mos6502x.asm | 293 ++---------------- .../mos6502-common/vwsm1=vwsm2_plus_vbuaa.asm | 4 +- .../AsmFragmentTemplateSynthesisRule.java | 13 + src/test/kc/complex/lazynes/balloon.c | 40 +++ src/test/kc/complex/lazynes/lazyhello.c | 1 + src/test/kc/complex/lazynes/lazymain.c | 62 ---- src/test/kc/complex/lazynes/lazynes.c | 109 ++++++- src/test/kc/complex/lazynes/lazynes.h | 15 +- src/test/ref/complex/polygon/polygon.asm | 2 +- src/test/ref/complex/polygon/polygon.log | 6 +- src/test/ref/global-label-problem.log | 4 +- src/test/ref/pointer-void-1.log | 4 +- src/test/ref/pointer-void-2.log | 4 +- .../procedure-callingconvention-stack-12.asm | 4 +- .../procedure-callingconvention-stack-12.log | 19 +- src/test/ref/struct-ptr-28.log | 4 +- src/test/ref/struct-ptr-31.log | 4 +- src/test/ref/struct-ptr-4.log | 4 +- 19 files changed, 221 insertions(+), 373 deletions(-) create mode 100644 src/test/kc/complex/lazynes/balloon.c delete mode 100644 src/test/kc/complex/lazynes/lazymain.c diff --git a/src/main/fragment/cache/fragment-cache-mos6502.asm b/src/main/fragment/cache/fragment-cache-mos6502.asm index 20bc835c1..06affc4ac 100644 --- a/src/main/fragment/cache/fragment-cache-mos6502.asm +++ b/src/main/fragment/cache/fragment-cache-mos6502.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE 1695362db1 +//KICKC FRAGMENT CACHE 160b015f22 //FRAGMENT vbuz1=vbuc1 lda #{c1} sta {z1} diff --git a/src/main/fragment/cache/fragment-cache-mos6502x.asm b/src/main/fragment/cache/fragment-cache-mos6502x.asm index dcd994605..9535746f0 100644 --- a/src/main/fragment/cache/fragment-cache-mos6502x.asm +++ b/src/main/fragment/cache/fragment-cache-mos6502x.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE 1695362db1 +//KICKC FRAGMENT CACHE 160b015f22 //FRAGMENT vbuz1=vbuc1 lda #{c1} sta {z1} @@ -6344,34 +6344,13 @@ tsx txa axs #-4 txs -//FRAGMENT pbuz1=_stackidxptr_vbuc1 -tsx -lda STACK_BASE+{c1},x -sta {z1} -lda STACK_BASE+{c1}+1,x -sta {z1}+1 -//FRAGMENT pbuc1_derefidx_vbuz1=_deref_pbuz2 -ldx {z1} -ldy #0 -lda ({z2}),y -sta {c1},x -//FRAGMENT _stackpushptr_=pbuc1 -lda #>{c1} -pha -lda #<{c1} -pha -//FRAGMENT _stackpushbyte_=vbuc1 -lda #{c1} -pha -//FRAGMENT _stackpullbyte_3 -tsx -txa -axs #-3 -txs //FRAGMENT vbuz1=vbuz2_minus_1 ldx {z2} dex stx {z1} +//FRAGMENT _stackpushbyte_=vbuc1 +lda #{c1} +pha //FRAGMENT vbuaa=vbuz1_minus_1 lda {z1} sec @@ -9067,21 +9046,6 @@ sta {z1} lda #>{c1} sbc {z1}+1 sta {z1}+1 -//FRAGMENT pbuc1_derefidx_vbuaa=_deref_pbuz1 -tax -ldy #0 -lda ({z1}),y -sta {c1},x -//FRAGMENT pbuc1_derefidx_vbuxx=_deref_pbuz1 -ldy #0 -lda ({z1}),y -sta {c1},x -//FRAGMENT pbuc1_derefidx_vbuyy=_deref_pbuz1 -tya -tax -ldy #0 -lda ({z1}),y -sta {c1},x //FRAGMENT pbsc1_derefidx_vbuz1=_deref_pbsc2 lda {c2} ldy {z1} @@ -11501,180 +11465,6 @@ sta {z1}+1 asl $ff rol {z1} rol {z1}+1 -//FRAGMENT vwuz1=pbuz2_bxor_vwuc1 -lda #<{c1} -eor {z2} -sta {z1} -lda #>{c1} -eor {z2}+1 -sta {z1}+1 -//FRAGMENT pbuz1_derefidx_vbuz2=pbuz1_derefidx_vbuz2_bor_pbuc1_derefidx_vbuz3 -ldy {z2} -lda ({z1}),y -ldy {z3} -ora {c1},y -ldy {z2} -sta ({z1}),y -//FRAGMENT vbuz1=vbuz1_bxor_pbuz2_derefidx_vbuz3 -lda {z1} -ldy {z3} -eor ({z2}),y -sta {z1} -//FRAGMENT vbuz1=_neg_vbuz1 -lda {z1} -eor #$ff -clc -adc #$01 -sta {z1} -//FRAGMENT pbuz1_derefidx_vbuz2=pbuz1_derefidx_vbuz2_bor_pbuc1_derefidx_vbuaa -ldy {z2} -tax -lda ({z1}),y -ora {c1},x -ldy {z2} -sta ({z1}),y -//FRAGMENT pbuz1_derefidx_vbuz2=pbuz1_derefidx_vbuz2_bor_pbuc1_derefidx_vbuxx -ldy {z2} -lda ({z1}),y -ora {c1},x -ldy {z2} -sta ({z1}),y -//FRAGMENT pbuz1_derefidx_vbuz2=pbuz1_derefidx_vbuz2_bor_pbuc1_derefidx_vbuyy -tya -ldy {z2} -tax -lda ({z1}),y -ora {c1},x -ldy {z2} -sta ({z1}),y -//FRAGMENT pbuz1_derefidx_vbuxx=pbuz1_derefidx_vbuxx_bor_pbuc1_derefidx_vbuz2 -txa -tay -lda ({z1}),y -ldy {z2} -stx $ff -ora {c1},y -ldy $ff -sta ({z1}),y -//FRAGMENT pbuz1_derefidx_vbuxx=pbuz1_derefidx_vbuxx_bor_pbuc1_derefidx_vbuaa -tay -txa -ldx {c1},y -tay -lda ({z1}),y -sty $ff - -stx $ff -ora $ff -ldy $ff -sta ({z1}),y -//FRAGMENT pbuz1_derefidx_vbuxx=pbuz1_derefidx_vbuxx_bor_pbuc1_derefidx_vbuxx -txa -tay -lda ({z1}),y -stx $ff -ora {c1},x -ldy $ff -sta ({z1}),y -//FRAGMENT pbuz1_derefidx_vbuxx=pbuz1_derefidx_vbuxx_bor_pbuc1_derefidx_vbuyy -txa -ldx {c1},y -tay -lda ({z1}),y -sty $ff - -stx $ff -ora $ff -ldy $ff -sta ({z1}),y -//FRAGMENT pbuz1_derefidx_vbuyy=pbuz1_derefidx_vbuyy_bor_pbuc1_derefidx_vbuz2 -lda ({z1}),y -sty $ff - -ldy {z2} -ora {c1},y -ldy $ff -sta ({z1}),y -//FRAGMENT pbuz1_derefidx_vbuyy=pbuz1_derefidx_vbuyy_bor_pbuc1_derefidx_vbuaa -tax -lda ({z1}),y -sty $ff - -ora {c1},x -ldy $ff -sta ({z1}),y -//FRAGMENT pbuz1_derefidx_vbuyy=pbuz1_derefidx_vbuyy_bor_pbuc1_derefidx_vbuxx -lda ({z1}),y -sty $ff - -ora {c1},x -ldy $ff -sta ({z1}),y -//FRAGMENT pbuz1_derefidx_vbuyy=pbuz1_derefidx_vbuyy_bor_pbuc1_derefidx_vbuyy -lda ({z1}),y -sty $ff - -ora {c1},y -ldy $ff -sta ({z1}),y -//FRAGMENT vbuz1=vbuz1_bxor_pbuz2_derefidx_vbuaa -tay -lda {z1} -eor ({z2}),y -sta {z1} -//FRAGMENT vbuz1=vbuz1_bxor_pbuz2_derefidx_vbuxx -txa -tay -lda {z1} -eor ({z2}),y -sta {z1} -//FRAGMENT vbuz1=vbuz1_bxor_pbuz2_derefidx_vbuyy -lda {z1} -eor ({z2}),y -sta {z1} -//FRAGMENT vbuaa=vbuaa_bxor_pbuz1_derefidx_vbuz2 -ldy {z2} -eor ({z1}),y -//FRAGMENT vbuaa=vbuaa_bxor_pbuz1_derefidx_vbuaa -tay -eor ({z1}),y -//FRAGMENT vbuaa=vbuaa_bxor_pbuz1_derefidx_vbuxx -stx $ff -ldy $ff -eor ({z1}),y -//FRAGMENT vbuaa=vbuaa_bxor_pbuz1_derefidx_vbuyy -eor ({z1}),y -//FRAGMENT vbuxx=vbuxx_bxor_pbuz1_derefidx_vbuz2 -ldy {z2} -txa -eor ({z1}),y -tax -//FRAGMENT vbuxx=vbuxx_bxor_pbuz1_derefidx_vbuaa -tay -txa -eor ({z1}),y -tax -//FRAGMENT vbuxx=vbuxx_bxor_pbuz1_derefidx_vbuxx -txa -tay -eor ({z1}),y -tax -//FRAGMENT vbuxx=vbuxx_bxor_pbuz1_derefidx_vbuyy -txa -eor ({z1}),y -tax -//FRAGMENT vbuyy=_neg_vbuyy -dey -tya -eor #$ff -tay -//FRAGMENT vwuz1=pbuz1_bxor_vwuc1 -lda #<{c1} -eor {z1} -sta {z1} -lda #>{c1} -eor {z1}+1 -sta {z1}+1 //FRAGMENT vbsz1=vbsz2_plus_vbsc1 lax {z2} axs #-[{c1}] @@ -12482,29 +12272,16 @@ ldy #{c2} tax lda ({z1}),y sta {c1},x -//FRAGMENT pssz1=pssc1 -lda #<{c1} -sta {z1} -lda #>{c1} -sta {z1}+1 -//FRAGMENT pssz1=pssz1_plus_vbuc1 -lda #{c1} -clc -adc {z1} -sta {z1} -bcc !+ -inc {z1}+1 -!: -//FRAGMENT pbuc1_derefidx_vbuaa=pbuz1_derefidx_vbuc2 -ldy #{c2} -tax -lda ({z1}),y -sta {c1},x //FRAGMENT _deref_qssc1=pssc2 lda #<{c2} sta {c1} lda #>{c2} sta {c1}+1 +//FRAGMENT pssz1=pssc1 +lda #<{c1} +sta {z1} +lda #>{c1} +sta {z1}+1 //FRAGMENT pssc1_neq_pssz1_then_la1 lda {z1}+1 cmp #>{c1} @@ -13152,6 +12929,12 @@ lda #{c1} sec sbc {z1} sta {z1} +//FRAGMENT vbuz1=_neg_vbuz1 +lda {z1} +eor #$ff +clc +adc #$01 +sta {z1} //FRAGMENT vbsz1=vbsz2_ror_vbuz3 lda {z2} ldy {z3} @@ -13203,6 +12986,11 @@ bne {la1} tya cmp #0 bne {la1} +//FRAGMENT vbuyy=_neg_vbuyy +dey +tya +eor #$ff +tay //FRAGMENT vbsaa=vbsz1_ror_vbuz2 lda {z1} ldy {z2} @@ -14735,6 +14523,14 @@ sta {z1} lda #0 adc {z2}+1 sta {z1}+1 +//FRAGMENT pssz1=pssz1_plus_vbuc1 +lda #{c1} +clc +adc {z1} +sta {z1} +bcc !+ +inc {z1}+1 +!: //FRAGMENT pssz1_lt_pssc1_then_la1 lda {z1}+1 cmp #>{c1} @@ -14806,6 +14602,11 @@ stx $fe ldx {c1}+1 stx $ff sta ($fe),y +//FRAGMENT pbuc1_derefidx_vbuaa=pbuz1_derefidx_vbuc2 +ldy #{c2} +tax +lda ({z1}),y +sta {c1},x //FRAGMENT pssz1_neq_pssc1_then_la1 lda {z1}+1 cmp #>{c1} @@ -14829,34 +14630,6 @@ sta {z1} iny lda ($fe),y sta {z1}+1 -//FRAGMENT pbuc1_derefidx_vbuz1=pbuc2_derefidx_(_deref_pbuz2) -ldx {z1} -ldy #0 -lda ({z2}),y -tay -lda {c2},y -sta {c1},x -//FRAGMENT pbuc1_derefidx_vbuxx=pbuc2_derefidx_(_deref_pbuz1) -ldy #0 -lda ({z1}),y -tay -lda {c2},y -sta {c1},x -//FRAGMENT pbuc1_derefidx_vbuaa=pbuc2_derefidx_(_deref_pbuz1) -tax -ldy #0 -lda ({z1}),y -tay -lda {c2},y -sta {c1},x -//FRAGMENT pbuc1_derefidx_vbuyy=pbuc2_derefidx_(_deref_pbuz1) -tya -tax -ldy #0 -lda ({z1}),y -tay -lda {c2},y -sta {c1},x //FRAGMENT _deref_pwuc1=vbuc2 lda #0 sta {c1}+1 diff --git a/src/main/fragment/mos6502-common/vwsm1=vwsm2_plus_vbuaa.asm b/src/main/fragment/mos6502-common/vwsm1=vwsm2_plus_vbuaa.asm index 5947cbc49..f5ccc74b7 100644 --- a/src/main/fragment/mos6502-common/vwsm1=vwsm2_plus_vbuaa.asm +++ b/src/main/fragment/mos6502-common/vwsm1=vwsm2_plus_vbuaa.asm @@ -1,6 +1,6 @@ clc -adc {m1} +adc {m2} sta {m1} -lda {m1}+1 +lda {m2}+1 adc #0 sta {m1}+1 diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateSynthesisRule.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateSynthesisRule.java index 7f800db90..2aff2caf0 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateSynthesisRule.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateSynthesisRule.java @@ -355,6 +355,7 @@ class AsmFragmentTemplateSynthesisRule { String lvalC2 = ".*c2.*=.*"; String lvalDerefZM1 = ".*_deref_...[zm]1=.*"; String lvalDerefZM2 = ".*_deref_...[zm]2=.*"; + String lvalDerefZM3 = ".*_deref_...[zm]3=.*"; String lvalDerefC1 = ".*_deref_...c1=.*"; String lvalDerefC2 = ".*_deref_...c2=.*"; String lvalDerefC3 = ".*_deref_...c3=.*"; @@ -651,6 +652,18 @@ class AsmFragmentTemplateSynthesisRule { synths.add(new AsmFragmentTemplateSynthesisRule("(.*z1.*)_deref_pb(.)z1(.*)", rvalAa+"|"+rvalYy+"|"+lvalDerefZM1, "ldy #0\n"+"lda ({z1}),y", "$1vb$2aa$3", null, null)); // Rewrite _deref_pb.z1_ to _vb.aa_ (if other Z1) synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_deref_pb(.)z1(.*[zm]1.*)", rvalAa+"|"+rvalYy+"|"+ lvalDerefZM1, "ldy #0\n"+"lda ({z1}),y", "$1vb$2aa$3", null, null)); + // Rewrite _deref_pb.z2_ to _vb.aa_ (if no other Z2s) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_deref_pb(.)z2(.*)", twoZM2+"|"+rvalAa+"|"+rvalYy+"|"+ lvalDerefZM2, "ldy #0\n"+"lda ({z2}),y", "$1vb$2aa$3", null, mapZM2)); + // Rewrite _deref_pb.z2_ to _vb.aa_ (if other Z2) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*z2.*)_deref_pb(.)z2(.*)", rvalAa+"|"+rvalYy+"|"+lvalDerefZM2, "ldy #0\n"+"lda ({z2}),y", "$1vb$2aa$3", null, null)); + // Rewrite _deref_pb.z2_ to _vb.aa_ (if other Z2) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_deref_pb(.)z2(.*[zm]2.*)", rvalAa+"|"+rvalYy+"|"+ lvalDerefZM2, "ldy #0\n"+"lda ({z2}),y", "$1vb$2aa$3", null, null)); + // Rewrite _deref_pb.z3_ to _vb.aa_ (if no other Z3s) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_deref_pb(.)z3(.*)", twoZM3+"|"+rvalAa+"|"+rvalYy+"|"+ lvalDerefZM3, "ldy #0\n"+"lda ({z3}),y", "$1vb$2aa$3", null, mapZM3)); + // Rewrite _deref_pb.z3_ to _vb.aa_ (if other Z3) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*z3.*)_deref_pb(.)z3(.*)", rvalAa+"|"+rvalYy+"|"+lvalDerefZM3, "ldy #0\n"+"lda ({z3}),y", "$1vb$2aa$3", null, null)); + // Rewrite _deref_pb.z3_ to _vb.aa_ (if other Z3) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_deref_pb(.)z3(.*[zm]3.*)", rvalAa+"|"+rvalYy+"|"+ lvalDerefZM3, "ldy #0\n"+"lda ({z3}),y", "$1vb$2aa$3", null, null)); // Rewrite _deref_pb.m1_ to _vb.aa_ (if no other M1s) synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_deref_pb(.)m1(.*)", twoZM1+"|"+rvalAa+"|"+rvalYy+"|"+lvalDerefZM1, "ldy {m1}\nsty $fe\nldy {m1}+1\nsty $ff\nldy #0\n"+"lda ($fe),y", "$1vb$2aa$3", null, mapZM1)); diff --git a/src/test/kc/complex/lazynes/balloon.c b/src/test/kc/complex/lazynes/balloon.c new file mode 100644 index 000000000..8de8c0166 --- /dev/null +++ b/src/test/kc/complex/lazynes/balloon.c @@ -0,0 +1,40 @@ +// lazyNES balloon demo + +#pragma target(nes) +#include "lazynes.h" + +int lnMain() { + static const ubyte bgColors[]={2,33}; + static const ubyte sprPal0[]={33}; + static const ubyte balloonData[]={ + 0,0,0,0, // balloon is build out of 6 sprites, 4 bytes define a sprite + 8,0,1,0, // x-offset, y-offset, tile, palette + flags + 0,8,2,0, + 8,8,3,0, + 0,16,4,0, + 8,16,5,0, + 128 // end of list marker (important!) + }; + + sword x=0, y=0; + + // To avoid glitches, always write color palettes immediately after lnSync()! + lnSync(lfBlank); // blank screen to enable lnPush() usage + lnSync(lfBlank); // blank screen to enable lnPush() usage + lnPush(lnBackCol,2,bgColors); // set colors, always directly after lnSync()! + lnPush(lnSprPal0,1,sprPal0); // set sprite colors + + while(1) { + ubyte j=lnGetPad(1); // query 1st joypad + if (0==j) { // automatic movement? + x+=1; if (x>=240) x=0; + y+=1; if (y>=240) y=0; + } + if (j&lfL) x-=1; else if (j&lfR) x+=1; // move left/right? + if (j&lfU) y-=1; else if (j&lfD) y+=1; // move up/down? + lnAddSpr(balloonData,x,y); // add meta sprite to display list + lnSync(0); // sync with vblank + } + + return 0; +} diff --git a/src/test/kc/complex/lazynes/lazyhello.c b/src/test/kc/complex/lazynes/lazyhello.c index eaf412d6d..a04c489fe 100644 --- a/src/test/kc/complex/lazynes/lazyhello.c +++ b/src/test/kc/complex/lazynes/lazyhello.c @@ -3,6 +3,7 @@ // Ported to KickC 2020 by Jesper Gravgaard // Original Source VBCC alpha 2 http://www.ibaug.de/vbcc/vbcc6502_2.zip +#pragma target(nes) #include "lazynes.h" int lnMain() { diff --git a/src/test/kc/complex/lazynes/lazymain.c b/src/test/kc/complex/lazynes/lazymain.c deleted file mode 100644 index 41ef9aa89..000000000 --- a/src/test/kc/complex/lazynes/lazymain.c +++ /dev/null @@ -1,62 +0,0 @@ -// lazyNES lazyhello demo -// Main file - -// Ported to KickC 2020 by Jesper Gravgaard -// Original Source VBCC aplha 2 http://www.ibaug.de/vbcc/vbcc6502_2.zip - -#pragma target(nes) -#include -#include -#include "lazynes.c" -#include "balloon.c" - -// RESET Called when the NES is reset, including when it is turned on. -void main() { - // Initialize NES after RESET - initNES(); - // Clear the name table - ppuDataFill(PPU_NAME_TABLE_0, 0, 0x3c0); - // Fill the PPU attribute table - ppuDataFill(PPU_ATTRIBUTE_TABLE_0, 0, 0x40); - // Enable screen rendering and vblank - enableVideoOutput(); - // Execute main code - lnMain(); - // Infinite loop - while(1) ; -} - -// NMI Called when the PPU refreshes the screen (also known as the V-Blank period) -interrupt(hardware_stack) void vblank() { - // DMA transfer the entire sprite buffer to the PPU - ppuSpriteBufferDmaTransfer(SPRITE_BUFFER); - // Set scroll - PPU->PPUSCROLL = 0; - PPU->PPUSCROLL = 0; -} - -// Data (in PRG ROM) -#pragma data_seg(Data) - -// Tile Set (in CHR ROM) -#pragma data_seg(Tiles) -export char TILES[] = kickasm(resource "example.chr", resource "sprites.chr") {{ - .import binary "example.chr" - .import binary "sprites.chr" -}}; - -// Sprite Buffer (in GAME RAM) -// Will be transferred to the PPU via DMA during vblank -#pragma data_seg(GameRam) -struct SpriteData align(0x100) SPRITE_BUFFER[0x40]; - -// Interrupt Vectors (in PRG ROM) -#pragma data_seg(Vectors) -export void()* const VECTORS[] = { - // NMI Called when the PPU refreshes the screen (also known as the V-Blank period) - &vblank, - // RESET Called when the NES is reset, including when it is turned on. - &main, - // IRQ Called when a BRK instruction is executed. - 0 -}; diff --git a/src/test/kc/complex/lazynes/lazynes.c b/src/test/kc/complex/lazynes/lazynes.c index e66dcc9f2..28303c4d8 100644 --- a/src/test/kc/complex/lazynes/lazynes.c +++ b/src/test/kc/complex/lazynes/lazynes.c @@ -7,14 +7,85 @@ #include "lazynes.h" #include +// Tile Set (in CHR ROM) +#pragma data_seg(Tiles) +export char TILES[] = kickasm(resource "example.chr", resource "sprites.chr") {{ + .import binary "example.chr" + .import binary "sprites.chr" +}}; + + +// Interrupt Vectors (in PRG ROM) +#pragma data_seg(Vectors) +export void()* const VECTORS[] = { + // NMI Called when the PPU refreshes the screen (also known as the V-Blank period) + &vblank, + // RESET Called when the NES is reset, including when it is turned on. + &main, + // IRQ Called when a BRK instruction is executed. + 0 +}; + +// RESET Called when the NES is reset, including when it is turned on. +void main() { + // Initialize NES after RESET + initNES(); + // Clear the name table + ppuDataFill(PPU_NAME_TABLE_0, 0, 0x3c0); + // Fill the PPU attribute table + ppuDataFill(PPU_ATTRIBUTE_TABLE_0, 0, 0x40); + // move all sprites off the screen + for(char i=0;i!=0x40;i++) + SPRITE_BUFFER[i].y = 0xff; + // Enable screen rendering and vblank + // Set sprite tileset to upper - enable vblank NMI + PPU->PPUCTRL = 0b10001000; + // Enable sprite and tile rendering + PPU->PPUMASK = 0b00011110; + // Execute lazynes main code + lnMain(); + // Infinite loop + while(1) ; +} + +// Sprite Buffer (in GAME RAM) +// Will be transferred to the PPU via DMA during vblank +#pragma data_seg(GameRam) +struct SpriteData align(0x100) SPRITE_BUFFER[0x40]; + +// Data (in PRG ROM) +#pragma data_seg(Data) + +// Index of the next SpriteData in SPRITE_BUFFER to write to in lnAddSpr() +volatile char add_sprite_idx; + +// NMI Called when the PPU refreshes the screen (also known as the V-Blank period) +interrupt(hardware_stack) void vblank() { + // DMA transfer the entire sprite buffer to the PPU + ppuSpriteBufferDmaTransfer(SPRITE_BUFFER); + // Set scroll + PPU->PPUSCROLL = 0; + PPU->PPUSCROLL = 0; + // move all sprites off the screen + //for(char i=0;i!=0x40;i++) + // SPRITE_BUFFER[i].y = 0xff; + // Reset the index of sprites to add + add_sprite_idx = 0; +} + // Wait for next vblank // flags: 0, lfBlank or lfSplit (see below) // result: Amount of frames since last sync [0..31], 128 is added on NTSC // ubyte lnSync(ubyte flags) { // Enable video output if lfBlank not set - if(!(flags&lfBlank)) - enableVideoOutput(); + if(!(flags&lfBlank)) { + // Set sprite tileset to upper - enable vblank NMI + PPU->PPUCTRL = 0b10001000; + // Enable sprite and tile rendering + PPU->PPUMASK = 0b00011110; + } + // Wait for V-Blank waitForVBlank(); // Disable video output if lfBlank set @@ -72,15 +143,23 @@ void lnPush(uword o, ubyte a, void* s) { // p: Pointer to metasprite data // x,y: Sprite coordinates // result: New position offset in OAM after the meta sprite has been added -// -// TODO: ubyte lnAddSpr(void* p, sword x, sword y); - // - // remarks: - // - The format for the metasprite data is an array of unsigned bytes. - // - Four bytes per sprite: x-offset, y-offset, tile, attributes - // - The end of the list is marked by the value 128! (important!) - // - It's the same format that's used in oam_meta_spr() from Shiru's neslib - +// remarks: +// - The format for the metasprite data is an array of unsigned bytes. +// - Four bytes per sprite: x-offset, y-offset, tile, attributes +// - The end of the list is marked by the value 128! (important!) +// - It's the same format that's used in oam_meta_spr() from Shiru's neslib +ubyte lnAddSpr(void* p, sword x, sword y) { + char* ptr = p; + while(*ptr!=128) { + SPRITE_BUFFER[add_sprite_idx].x = (char) (x+ptr[0]); + SPRITE_BUFFER[add_sprite_idx].y = (char) (y+ptr[1]); + SPRITE_BUFFER[add_sprite_idx].tile = ptr[2]; + SPRITE_BUFFER[add_sprite_idx].attributes = ptr[3]; + ptr+=4; + add_sprite_idx++; + } + return add_sprite_idx*4; +} // Query joypad state // port: Joypad port (1 or 2) @@ -94,10 +173,10 @@ ubyte lnGetPad(ubyte port) { // advanced usage // -__zp volatile ubyte - lnSpr0Wait, // delay until scroll registers will be set after a SPR0HIT - lnPPUCTRL, // current value of PPUCTRL register (will be written in NMI) - lnPPUMASK; // current value of PPUMASK register (will be written in NMI) +// TODO: __zp volatile ubyte +// TODO: lnSpr0Wait, // delay until scroll registers will be set after a SPR0HIT +// TODO: lnPPUCTRL, // current value of PPUCTRL register (will be written in NMI) +// TODO: lnPPUMASK; // current value of PPUMASK register (will be written in NMI) // // remark: The lazyNES NMI will write the PPUCTRL and PPUMASK registers, // so don't write PPUCTRL and PPUMASK directly - use these two diff --git a/src/test/kc/complex/lazynes/lazynes.h b/src/test/kc/complex/lazynes/lazynes.h index 093761a65..0665d9c51 100644 --- a/src/test/kc/complex/lazynes/lazynes.h +++ b/src/test/kc/complex/lazynes/lazynes.h @@ -10,6 +10,11 @@ typedef unsigned char ubyte; typedef signed short sword; 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(); + // Wait for next vblank // flags: 0, lfBlank or lfSplit (see below) // result: Amount of frames since last sync [0..31], 128 is added on NTSC @@ -74,7 +79,7 @@ enum { // x,y: Sprite coordinates // result: New position offset in OAM after the meta sprite has been added // -// TODO: ubyte lnAddSpr(void* p, sword x, sword y); +ubyte lnAddSpr(void* p, sword x, sword y); // // remarks: // - The format for the metasprite data is an array of unsigned bytes. @@ -94,10 +99,10 @@ enum { lfU=8, lfD=4, lfL=2, lfR=1, lfA=128, lfB=64, lfStart=16, lfSelect=32 }; // advanced usage // -extern __zp volatile ubyte - lnSpr0Wait, // delay until scroll registers will be set after a SPR0HIT - lnPPUCTRL, // current value of PPUCTRL register (will be written in NMI) - lnPPUMASK; // current value of PPUMASK register (will be written in NMI) +// TODO: extern __zp volatile ubyte +// TODO: lnSpr0Wait, // delay until scroll registers will be set after a SPR0HIT +// TODO: lnPPUCTRL, // current value of PPUCTRL register (will be written in NMI) +// TODO: lnPPUMASK; // current value of PPUMASK register (will be written in NMI) // // remark: The lazyNES NMI will write the PPUCTRL and PPUMASK registers, // so don't write PPUCTRL and PPUMASK directly - use these two diff --git a/src/test/ref/complex/polygon/polygon.asm b/src/test/ref/complex/polygon/polygon.asm index f2ff7e00a..609a749ca 100644 --- a/src/test/ref/complex/polygon/polygon.asm +++ b/src/test/ref/complex/polygon/polygon.asm @@ -873,7 +873,7 @@ eorfill: { iny jmp __b3 } -// Get the absolute value of a u-bit unsigned number treated as a signed number. +// Get the absolute value of a 8-bit unsigned number treated as a signed number. // abs_u8(byte register(A) u) abs_u8: { // u & 0x80 diff --git a/src/test/ref/complex/polygon/polygon.log b/src/test/ref/complex/polygon/polygon.log index d56c8b19c..040dab9e8 100644 --- a/src/test/ref/complex/polygon/polygon.log +++ b/src/test/ref/complex/polygon/polygon.log @@ -5577,7 +5577,7 @@ eorfill: { jmp __b3 } // abs_u8 -// Get the absolute value of a u-bit unsigned number treated as a signed number. +// Get the absolute value of a 8-bit unsigned number treated as a signed number. // abs_u8(byte zp($23) u) abs_u8: { .label __0 = $5c @@ -7450,7 +7450,7 @@ eorfill: { jmp __b3 } // abs_u8 -// Get the absolute value of a u-bit unsigned number treated as a signed number. +// Get the absolute value of a 8-bit unsigned number treated as a signed number. // abs_u8(byte register(A) u) abs_u8: { // [212] (byte~) abs_u8::$0 ← (byte) abs_u8::u#2 & (byte) $80 -- vbuxx=vbuaa_band_vbuc1 @@ -9536,7 +9536,7 @@ eorfill: { jmp __b3 } // abs_u8 -// Get the absolute value of a u-bit unsigned number treated as a signed number. +// Get the absolute value of a 8-bit unsigned number treated as a signed number. // abs_u8(byte register(A) u) abs_u8: { // u & 0x80 diff --git a/src/test/ref/global-label-problem.log b/src/test/ref/global-label-problem.log index 566032371..6780b68a4 100644 --- a/src/test/ref/global-label-problem.log +++ b/src/test/ref/global-label-problem.log @@ -398,10 +398,10 @@ print: { // print::@2 __b2: // [11] *((const nomodify byte*) SCREEN + (byte) idx#19) ← *((byte*) print::msg#5) -- pbuc1_derefidx_vbuz1=_deref_pbuz2 - ldx.z idx ldy #0 lda (msg),y - sta SCREEN,x + ldy.z idx + sta SCREEN,y // [12] (byte) idx#7 ← ++ (byte) idx#19 -- vbuz1=_inc_vbuz1 inc.z idx // [13] (byte*) print::msg#4 ← ++ (byte*) print::msg#5 -- pbuz1=_inc_pbuz1 diff --git a/src/test/ref/pointer-void-1.log b/src/test/ref/pointer-void-1.log index 36be44386..35bf18632 100644 --- a/src/test/ref/pointer-void-1.log +++ b/src/test/ref/pointer-void-1.log @@ -315,10 +315,10 @@ main: { print: { .label ptr = 2 // [10] *((const nomodify byte*) SCREEN + (byte) idx#13) ← *((byte*)(void*) print::ptr#3) -- pbuc1_derefidx_vbuz1=_deref_pbuz2 - ldx.z idx ldy #0 lda (ptr),y - sta SCREEN,x + ldy.z idx + sta SCREEN,y // [11] (byte) idx#14 ← ++ (byte) idx#13 -- vbuz1=_inc_vbuz1 inc.z idx jmp __breturn diff --git a/src/test/ref/pointer-void-2.log b/src/test/ref/pointer-void-2.log index 4f8faafe3..64e04a784 100644 --- a/src/test/ref/pointer-void-2.log +++ b/src/test/ref/pointer-void-2.log @@ -309,10 +309,10 @@ main: { print: { .label ptr = 2 // [10] *((const nomodify byte*) SCREEN + (byte) idx#13) ← *((byte*)(void*) print::ptr#3) -- pbuc1_derefidx_vbuz1=_deref_pbuz2 - ldx.z idx ldy #0 lda (ptr),y - sta SCREEN,x + ldy.z idx + sta SCREEN,y // [11] (byte) idx#14 ← ++ (byte) idx#13 -- vbuz1=_inc_vbuz1 inc.z idx jmp __breturn diff --git a/src/test/ref/procedure-callingconvention-stack-12.asm b/src/test/ref/procedure-callingconvention-stack-12.asm index 683ad6f87..d9daab942 100644 --- a/src/test/ref/procedure-callingconvention-stack-12.asm +++ b/src/test/ref/procedure-callingconvention-stack-12.asm @@ -38,10 +38,10 @@ print: { rts __b2: // SCREEN[idx++] = *(str++) - ldx.z idx ldy #0 lda (str),y - sta SCREEN,x + ldy.z idx + sta SCREEN,y // SCREEN[idx++] = *(str++); inc.z idx inc.z str diff --git a/src/test/ref/procedure-callingconvention-stack-12.log b/src/test/ref/procedure-callingconvention-stack-12.log index 0773e144d..b15a99bbf 100644 --- a/src/test/ref/procedure-callingconvention-stack-12.log +++ b/src/test/ref/procedure-callingconvention-stack-12.log @@ -332,10 +332,10 @@ print: { // print::@2 __b2: // [10] *((const nomodify byte*) SCREEN + (byte) idx) ← *((byte*) print::str#2) -- pbuc1_derefidx_vbuz1=_deref_pbuz2 - ldx.z idx ldy #0 lda (str),y - sta SCREEN,x + ldy.z idx + sta SCREEN,y // [11] (byte) idx ← ++ (byte) idx -- vbuz1=_inc_vbuz1 inc.z idx // [12] (byte*) print::str#1 ← ++ (byte*) print::str#2 -- pbuz1=_inc_pbuz1 @@ -424,8 +424,7 @@ Statement [6] (byte) print::spacing#0 ← stackidx(byte,(const byte) print::OFFS Statement [8] if((byte) 0!=*((byte*) print::str#2)) goto print::@2 [ idx print::spacing#0 print::str#2 ] ( main:3::print:20 [ idx print::spacing#0 print::str#2 ] { } main:3::print:24 [ idx print::spacing#0 print::str#2 ] { } ) always clobbers reg byte a reg byte y Removing always clobbered register reg byte a as potential for zp[1]:6 [ print::spacing#0 ] Removing always clobbered register reg byte y as potential for zp[1]:6 [ print::spacing#0 ] -Statement [10] *((const nomodify byte*) SCREEN + (byte) idx) ← *((byte*) print::str#2) [ idx print::spacing#0 print::str#2 ] ( main:3::print:20 [ idx print::spacing#0 print::str#2 ] { } main:3::print:24 [ idx print::spacing#0 print::str#2 ] { } ) always clobbers reg byte a reg byte x reg byte y -Removing always clobbered register reg byte x as potential for zp[1]:6 [ print::spacing#0 ] +Statement [10] *((const nomodify byte*) SCREEN + (byte) idx) ← *((byte*) print::str#2) [ idx print::spacing#0 print::str#2 ] ( main:3::print:20 [ idx print::spacing#0 print::str#2 ] { } main:3::print:24 [ idx print::spacing#0 print::str#2 ] { } ) always clobbers reg byte a reg byte y Statement [15] *((const nomodify byte*) SCREEN + (byte) idx) ← (byte) ' ' [ idx print::spacing#0 print::str#1 print::c#2 ] ( main:3::print:20 [ idx print::spacing#0 print::str#1 print::c#2 ] { } main:3::print:24 [ idx print::spacing#0 print::str#1 print::c#2 ] { } ) always clobbers reg byte a reg byte y Removing always clobbered register reg byte a as potential for zp[1]:4 [ print::c#2 print::c#1 ] Removing always clobbered register reg byte y as potential for zp[1]:4 [ print::c#2 print::c#1 ] @@ -439,7 +438,7 @@ Statement [1] (byte) idx ← (byte) 0 [ idx ] ( [ idx ] { } ) always clobbers Statement [5] (byte*) print::str#0 ← stackidx(byte*,(const byte) print::OFFSET_STACK_STR) [ idx print::str#0 ] ( main:3::print:20 [ idx print::str#0 ] { } main:3::print:24 [ idx print::str#0 ] { } ) always clobbers reg byte a reg byte x Statement [6] (byte) print::spacing#0 ← stackidx(byte,(const byte) print::OFFSET_STACK_SPACING) [ idx print::str#0 print::spacing#0 ] ( main:3::print:20 [ idx print::str#0 print::spacing#0 ] { } main:3::print:24 [ idx print::str#0 print::spacing#0 ] { } ) always clobbers reg byte a reg byte x Statement [8] if((byte) 0!=*((byte*) print::str#2)) goto print::@2 [ idx print::spacing#0 print::str#2 ] ( main:3::print:20 [ idx print::spacing#0 print::str#2 ] { } main:3::print:24 [ idx print::spacing#0 print::str#2 ] { } ) always clobbers reg byte a reg byte y -Statement [10] *((const nomodify byte*) SCREEN + (byte) idx) ← *((byte*) print::str#2) [ idx print::spacing#0 print::str#2 ] ( main:3::print:20 [ idx print::spacing#0 print::str#2 ] { } main:3::print:24 [ idx print::spacing#0 print::str#2 ] { } ) always clobbers reg byte a reg byte x reg byte y +Statement [10] *((const nomodify byte*) SCREEN + (byte) idx) ← *((byte*) print::str#2) [ idx print::spacing#0 print::str#2 ] ( main:3::print:20 [ idx print::spacing#0 print::str#2 ] { } main:3::print:24 [ idx print::spacing#0 print::str#2 ] { } ) always clobbers reg byte a reg byte y Statement [15] *((const nomodify byte*) SCREEN + (byte) idx) ← (byte) ' ' [ idx print::spacing#0 print::str#1 print::c#2 ] ( main:3::print:20 [ idx print::spacing#0 print::str#1 print::c#2 ] { } main:3::print:24 [ idx print::spacing#0 print::str#1 print::c#2 ] { } ) always clobbers reg byte a reg byte y Statement [18] stackpush(byte*) ← (const byte*) main::str [ idx ] ( main:3 [ idx ] { } ) always clobbers reg byte a Statement [19] stackpush(byte) ← (byte) 1 [ idx ] ( main:3 [ idx ] { } ) always clobbers reg byte a @@ -450,7 +449,7 @@ Statement sideeffect stackpullbytes((number) 3) always clobbers reg byte a reg b Potential registers zp[2]:2 [ print::str#2 print::str#0 print::str#1 ] : zp[2]:2 , Potential registers zp[1]:4 [ print::c#2 print::c#1 ] : zp[1]:4 , reg byte x , Potential registers zp[1]:5 [ idx ] : zp[1]:5 , -Potential registers zp[1]:6 [ print::spacing#0 ] : zp[1]:6 , +Potential registers zp[1]:6 [ print::spacing#0 ] : zp[1]:6 , reg byte x , REGISTER UPLIFT SCOPES Uplift Scope [print] 27,502.75: zp[1]:4 [ print::c#2 print::c#1 ] 5,210.92: zp[2]:2 [ print::str#2 print::str#0 print::str#1 ] 918.36: zp[1]:6 [ print::spacing#0 ] @@ -539,10 +538,10 @@ print: { // print::@2 __b2: // [10] *((const nomodify byte*) SCREEN + (byte) idx) ← *((byte*) print::str#2) -- pbuc1_derefidx_vbuz1=_deref_pbuz2 - ldx.z idx ldy #0 lda (str),y - sta SCREEN,x + ldy.z idx + sta SCREEN,y // [11] (byte) idx ← ++ (byte) idx -- vbuz1=_inc_vbuz1 inc.z idx // [12] (byte*) print::str#1 ← ++ (byte*) print::str#2 -- pbuz1=_inc_pbuz1 @@ -746,10 +745,10 @@ print: { __b2: // SCREEN[idx++] = *(str++) // [10] *((const nomodify byte*) SCREEN + (byte) idx) ← *((byte*) print::str#2) -- pbuc1_derefidx_vbuz1=_deref_pbuz2 - ldx.z idx ldy #0 lda (str),y - sta SCREEN,x + ldy.z idx + sta SCREEN,y // SCREEN[idx++] = *(str++); // [11] (byte) idx ← ++ (byte) idx -- vbuz1=_inc_vbuz1 inc.z idx diff --git a/src/test/ref/struct-ptr-28.log b/src/test/ref/struct-ptr-28.log index eaf898cb6..087ac68e2 100644 --- a/src/test/ref/struct-ptr-28.log +++ b/src/test/ref/struct-ptr-28.log @@ -407,12 +407,12 @@ print_person: { .label i = 5 .label person = 2 // [6] *((const nomodify byte*) SCREEN + (byte) idx#14) ← *((const byte*) DIGIT + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_(_deref_pbuz2) - ldx.z idx_2 ldy #0 lda (person),y tay lda DIGIT,y - sta SCREEN,x + ldy.z idx_2 + sta SCREEN,y // [7] (byte) idx#3 ← ++ (byte) idx#14 -- vbuz1=_inc_vbuz2 ldy.z idx_2 iny diff --git a/src/test/ref/struct-ptr-31.log b/src/test/ref/struct-ptr-31.log index f90dcbb53..59d3e1269 100644 --- a/src/test/ref/struct-ptr-31.log +++ b/src/test/ref/struct-ptr-31.log @@ -380,12 +380,12 @@ print_person: { .label i = 5 .label person = 2 // [6] *((const nomodify byte*) SCREEN + (byte) idx#14) ← *((const byte*) DIGIT + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_(_deref_pbuz2) - ldx.z idx_2 ldy #0 lda (person),y tay lda DIGIT,y - sta SCREEN,x + ldy.z idx_2 + sta SCREEN,y // [7] (byte) idx#3 ← ++ (byte) idx#14 -- vbuz1=_inc_vbuz2 ldy.z idx_2 iny diff --git a/src/test/ref/struct-ptr-4.log b/src/test/ref/struct-ptr-4.log index 34bf7ef35..10be2ee2f 100644 --- a/src/test/ref/struct-ptr-4.log +++ b/src/test/ref/struct-ptr-4.log @@ -382,10 +382,10 @@ main: { // main::@2 __b2: // [9] *((const nomodify byte*) main::SCREEN + (byte) main::idx#4) ← *((byte*)(struct Point*) main::points#5) -- pbuc1_derefidx_vbuz1=_deref_pbuz2 - ldx.z idx_2 ldy #0 lda (points_1),y - sta SCREEN,x + ldy.z idx_2 + sta SCREEN,y // [10] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuz1=_inc_vbuz2 ldy.z idx_2 iny