From dbaea056236a26107ec063aae3731cf3f343688e Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Wed, 16 Dec 2020 22:24:38 +0100 Subject: [PATCH] Added a sprite CX16 example. #581 --- .../cache/fragment-cache-wdc65c02.asm | 155 ++ src/main/kc/include/cx16-vera.h | 39 +- src/main/kc/include/cx16.h | 7 + src/main/kc/lib/cx16.c | 19 +- .../dk/camelot64/kickc/test/TestPrograms.java | 5 + src/test/kc/examples/cx16/sprite.c | 68 + src/test/kc/examples/cx16/sprite.png | Bin 0 -> 650 bytes src/test/ref/examples/cx16/rasterbars.log | 2 + src/test/ref/examples/cx16/sprite.asm | 337 ++++ src/test/ref/examples/cx16/sprite.cfg | 103 ++ src/test/ref/examples/cx16/sprite.log | 1632 +++++++++++++++++ src/test/ref/examples/cx16/sprite.sym | 71 + src/test/ref/examples/cx16/text.asm | 5 +- src/test/ref/examples/cx16/text.log | 27 +- 14 files changed, 2454 insertions(+), 16 deletions(-) create mode 100644 src/test/kc/examples/cx16/sprite.c create mode 100644 src/test/kc/examples/cx16/sprite.png create mode 100644 src/test/ref/examples/cx16/sprite.asm create mode 100644 src/test/ref/examples/cx16/sprite.cfg create mode 100644 src/test/ref/examples/cx16/sprite.log create mode 100644 src/test/ref/examples/cx16/sprite.sym diff --git a/src/main/fragment/cache/fragment-cache-wdc65c02.asm b/src/main/fragment/cache/fragment-cache-wdc65c02.asm index 5079ca8cb..b6e596087 100644 --- a/src/main/fragment/cache/fragment-cache-wdc65c02.asm +++ b/src/main/fragment/cache/fragment-cache-wdc65c02.asm @@ -315,3 +315,158 @@ 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 +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 +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 +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 diff --git a/src/main/kc/include/cx16-vera.h b/src/main/kc/include/cx16-vera.h index b3d77b94f..9b7021115 100644 --- a/src/main/kc/include/cx16-vera.h +++ b/src/main/kc/include/cx16-vera.h @@ -81,6 +81,14 @@ char * const VERA_IRQLINE_L = 0x9f28; // Bit 2: Chroma Disable Setting 'Chroma Disable' disables output of chroma in NTSC composite mode and will give a better picture on a monochrome display. (Setting this bit will also disable the chroma output on the S-video output.) // Bit 0-1: Output Mode 0: Video disabled, 1: VGA output, 2: NTSC composite, 3: RGB interlaced, composite sync (via VGA connector) char * const VERA_DC_VIDEO = 0x9f29; +char VERA_SPRITES_ENABLE = 0x40; +char VERA_LAYER1_ENABLE = 0x20; +char VERA_LAYER0_ENABLE = 0x10; +char VERA_CROMA_DISABLE = 0x04; +char VERA_OUTPUT_DISABLE = 0x00; +char VERA_OUTPUT_VGA = 0x01; +char VERA_OUTPUT_NTSC = 0x02; +char VERA_OUTPUT_RGB = 0x03; // $9F2A DC_HSCALE (DCSEL=0) Active Display H-Scale char * const VERA_DC_HSCALE = 0x9f2a; // $9F2B DC_VSCALE (DCSEL=0) Active Display V-Scale @@ -155,4 +163,33 @@ char * const VERA_SPI_DATA = 0x9f3e; // Bit 7: Busy // Bit 1: Slow clock // Bit 0: Select -char * const VERA_SPI_CTRL = 0x9f3f; \ No newline at end of file +char * const VERA_SPI_CTRL = 0x9f3f; + +// Sprite Attributes address in VERA VRAM +const unsigned long VERA_SPRITE_ATTR = 0x1fc00; + +// The VERA structure of a sprite (8 bytes) +// 128*8 bytes located at $1FC00-$1FFFF +struct VERA_SPRITE { + // 0-1 ADDRESS Address and mode + // - bits 0-11: Address (16:5) + // - bits 15: Mode (0:4 bpp 1:8 bpp) + unsigned int ADDR; + // 2-3 X (9:0) + unsigned int X; + // 4-5 Y (9:0) + unsigned int Y; + // 6 CTRL1 Control 1 + // - bits 4-7 Collision mask + // - bits 2-3 Z-depth ( 0:Sprite disabled, 1:Sprite between background and layer 0, 2:Sprite between layer 0 and layer 1, 3:Sprite in front of layer 1 ) + // - bits 1 V-flip + // - bits 0 H-flip + char CTRL1; + // 7 CTRL2 Control 2 + // - bits 6-7 Sprite height ( 0:8 pixels, 1:16 pixels, 2:32 pixels, 3:64 pixels ) + // - bits 4-5 Sprite width ( 0:8 pixels, 1:16 pixels, 2:32 pixels, 3:64 pixels ) + // - bits 0-3 Palette offset (if 4bpp Color index 1-15 is modified by adding 16 x palette offset) + char CTRL2; +}; +// 8BPP sprite mode (add to VERA_SPRITE.ADDR to enable) +const unsigned int VERA_SPRITE_8BPP = 0x8000; diff --git a/src/main/kc/include/cx16.h b/src/main/kc/include/cx16.h index 6e27ea1db..497e56fde 100644 --- a/src/main/kc/include/cx16.h +++ b/src/main/kc/include/cx16.h @@ -47,6 +47,13 @@ char * const DEFAULT_SCREEN_VBANK = 0; // - data: The data to put into VRAM void vpoke(char vbank, char* vaddr, char data); +// Read a single byte from VRAM. +// Uses VERA DATA0 +// - bank: Which 64K VRAM bank to put data into (0/1) +// - addr: The address in VRAM +// - returns: The data to put into VRAM +char vpeek(char vbank, char* vaddr); + // Copy block of memory (from RAM to VRAM) // Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination in VRAM. // - vbank: Which 64K VRAM bank to put data into (0/1) diff --git a/src/main/kc/lib/cx16.c b/src/main/kc/lib/cx16.c index 0570f200b..0fe122b36 100644 --- a/src/main/kc/lib/cx16.c +++ b/src/main/kc/lib/cx16.c @@ -20,6 +20,22 @@ void vpoke(char vbank, char* vaddr, char data) { *VERA_DATA0 = data; } +// Read a single byte from VRAM. +// Uses VERA DATA0 +// - bank: Which 64K VRAM bank to put data into (0/1) +// - addr: The address in VRAM +// - returns: The data to put into VRAM +char vpeek(char vbank, char* vaddr) { + // Select DATA0 + *VERA_CTRL &= ~VERA_ADDRSEL; + // Set address + *VERA_ADDRX_L = vaddr; + *VERA_ADDRX_H = VERA_INC_0 | vbank; + // Get data + return *VERA_DATA0; +} + // Copy block of memory (from RAM to VRAM) // Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination in VRAM. // - vbank: Which 64K VRAM bank to put data into (0/1) @@ -34,8 +50,7 @@ void memcpy_to_vram(char vbank, void* vdest, void* src, unsigned int num ) { *VERA_ADDRX_M = >vdest; *VERA_ADDRX_H = VERA_INC_1 | vbank; // Transfer the data - char *s = src; char *end = (char*)src+num; - for(; s!=end; s++) + for(char *s = src; s!=end; s++) *VERA_DATA0 = *s; } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index dd4b0b1de..218950f1c 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -463,6 +463,11 @@ public class TestPrograms { compileAndCompare("examples/nes/nes-demo.c"); } + @Test + public void testCx16Sprite() throws IOException, URISyntaxException { + compileAndCompare("examples/cx16/sprite.c"); + } + @Test public void testCx16Text() throws IOException, URISyntaxException { compileAndCompare("examples/cx16/text.c"); diff --git a/src/test/kc/examples/cx16/sprite.c b/src/test/kc/examples/cx16/sprite.c new file mode 100644 index 000000000..04822136b --- /dev/null +++ b/src/test/kc/examples/cx16/sprite.c @@ -0,0 +1,68 @@ +// Example program for the Commander X16 +// Displays a sprite + +#pragma target(cx16) +#include +#include <6502.h> + +// A 64*64 8bpp sprite +align(0x100) char SPRITE_PIXELS[64*64] = kickasm(resource "sprite.png") {{ + .var pic = LoadPicture("sprite.png", List().add($000000, $ffffff)) + .for (var x=0;x<64; x++) + .for (var y=0; y<64; y++) + .byte (pic.getPixel(x,y)==0) ? 0 : 1 +}}; + +// Address to use for sprite pixels in VRAM +const unsigned long SPRITE_PIXELS_VRAM = 0x08000; + +// Sprite attributes: 8bpp, in front, 64x64, address SPRITE_PIXELS_VRAM +struct VERA_SPRITE SPRITE_ATTR = { <(SPRITE_PIXELS_VRAM/32)|VERA_SPRITE_8BPP, 320-32, 240-32, 0x0c, 0xf0 }; + +// X sine [0;640-64] +align(0x100) unsigned int SINX[241] = kickasm {{ + .fillword 256, 288+288*sin(i*2*PI/241) +}}; + +// Y sine [0;480-64] +align(0x100) unsigned int SINY[251] = kickasm {{ + .fillword 256, 208+208*sin(i*2*PI/251) +}}; + +void main() { + // Copy sprite data to VRAM + memcpy_to_vram((char)>SPRITE_PIXELS_VRAM, VERA_SPRITE_ATTR, VERA_SPRITE_ATTR, z-uk`Y=&_cpktU;h*)CPTCD#Hx-u$jfeBHn9^roEOueFnJm#n;2`q#_WLe*L|$6aoxi*wv}InH+HeXzfK`GX)1 zErz`v>l;6CEHMALR3MM>i`G6CCozZjkG2YIV%Txu#Ydq78h6t_zx!uY!yw`NN4SNb zVUB?6JcgcIwPv5QwC6BG{-(2o`TV{Qd@~r7qT;jW@l7yMlJjSGd9&+^jjTeZi%s3he7A`VAEZCrVVbzB zZfU6%L&zdq_8tEh)><)$DD@v^4BXbZ#a^nOq2pDPaKpve31#(G53;y>UNxc zdt<(wd(76ry4hjQV|mT~i%GuMp7J$tE1x=4xQ;c*n%~mPJ(wZWaOH+CR_C`asMxRi Zk7;Ar=cHU$HV;sm@O1TaS?83{1OQEN00#g7 literal 0 HcmV?d00001 diff --git a/src/test/ref/examples/cx16/rasterbars.log b/src/test/ref/examples/cx16/rasterbars.log index 1cf37d703..02669aeba 100644 --- a/src/test/ref/examples/cx16/rasterbars.log +++ b/src/test/ref/examples/cx16/rasterbars.log @@ -862,6 +862,7 @@ REGISTER UPLIFT SCOPES Uplift Scope [irq_line] 370.33: zp[1]:5 [ irq_line::i2#2 irq_line::i2#1 ] 353.5: zp[1]:6 [ irq_line::i#2 irq_line::i#1 ] 353.5: zp[1]:7 [ irq_line::i1#2 irq_line::i1#1 ] 26.12: zp[1]:3 [ irq_line::b#2 irq_line::b#1 ] 26: zp[1]:2 [ irq_line::l#2 irq_line::l#1 ] 22.4: zp[2]:16 [ irq_line::bar#0 ] 18: zp[1]:4 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ] Uplift Scope [memset] 336.67: zp[2]:8 [ memset::dst#2 memset::dst#1 ] Uplift Scope [] 0.53: zp[1]:14 [ cnt ] 0.45: zp[1]:10 [ hstart ] 0.35: zp[1]:11 [ hstop ] 0.33: zp[1]:12 [ vstart ] 0.32: zp[1]:13 [ vstop ] 0.28: zp[1]:15 [ sin_idx ] +Uplift Scope [VERA_SPRITE] Uplift Scope [MOS6522_VIA] Uplift Scope [main] Uplift Scope [__start] @@ -870,6 +871,7 @@ Uplifting [irq_line] best 8197 combination reg byte y [ irq_line::i2#2 irq_line: Limited combination testing to 100 combinations of 1296 possible. Uplifting [memset] best 8197 combination zp[2]:8 [ memset::dst#2 memset::dst#1 ] Uplifting [] best 8197 combination zp[1]:14 [ cnt ] zp[1]:10 [ hstart ] zp[1]:11 [ hstop ] zp[1]:12 [ vstart ] zp[1]:13 [ vstop ] zp[1]:15 [ sin_idx ] +Uplifting [VERA_SPRITE] best 8197 combination Uplifting [MOS6522_VIA] best 8197 combination Uplifting [main] best 8197 combination Uplifting [__start] best 8197 combination diff --git a/src/test/ref/examples/cx16/sprite.asm b/src/test/ref/examples/cx16/sprite.asm new file mode 100644 index 000000000..f24fdcbb4 --- /dev/null +++ b/src/test/ref/examples/cx16/sprite.asm @@ -0,0 +1,337 @@ +// Example program for the Commander X16 +// Displays a sprite +.cpu _65c02 + // Commodore 64 PRG executable file +.file [name="sprite.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(__start) +.segment Code + + + .const VERA_INC_1 = $10 + .const VERA_DCSEL = 2 + .const VERA_ADDRSEL = 1 + .const VERA_VSYNC = 1 + // Sprite Attributes address in VERA VRAM + .const VERA_SPRITE_ATTR = $1fc00 + // 8BPP sprite mode (add to VERA_SPRITE.ADDR to enable) + .const VERA_SPRITE_8BPP = $8000 + // Address to use for sprite pixels in VRAM + .const SPRITE_PIXELS_VRAM = $8000 + .const SIZEOF_STRUCT_VERA_SPRITE = 8 + .const OFFSET_STRUCT_VERA_SPRITE_X = 2 + .const OFFSET_STRUCT_VERA_SPRITE_Y = 4 + .const VERA_SPRITES_ENABLE = $40 + .const SIZEOF_BYTE = 1 + // $9F20 VRAM Address (7:0) + .label VERA_ADDRX_L = $9f20 + // $9F21 VRAM Address (15:8) + .label VERA_ADDRX_M = $9f21 + // $9F22 VRAM Address (7:0) + // Bit 4-7: Address Increment The following is the amount incremented per value value:increment + // 0:0, 1:1, 2:2, 3:4, 4:8, 5:16, 6:32, 7:64, 8:128, 9:256, 10:512, 11:40, 12:80, 13:160, 14:320, 15:640 + // Bit 3: DECR Setting the DECR bit, will decrement instead of increment by the value set by the 'Address Increment' field. + // Bit 0: VRAM Address (16) + .label VERA_ADDRX_H = $9f22 + // $9F23 DATA0 VRAM Data port 0 + .label VERA_DATA0 = $9f23 + // $9F25 CTRL Control + // Bit 7: Reset + // Bit 1: DCSEL + // Bit 2: ADDRSEL + .label VERA_CTRL = $9f25 + // $9F26 IEN Interrupt Enable + // Bit 7: IRQ line (8) + // Bit 3: AFLOW + // Bit 2: SPRCOL + // Bit 1: LINE + // Bit 0: VSYNC + .label VERA_IEN = $9f26 + // $9F27 ISR Interrupt Status + // Interrupts will be generated for the interrupt sources set in the lower 4 bits of IEN. ISR will indicate the interrupts that have occurred. + // Writing a 1 to one of the lower 3 bits in ISR will clear that interrupt status. AFLOW can only be cleared by filling the audio FIFO for at least 1/4. + // Bit 4-7: Sprite Collisions. This field indicates which groups of sprites have collided. + // Bit 3: AFLOW + // Bit 2: SPRCOL + // Bit 1: LINE + // Bit 0: VSYNC + .label VERA_ISR = $9f27 + // $9F29 DC_VIDEO (DCSEL=0) + // Bit 7: Current Field Read-only bit which reflects the active interlaced field in composite and RGB modes. (0: even, 1: odd) + // Bit 6: Sprites Enable Enable output from the Sprites renderer + // Bit 5: Layer1 Enable Enable output from the Layer1 renderer + // Bit 4: Layer0 Enable Enable output from the Layer0 renderer + // Bit 2: Chroma Disable Setting 'Chroma Disable' disables output of chroma in NTSC composite mode and will give a better picture on a monochrome display. (Setting this bit will also disable the chroma output on the S-video output.) + // Bit 0-1: Output Mode 0: Video disabled, 1: VGA output, 2: NTSC composite, 3: RGB interlaced, composite sync (via VGA connector) + .label VERA_DC_VIDEO = $9f29 + // $0314 (RAM) IRQ vector - The vector used when the KERNAL serves IRQ interrupts + .label KERNEL_IRQ = $314 + // X sine index + .label sin_idx_x = 8 + // Y sine index + .label sin_idx_y = $a +.segment Code +__start: { + // sin_idx_x = 119 + lda #<$77 + sta.z sin_idx_x + lda #>$77 + sta.z sin_idx_x+1 + // sin_idx_y = 79 + lda #<$4f + sta.z sin_idx_y + lda #>$4f + sta.z sin_idx_y+1 + jsr main + rts +} +// VSYNC Interrupt Routine +irq_vsync: { + .label __5 = $c + .label __6 = $e + .label __7 = $c + .label __8 = $e + // if(++sin_idx_x==241) + inc.z sin_idx_x + bne !+ + inc.z sin_idx_x+1 + !: + lda.z sin_idx_x+1 + cmp #>$f1 + bne __b1 + lda.z sin_idx_x + cmp #<$f1 + bne __b1 + // sin_idx_x = 0 + lda #<0 + sta.z sin_idx_x + sta.z sin_idx_x+1 + __b1: + // if(--sin_idx_y==0xffff) + lda.z sin_idx_y + bne !+ + dec.z sin_idx_y+1 + !: + dec.z sin_idx_y + lda.z sin_idx_y+1 + cmp #>$ffff + bne __b2 + lda.z sin_idx_y + cmp #<$ffff + bne __b2 + // sin_idx_y = 251-1 + lda #<$fb-1 + sta.z sin_idx_y + lda #>$fb-1 + sta.z sin_idx_y+1 + __b2: + // SPRITE_ATTR.X = SINX[sin_idx_x] + lda.z sin_idx_x + asl + sta.z __5 + lda.z sin_idx_x+1 + rol + sta.z __5+1 + clc + lda.z __7 + adc #SINX + sta.z __7+1 + ldy #0 + lda (__7),y + sta SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_X + iny + lda (__7),y + sta SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_X+1 + // SPRITE_ATTR.Y = SINY[sin_idx_y] + lda.z sin_idx_y + asl + sta.z __6 + lda.z sin_idx_y+1 + rol + sta.z __6+1 + clc + lda.z __8 + adc #SINY + sta.z __8+1 + ldy #0 + lda (__8),y + sta SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_Y + iny + lda (__8),y + sta SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_Y+1 + // memcpy_to_vram((char)>VERA_SPRITE_ATTR, 4 + sta.z memcpy_to_vram.num+1 + lda #SPRITE_ATTR+2 + sta.z memcpy_to_vram.src+1 + ldx #VERA_SPRITE_ATTR>>$10 + lda #VERA_SPRITE_ATTR+2&$ffff + sta.z memcpy_to_vram.vdest+1 + jsr memcpy_to_vram + // *VERA_ISR = VERA_VSYNC + // Reset the VSYNC interrupt + lda #VERA_VSYNC + sta VERA_ISR + // asm + // Exit CX16 KERNAL IRQ + jmp $e034 + // } +} +main: { + // memcpy_to_vram((char)>SPRITE_PIXELS_VRAM, $40*$40*SIZEOF_BYTE + sta.z memcpy_to_vram.num+1 + lda #SPRITE_PIXELS + sta.z memcpy_to_vram.src+1 + ldx #0 + lda #SPRITE_PIXELS_VRAM&$ffff + sta.z memcpy_to_vram.vdest+1 + jsr memcpy_to_vram + // memcpy_to_vram((char)>VERA_SPRITE_ATTR, SIZEOF_STRUCT_VERA_SPRITE + sta.z memcpy_to_vram.num+1 + lda #SPRITE_ATTR + sta.z memcpy_to_vram.src+1 + ldx #VERA_SPRITE_ATTR>>$10 + lda #VERA_SPRITE_ATTR&$ffff + sta.z memcpy_to_vram.vdest+1 + jsr memcpy_to_vram + // *VERA_CTRL &= ~VERA_DCSEL + // Enable sprites + lda #VERA_DCSEL^$ff + and VERA_CTRL + sta VERA_CTRL + // *VERA_DC_VIDEO |= VERA_SPRITES_ENABLE + lda #VERA_SPRITES_ENABLE + ora VERA_DC_VIDEO + sta VERA_DC_VIDEO + // asm + sei + // *KERNEL_IRQ = &irq_vsync + lda #irq_vsync + sta KERNEL_IRQ+1 + // *VERA_IEN = VERA_VSYNC + lda #VERA_VSYNC + sta VERA_IEN + // asm + cli + // } + rts +} +// Copy block of memory (from RAM to VRAM) +// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination in VRAM. +// - vbank: Which 64K VRAM bank to put data into (0/1) +// - vdest: The destination address in VRAM +// - src: The source address in RAM +// - num: The number of bytes to copy +// memcpy_to_vram(byte register(X) vbank, void* zp(2) vdest, void* zp(4) src, word zp(6) num) +memcpy_to_vram: { + .label end = 6 + .label s = 4 + .label vdest = 2 + .label src = 4 + .label num = 6 + // *VERA_CTRL &= ~VERA_ADDRSEL + // Select DATA0 + lda #VERA_ADDRSEL^$ff + and VERA_CTRL + sta VERA_CTRL + // vdest + lda.z vdest+1 + // *VERA_ADDRX_M = >vdest + sta VERA_ADDRX_M + // VERA_INC_1 | vbank + txa + ora #VERA_INC_1 + // *VERA_ADDRX_H = VERA_INC_1 | vbank + sta VERA_ADDRX_H + // end = (char*)src+num + lda.z end + clc + adc.z src + sta.z end + lda.z end+1 + adc.z src+1 + sta.z end+1 + __b1: + // for(char *s = src; s!=end; s++) + lda.z s+1 + cmp.z end+1 + bne __b2 + lda.z s + cmp.z end + bne __b2 + // } + rts + __b2: + // *VERA_DATA0 = *s + ldy #0 + lda (s),y + sta VERA_DATA0 + // for(char *s = src; s!=end; s++) + inc.z s + bne !+ + inc.z s+1 + !: + jmp __b1 +} +.segment Data + // A 64*64 8bpp sprite + .align $100 +SPRITE_PIXELS: +.var pic = LoadPicture("sprite.png", List().add($000000, $ffffff)) + .for (var x=0;x<64; x++) + .for (var y=0; y<64; y++) + .byte (pic.getPixel(x,y)==0) ? 0 : 1 + + // X sine [0;640-64] + .align $100 +SINX: +.fillword 256, 288+288*sin(i*2*PI/241) + + // Y sine [0;480-64] + .align $100 +SINY: +.fillword 256, 208+208*sin(i*2*PI/251) + + // Sprite attributes: 8bpp, in front, 64x64, address SPRITE_PIXELS_VRAM + SPRITE_ATTR: .word (SPRITE_PIXELS_VRAM/$20&$ffff)|VERA_SPRITE_8BPP, $140-$20, $f0-$20 + .byte $c, $f0 diff --git a/src/test/ref/examples/cx16/sprite.cfg b/src/test/ref/examples/cx16/sprite.cfg new file mode 100644 index 000000000..b4578b978 --- /dev/null +++ b/src/test/ref/examples/cx16/sprite.cfg @@ -0,0 +1,103 @@ + +void __start() +__start: scope:[__start] from + [0] phi() + to:__start::__init1 +__start::__init1: scope:[__start] from __start + [1] sin_idx_x = $77 + [2] sin_idx_y = $4f + to:__start::@1 +__start::@1: scope:[__start] from __start::__init1 + [3] phi() + [4] call main + to:__start::@return +__start::@return: scope:[__start] from __start::@1 + [5] return + to:@return + +void irq_vsync() +irq_vsync: scope:[irq_vsync] from + [6] sin_idx_x = ++ sin_idx_x + [7] if(sin_idx_x!=$f1) goto irq_vsync::@1 + to:irq_vsync::@3 +irq_vsync::@3: scope:[irq_vsync] from irq_vsync + [8] sin_idx_x = 0 + to:irq_vsync::@1 +irq_vsync::@1: scope:[irq_vsync] from irq_vsync irq_vsync::@3 + [9] sin_idx_y = -- sin_idx_y + [10] if(sin_idx_y!=$ffff) goto irq_vsync::@2 + to:irq_vsync::@4 +irq_vsync::@4: scope:[irq_vsync] from irq_vsync::@1 + [11] sin_idx_y = $fb-1 + to:irq_vsync::@2 +irq_vsync::@2: scope:[irq_vsync] from irq_vsync::@1 irq_vsync::@4 + [12] irq_vsync::$5 = sin_idx_x << 1 + [13] irq_vsync::$7 = SINX + irq_vsync::$5 + [14] *((word*)&SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_X) = *irq_vsync::$7 + [15] irq_vsync::$6 = sin_idx_y << 1 + [16] irq_vsync::$8 = SINY + irq_vsync::$6 + [17] *((word*)&SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_Y) = *irq_vsync::$8 + [18] call memcpy_to_vram + to:irq_vsync::@5 +irq_vsync::@5: scope:[irq_vsync] from irq_vsync::@2 + [19] *VERA_ISR = VERA_VSYNC + asm { jmp$e034 } + to:irq_vsync::@return +irq_vsync::@return: scope:[irq_vsync] from irq_vsync::@5 + [21] return + to:@return + +void main() +main: scope:[main] from __start::@1 + [22] phi() + [23] call memcpy_to_vram + to:main::@2 +main::@2: scope:[main] from main + [24] phi() + [25] call memcpy_to_vram + to:main::@3 +main::@3: scope:[main] from main::@2 + [26] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL + [27] *VERA_DC_VIDEO = *VERA_DC_VIDEO | VERA_SPRITES_ENABLE + to:main::SEI1 +main::SEI1: scope:[main] from main::@3 + asm { sei } + to:main::@1 +main::@1: scope:[main] from main::SEI1 + [29] *KERNEL_IRQ = &irq_vsync + [30] *VERA_IEN = VERA_VSYNC + to:main::CLI1 +main::CLI1: scope:[main] from main::@1 + asm { cli } + to:main::@return +main::@return: scope:[main] from main::CLI1 + [32] return + to:@return + +void memcpy_to_vram(byte memcpy_to_vram::vbank , void* memcpy_to_vram::vdest , void* memcpy_to_vram::src , word memcpy_to_vram::num) +memcpy_to_vram: scope:[memcpy_to_vram] from irq_vsync::@2 main main::@2 + [33] memcpy_to_vram::num#3 = phi( irq_vsync::@2/4, main/(word)$40*$40*SIZEOF_BYTE, main::@2/SIZEOF_STRUCT_VERA_SPRITE ) + [33] memcpy_to_vram::src#3 = phi( irq_vsync::@2/(void*)&SPRITE_ATTR+2, main/(void*)SPRITE_PIXELS, main::@2/(void*)&SPRITE_ATTR ) + [33] memcpy_to_vram::vbank#3 = phi( irq_vsync::@2/(byte)>VERA_SPRITE_ATTR, main/0, main::@2/(byte)>VERA_SPRITE_ATTR ) + [33] memcpy_to_vram::vdest#3 = phi( irq_vsync::@2/(void*) memcpy_to_vram::vdest#3 + [38] *VERA_ADDRX_M = memcpy_to_vram::$1 + [39] memcpy_to_vram::$2 = VERA_INC_1 | memcpy_to_vram::vbank#3 + [40] *VERA_ADDRX_H = memcpy_to_vram::$2 + [41] memcpy_to_vram::end#0 = (byte*)memcpy_to_vram::src#3 + memcpy_to_vram::num#3 + [42] memcpy_to_vram::s#4 = (byte*)memcpy_to_vram::src#3 + to:memcpy_to_vram::@1 +memcpy_to_vram::@1: scope:[memcpy_to_vram] from memcpy_to_vram memcpy_to_vram::@2 + [43] memcpy_to_vram::s#2 = phi( memcpy_to_vram/memcpy_to_vram::s#4, memcpy_to_vram::@2/memcpy_to_vram::s#1 ) + [44] if(memcpy_to_vram::s#2!=memcpy_to_vram::end#0) goto memcpy_to_vram::@2 + to:memcpy_to_vram::@return +memcpy_to_vram::@return: scope:[memcpy_to_vram] from memcpy_to_vram::@1 + [45] return + to:@return +memcpy_to_vram::@2: scope:[memcpy_to_vram] from memcpy_to_vram::@1 + [46] *VERA_DATA0 = *memcpy_to_vram::s#2 + [47] memcpy_to_vram::s#1 = ++ memcpy_to_vram::s#2 + to:memcpy_to_vram::@1 diff --git a/src/test/ref/examples/cx16/sprite.log b/src/test/ref/examples/cx16/sprite.log new file mode 100644 index 000000000..d4beccc30 --- /dev/null +++ b/src/test/ref/examples/cx16/sprite.log @@ -0,0 +1,1632 @@ +Resolved forward reference irq_vsync to void irq_vsync() +Setting struct to load/store in variable affected by address-of main::$3 = call memcpy_to_vram (byte)>VERA_SPRITE_ATTR VERA_SPRITE_ATTR memcpy_to_vram::vdest#3 + *VERA_ADDRX_M = memcpy_to_vram::$1 + memcpy_to_vram::$2 = VERA_INC_1 | memcpy_to_vram::vbank#3 + *VERA_ADDRX_H = memcpy_to_vram::$2 + memcpy_to_vram::$5 = (byte*)memcpy_to_vram::src#3 + memcpy_to_vram::$3 = memcpy_to_vram::$5 + memcpy_to_vram::num#3 + memcpy_to_vram::end#0 = memcpy_to_vram::$3 + memcpy_to_vram::s#0 = ((byte*)) memcpy_to_vram::src#3 + to:memcpy_to_vram::@1 +memcpy_to_vram::@1: scope:[memcpy_to_vram] from memcpy_to_vram memcpy_to_vram::@2 + memcpy_to_vram::end#1 = phi( memcpy_to_vram/memcpy_to_vram::end#0, memcpy_to_vram::@2/memcpy_to_vram::end#2 ) + memcpy_to_vram::s#2 = phi( memcpy_to_vram/memcpy_to_vram::s#0, memcpy_to_vram::@2/memcpy_to_vram::s#1 ) + memcpy_to_vram::$4 = memcpy_to_vram::s#2 != memcpy_to_vram::end#1 + if(memcpy_to_vram::$4) goto memcpy_to_vram::@2 + to:memcpy_to_vram::@return +memcpy_to_vram::@2: scope:[memcpy_to_vram] from memcpy_to_vram::@1 + memcpy_to_vram::end#2 = phi( memcpy_to_vram::@1/memcpy_to_vram::end#1 ) + memcpy_to_vram::s#3 = phi( memcpy_to_vram::@1/memcpy_to_vram::s#2 ) + *VERA_DATA0 = *memcpy_to_vram::s#3 + memcpy_to_vram::s#1 = ++ memcpy_to_vram::s#3 + to:memcpy_to_vram::@1 +memcpy_to_vram::@return: scope:[memcpy_to_vram] from memcpy_to_vram::@1 + return + to:@return + +void main() +main: scope:[main] from __start::@1 + main::$0 = sizeof SPRITE_PIXELS + memcpy_to_vram::vbank#0 = (byte)>SPRITE_PIXELS_VRAM + memcpy_to_vram::vdest#0 = (void*)VERA_SPRITE_ATTR + memcpy_to_vram::vdest#1 = (void*)VERA_SPRITE_ATTR + memcpy_to_vram::vdest#2 = (void*)SPRITE_PIXELS_VRAM +Constant memcpy_to_vram::vdest#0 = (void*)VERA_SPRITE_ATTR +Constant memcpy_to_vram::vdest#1 = (void*)VERA_SPRITE_ATTR +Constant memcpy_to_vram::vdest#2 = (void*)SPRITE_PIXELS_VRAM in +Successful SSA optimization PassNSimplifyConstantZero +Simplifying constant integer cast VERA_SPRITE_ATTR +Constant inlined memcpy_to_vram::vbank#2 = (byte)>VERA_SPRITE_ATTR +Constant inlined memcpy_to_vram::num#2 = 4 +Constant inlined memcpy_to_vram::num#1 = SIZEOF_STRUCT_VERA_SPRITE +Successful SSA optimization Pass2ConstantInlining +Eliminating unused constant SIZEOF_WORD +Successful SSA optimization PassNEliminateUnusedVars +Finalized unsigned number type (byte) $40 +Finalized unsigned number type (byte) $40 +Finalized unsigned number type (word) $140 +Finalized unsigned number type (byte) $20 +Finalized unsigned number type (byte) $f0 +Finalized unsigned number type (byte) $20 +Finalized unsigned number type (byte) $f1 +Finalized unsigned number type (byte) $fb +Finalized unsigned number type (byte) $fb +Finalized unsigned number type (byte) 1 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Simplifying constant integer cast $140-$20 +Simplifying constant integer cast $fb-1 +Successful SSA optimization PassNCastSimplification +Adding NOP phi() at start of __start +Adding NOP phi() at start of __start::@1 +Adding NOP phi() at start of __start::@2 +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@2 +CALL GRAPH +Calls in [__start] to main:4 +Calls in [irq_vsync] to memcpy_to_vram:19 +Calls in [main] to memcpy_to_vram:24 memcpy_to_vram:26 + +Created 5 initial phi equivalence classes +Coalesced [49] memcpy_to_vram::s#5 = memcpy_to_vram::s#1 +Coalesced down to 5 phi equivalence classes +Culled Empty Block label __start::@2 +Adding NOP phi() at start of __start +Adding NOP phi() at start of __start::@1 +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@2 + +FINAL CONTROL FLOW GRAPH + +void __start() +__start: scope:[__start] from + [0] phi() + to:__start::__init1 +__start::__init1: scope:[__start] from __start + [1] sin_idx_x = $77 + [2] sin_idx_y = $4f + to:__start::@1 +__start::@1: scope:[__start] from __start::__init1 + [3] phi() + [4] call main + to:__start::@return +__start::@return: scope:[__start] from __start::@1 + [5] return + to:@return + +void irq_vsync() +irq_vsync: scope:[irq_vsync] from + [6] sin_idx_x = ++ sin_idx_x + [7] if(sin_idx_x!=$f1) goto irq_vsync::@1 + to:irq_vsync::@3 +irq_vsync::@3: scope:[irq_vsync] from irq_vsync + [8] sin_idx_x = 0 + to:irq_vsync::@1 +irq_vsync::@1: scope:[irq_vsync] from irq_vsync irq_vsync::@3 + [9] sin_idx_y = -- sin_idx_y + [10] if(sin_idx_y!=$ffff) goto irq_vsync::@2 + to:irq_vsync::@4 +irq_vsync::@4: scope:[irq_vsync] from irq_vsync::@1 + [11] sin_idx_y = $fb-1 + to:irq_vsync::@2 +irq_vsync::@2: scope:[irq_vsync] from irq_vsync::@1 irq_vsync::@4 + [12] irq_vsync::$5 = sin_idx_x << 1 + [13] irq_vsync::$7 = SINX + irq_vsync::$5 + [14] *((word*)&SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_X) = *irq_vsync::$7 + [15] irq_vsync::$6 = sin_idx_y << 1 + [16] irq_vsync::$8 = SINY + irq_vsync::$6 + [17] *((word*)&SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_Y) = *irq_vsync::$8 + [18] call memcpy_to_vram + to:irq_vsync::@5 +irq_vsync::@5: scope:[irq_vsync] from irq_vsync::@2 + [19] *VERA_ISR = VERA_VSYNC + asm { jmp$e034 } + to:irq_vsync::@return +irq_vsync::@return: scope:[irq_vsync] from irq_vsync::@5 + [21] return + to:@return + +void main() +main: scope:[main] from __start::@1 + [22] phi() + [23] call memcpy_to_vram + to:main::@2 +main::@2: scope:[main] from main + [24] phi() + [25] call memcpy_to_vram + to:main::@3 +main::@3: scope:[main] from main::@2 + [26] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL + [27] *VERA_DC_VIDEO = *VERA_DC_VIDEO | VERA_SPRITES_ENABLE + to:main::SEI1 +main::SEI1: scope:[main] from main::@3 + asm { sei } + to:main::@1 +main::@1: scope:[main] from main::SEI1 + [29] *KERNEL_IRQ = &irq_vsync + [30] *VERA_IEN = VERA_VSYNC + to:main::CLI1 +main::CLI1: scope:[main] from main::@1 + asm { cli } + to:main::@return +main::@return: scope:[main] from main::CLI1 + [32] return + to:@return + +void memcpy_to_vram(byte memcpy_to_vram::vbank , void* memcpy_to_vram::vdest , void* memcpy_to_vram::src , word memcpy_to_vram::num) +memcpy_to_vram: scope:[memcpy_to_vram] from irq_vsync::@2 main main::@2 + [33] memcpy_to_vram::num#3 = phi( irq_vsync::@2/4, main/(word)$40*$40*SIZEOF_BYTE, main::@2/SIZEOF_STRUCT_VERA_SPRITE ) + [33] memcpy_to_vram::src#3 = phi( irq_vsync::@2/(void*)&SPRITE_ATTR+2, main/(void*)SPRITE_PIXELS, main::@2/(void*)&SPRITE_ATTR ) + [33] memcpy_to_vram::vbank#3 = phi( irq_vsync::@2/(byte)>VERA_SPRITE_ATTR, main/0, main::@2/(byte)>VERA_SPRITE_ATTR ) + [33] memcpy_to_vram::vdest#3 = phi( irq_vsync::@2/(void*) memcpy_to_vram::vdest#3 + [38] *VERA_ADDRX_M = memcpy_to_vram::$1 + [39] memcpy_to_vram::$2 = VERA_INC_1 | memcpy_to_vram::vbank#3 + [40] *VERA_ADDRX_H = memcpy_to_vram::$2 + [41] memcpy_to_vram::end#0 = (byte*)memcpy_to_vram::src#3 + memcpy_to_vram::num#3 + [42] memcpy_to_vram::s#4 = (byte*)memcpy_to_vram::src#3 + to:memcpy_to_vram::@1 +memcpy_to_vram::@1: scope:[memcpy_to_vram] from memcpy_to_vram memcpy_to_vram::@2 + [43] memcpy_to_vram::s#2 = phi( memcpy_to_vram/memcpy_to_vram::s#4, memcpy_to_vram::@2/memcpy_to_vram::s#1 ) + [44] if(memcpy_to_vram::s#2!=memcpy_to_vram::end#0) goto memcpy_to_vram::@2 + to:memcpy_to_vram::@return +memcpy_to_vram::@return: scope:[memcpy_to_vram] from memcpy_to_vram::@1 + [45] return + to:@return +memcpy_to_vram::@2: scope:[memcpy_to_vram] from memcpy_to_vram::@1 + [46] *VERA_DATA0 = *memcpy_to_vram::s#2 + [47] memcpy_to_vram::s#1 = ++ memcpy_to_vram::s#2 + to:memcpy_to_vram::@1 + + +VARIABLE REGISTER WEIGHTS +struct VERA_SPRITE SPRITE_ATTR loadstore = { ADDR: $77 + sta.z sin_idx_x+1 + // [2] sin_idx_y = $4f -- vwuz1=vwuc1 + lda #<$4f + sta.z sin_idx_y + lda #>$4f + sta.z sin_idx_y+1 + // [3] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1] + __b1_from___init1: + jmp __b1 + // __start::@1 + __b1: + // [4] call main + // [22] phi from __start::@1 to main [phi:__start::@1->main] + main_from___b1: + jsr main + jmp __breturn + // __start::@return + __breturn: + // [5] return + rts +} + // irq_vsync +// VSYNC Interrupt Routine +irq_vsync: { + .label __5 = $c + .label __6 = $e + .label __7 = $c + .label __8 = $e + // [6] sin_idx_x = ++ sin_idx_x -- vwuz1=_inc_vwuz1 + inc.z sin_idx_x + bne !+ + inc.z sin_idx_x+1 + !: + // [7] if(sin_idx_x!=$f1) goto irq_vsync::@1 -- vwuz1_neq_vwuc1_then_la1 + lda.z sin_idx_x+1 + cmp #>$f1 + bne __b1 + lda.z sin_idx_x + cmp #<$f1 + bne __b1 + jmp __b3 + // irq_vsync::@3 + __b3: + // [8] sin_idx_x = 0 -- vwuz1=vbuc1 + lda #<0 + sta.z sin_idx_x + lda #>0 + sta.z sin_idx_x+1 + jmp __b1 + // irq_vsync::@1 + __b1: + // [9] sin_idx_y = -- sin_idx_y -- vwuz1=_dec_vwuz1 + lda.z sin_idx_y + bne !+ + dec.z sin_idx_y+1 + !: + dec.z sin_idx_y + // [10] if(sin_idx_y!=$ffff) goto irq_vsync::@2 -- vwuz1_neq_vwuc1_then_la1 + lda.z sin_idx_y+1 + cmp #>$ffff + bne __b2 + lda.z sin_idx_y + cmp #<$ffff + bne __b2 + jmp __b4 + // irq_vsync::@4 + __b4: + // [11] sin_idx_y = $fb-1 -- vwuz1=vbuc1 + lda #<$fb-1 + sta.z sin_idx_y + lda #>$fb-1 + sta.z sin_idx_y+1 + jmp __b2 + // irq_vsync::@2 + __b2: + // [12] irq_vsync::$5 = sin_idx_x << 1 -- vwuz1=vwuz2_rol_1 + lda.z sin_idx_x + asl + sta.z __5 + lda.z sin_idx_x+1 + rol + sta.z __5+1 + // [13] irq_vsync::$7 = SINX + irq_vsync::$5 -- pwuz1=pwuc1_plus_vwuz1 + clc + lda.z __7 + adc #SINX + sta.z __7+1 + // [14] *((word*)&SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_X) = *irq_vsync::$7 -- _deref_pwuc1=_deref_pwuz1 + ldy #0 + lda (__7),y + sta SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_X + iny + lda (__7),y + sta SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_X+1 + // [15] irq_vsync::$6 = sin_idx_y << 1 -- vwuz1=vwuz2_rol_1 + lda.z sin_idx_y + asl + sta.z __6 + lda.z sin_idx_y+1 + rol + sta.z __6+1 + // [16] irq_vsync::$8 = SINY + irq_vsync::$6 -- pwuz1=pwuc1_plus_vwuz1 + clc + lda.z __8 + adc #SINY + sta.z __8+1 + // [17] *((word*)&SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_Y) = *irq_vsync::$8 -- _deref_pwuc1=_deref_pwuz1 + ldy #0 + lda (__8),y + sta SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_Y + iny + lda (__8),y + sta SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_Y+1 + // [18] call memcpy_to_vram + // Copy sprite positions to VRAM (the 4 relevant bytes in VERA_SPRITE_ATTR) + // [33] phi from irq_vsync::@2 to memcpy_to_vram [phi:irq_vsync::@2->memcpy_to_vram] + memcpy_to_vram_from___b2: + // [33] phi memcpy_to_vram::num#3 = 4 [phi:irq_vsync::@2->memcpy_to_vram#0] -- vwuz1=vbuc1 + lda #<4 + sta.z memcpy_to_vram.num + lda #>4 + sta.z memcpy_to_vram.num+1 + // [33] phi memcpy_to_vram::src#3 = (void*)&SPRITE_ATTR+2 [phi:irq_vsync::@2->memcpy_to_vram#1] -- pvoz1=pvoc1 + lda #SPRITE_ATTR+2 + sta.z memcpy_to_vram.src+1 + // [33] phi memcpy_to_vram::vbank#3 = (byte)>VERA_SPRITE_ATTR [phi:irq_vsync::@2->memcpy_to_vram#2] -- vbuxx=vbuc1 + ldx #VERA_SPRITE_ATTR>>$10 + // [33] phi memcpy_to_vram::vdest#3 = (void*)memcpy_to_vram#3] -- pvoz1=pvoc1 + lda #VERA_SPRITE_ATTR+2&$ffff + sta.z memcpy_to_vram.vdest+1 + jsr memcpy_to_vram + jmp __b5 + // irq_vsync::@5 + __b5: + // [19] *VERA_ISR = VERA_VSYNC -- _deref_pbuc1=vbuc2 + // Reset the VSYNC interrupt + lda #VERA_VSYNC + sta VERA_ISR + // asm { jmp$e034 } + // Exit CX16 KERNAL IRQ + jmp $e034 + jmp __breturn + // irq_vsync::@return + __breturn: + // [21] return + rts +} + // main +main: { + // [23] call memcpy_to_vram + // Copy sprite data to VRAM + // [33] phi from main to memcpy_to_vram [phi:main->memcpy_to_vram] + memcpy_to_vram_from_main: + // [33] phi memcpy_to_vram::num#3 = (word)$40*$40*SIZEOF_BYTE [phi:main->memcpy_to_vram#0] -- vwuz1=vwuc1 + lda #<$40*$40*SIZEOF_BYTE + sta.z memcpy_to_vram.num + lda #>$40*$40*SIZEOF_BYTE + sta.z memcpy_to_vram.num+1 + // [33] phi memcpy_to_vram::src#3 = (void*)SPRITE_PIXELS [phi:main->memcpy_to_vram#1] -- pvoz1=pvoc1 + lda #SPRITE_PIXELS + sta.z memcpy_to_vram.src+1 + // [33] phi memcpy_to_vram::vbank#3 = 0 [phi:main->memcpy_to_vram#2] -- vbuxx=vbuc1 + ldx #0 + // [33] phi memcpy_to_vram::vdest#3 = (void*)memcpy_to_vram#3] -- pvoz1=pvoc1 + lda #SPRITE_PIXELS_VRAM&$ffff + sta.z memcpy_to_vram.vdest+1 + jsr memcpy_to_vram + // [24] phi from main to main::@2 [phi:main->main::@2] + __b2_from_main: + jmp __b2 + // main::@2 + __b2: + // [25] call memcpy_to_vram + // Copy sprite attributes to VRAM + // [33] phi from main::@2 to memcpy_to_vram [phi:main::@2->memcpy_to_vram] + memcpy_to_vram_from___b2: + // [33] phi memcpy_to_vram::num#3 = SIZEOF_STRUCT_VERA_SPRITE [phi:main::@2->memcpy_to_vram#0] -- vwuz1=vbuc1 + lda #SIZEOF_STRUCT_VERA_SPRITE + sta.z memcpy_to_vram.num+1 + // [33] phi memcpy_to_vram::src#3 = (void*)&SPRITE_ATTR [phi:main::@2->memcpy_to_vram#1] -- pvoz1=pvoc1 + lda #SPRITE_ATTR + sta.z memcpy_to_vram.src+1 + // [33] phi memcpy_to_vram::vbank#3 = (byte)>VERA_SPRITE_ATTR [phi:main::@2->memcpy_to_vram#2] -- vbuxx=vbuc1 + ldx #VERA_SPRITE_ATTR>>$10 + // [33] phi memcpy_to_vram::vdest#3 = (void*)memcpy_to_vram#3] -- pvoz1=pvoc1 + lda #VERA_SPRITE_ATTR&$ffff + sta.z memcpy_to_vram.vdest+1 + jsr memcpy_to_vram + jmp __b3 + // main::@3 + __b3: + // [26] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2 + // Enable sprites + lda #VERA_DCSEL^$ff + and VERA_CTRL + sta VERA_CTRL + // [27] *VERA_DC_VIDEO = *VERA_DC_VIDEO | VERA_SPRITES_ENABLE -- _deref_pbuc1=_deref_pbuc1_bor_vbuc2 + lda #VERA_SPRITES_ENABLE + ora VERA_DC_VIDEO + sta VERA_DC_VIDEO + jmp SEI1 + // main::SEI1 + SEI1: + // asm { sei } + sei + jmp __b1 + // main::@1 + __b1: + // [29] *KERNEL_IRQ = &irq_vsync -- _deref_qprc1=pprc2 + lda #irq_vsync + sta KERNEL_IRQ+1 + // [30] *VERA_IEN = VERA_VSYNC -- _deref_pbuc1=vbuc2 + lda #VERA_VSYNC + sta VERA_IEN + jmp CLI1 + // main::CLI1 + CLI1: + // asm { cli } + cli + jmp __breturn + // main::@return + __breturn: + // [32] return + rts +} + // memcpy_to_vram +// Copy block of memory (from RAM to VRAM) +// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination in VRAM. +// - vbank: Which 64K VRAM bank to put data into (0/1) +// - vdest: The destination address in VRAM +// - src: The source address in RAM +// - num: The number of bytes to copy +// memcpy_to_vram(byte register(X) vbank, void* zp(2) vdest, void* zp(4) src, word zp(6) num) +memcpy_to_vram: { + .label end = 6 + .label s = 4 + .label vdest = 2 + .label src = 4 + .label num = 6 + // [34] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2 + // Select DATA0 + lda #VERA_ADDRSEL^$ff + and VERA_CTRL + sta VERA_CTRL + // [35] memcpy_to_vram::$0 = < memcpy_to_vram::vdest#3 -- vbuaa=_lo_pvoz1 + lda.z vdest + // [36] *VERA_ADDRX_L = memcpy_to_vram::$0 -- _deref_pbuc1=vbuaa + // Set address + sta VERA_ADDRX_L + // [37] memcpy_to_vram::$1 = > memcpy_to_vram::vdest#3 -- vbuaa=_hi_pvoz1 + lda.z vdest+1 + // [38] *VERA_ADDRX_M = memcpy_to_vram::$1 -- _deref_pbuc1=vbuaa + sta VERA_ADDRX_M + // [39] memcpy_to_vram::$2 = VERA_INC_1 | memcpy_to_vram::vbank#3 -- vbuaa=vbuc1_bor_vbuxx + txa + ora #VERA_INC_1 + // [40] *VERA_ADDRX_H = memcpy_to_vram::$2 -- _deref_pbuc1=vbuaa + sta VERA_ADDRX_H + // [41] memcpy_to_vram::end#0 = (byte*)memcpy_to_vram::src#3 + memcpy_to_vram::num#3 -- pbuz1=pbuz2_plus_vwuz1 + lda.z end + clc + adc.z src + sta.z end + lda.z end+1 + adc.z src+1 + sta.z end+1 + // [42] memcpy_to_vram::s#4 = (byte*)memcpy_to_vram::src#3 + // [43] phi from memcpy_to_vram memcpy_to_vram::@2 to memcpy_to_vram::@1 [phi:memcpy_to_vram/memcpy_to_vram::@2->memcpy_to_vram::@1] + __b1_from_memcpy_to_vram: + __b1_from___b2: + // [43] phi memcpy_to_vram::s#2 = memcpy_to_vram::s#4 [phi:memcpy_to_vram/memcpy_to_vram::@2->memcpy_to_vram::@1#0] -- register_copy + jmp __b1 + // memcpy_to_vram::@1 + __b1: + // [44] if(memcpy_to_vram::s#2!=memcpy_to_vram::end#0) goto memcpy_to_vram::@2 -- pbuz1_neq_pbuz2_then_la1 + lda.z s+1 + cmp.z end+1 + bne __b2 + lda.z s + cmp.z end + bne __b2 + jmp __breturn + // memcpy_to_vram::@return + __breturn: + // [45] return + rts + // memcpy_to_vram::@2 + __b2: + // [46] *VERA_DATA0 = *memcpy_to_vram::s#2 -- _deref_pbuc1=_deref_pbuz1 + ldy #0 + lda (s),y + sta VERA_DATA0 + // [47] memcpy_to_vram::s#1 = ++ memcpy_to_vram::s#2 -- pbuz1=_inc_pbuz1 + inc.z s + bne !+ + inc.z s+1 + !: + jmp __b1_from___b2 +} + // File Data +.segment Data + // A 64*64 8bpp sprite + .align $100 +SPRITE_PIXELS: +.var pic = LoadPicture("sprite.png", List().add($000000, $ffffff)) + .for (var x=0;x<64; x++) + .for (var y=0; y<64; y++) + .byte (pic.getPixel(x,y)==0) ? 0 : 1 + + // X sine [0;640-64] + .align $100 +SINX: +.fillword 256, 288+288*sin(i*2*PI/241) + + // Y sine [0;480-64] + .align $100 +SINY: +.fillword 256, 208+208*sin(i*2*PI/251) + + // Sprite attributes: 8bpp, in front, 64x64, address SPRITE_PIXELS_VRAM + SPRITE_ATTR: .word (SPRITE_PIXELS_VRAM/$20&$ffff)|VERA_SPRITE_8BPP, $140-$20, $f0-$20 + .byte $c, $f0 + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __init1 +Removing instruction jmp __b1 +Removing instruction jmp __breturn +Removing instruction jmp __b3 +Removing instruction jmp __b1 +Removing instruction jmp __b4 +Removing instruction jmp __b2 +Removing instruction jmp __b5 +Removing instruction jmp __breturn +Removing instruction jmp __b2 +Removing instruction jmp __b3 +Removing instruction jmp SEI1 +Removing instruction jmp __b1 +Removing instruction jmp CLI1 +Removing instruction jmp __breturn +Removing instruction jmp __b1 +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda #>0 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Replacing label __b1_from___b2 with __b1 +Removing instruction __b1_from___init1: +Removing instruction main_from___b1: +Removing instruction __b2_from_main: +Removing instruction __b1_from_memcpy_to_vram: +Removing instruction __b1_from___b2: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction __init1: +Removing instruction __b1: +Removing instruction __breturn: +Removing instruction __b3: +Removing instruction __b4: +Removing instruction memcpy_to_vram_from___b2: +Removing instruction __b5: +Removing instruction __breturn: +Removing instruction memcpy_to_vram_from_main: +Removing instruction __b2: +Removing instruction memcpy_to_vram_from___b2: +Removing instruction __b3: +Removing instruction SEI1: +Removing instruction __b1: +Removing instruction CLI1: +Removing instruction __breturn: +Removing instruction __breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Removing unreachable instruction rts +Succesful ASM optimization Pass5UnreachableCodeElimination + +FINAL SYMBOL TABLE +const nomodify void()** KERNEL_IRQ = (void()**) 788 +const byte OFFSET_STRUCT_VERA_SPRITE_X = 2 +const byte OFFSET_STRUCT_VERA_SPRITE_Y = 4 +const word* SINX[$f1] = kickasm {{ .fillword 256, 288+288*sin(i*2*PI/241) + }} +const word* SINY[$fb] = kickasm {{ .fillword 256, 208+208*sin(i*2*PI/251) + }} +const byte SIZEOF_BYTE = 1 +const byte SIZEOF_STRUCT_VERA_SPRITE = 8 +struct VERA_SPRITE SPRITE_ATTR loadstore mem[8] = { ADDR: $77 + sta.z sin_idx_x+1 + // sin_idx_y = 79 + // [2] sin_idx_y = $4f -- vwuz1=vwuc1 + lda #<$4f + sta.z sin_idx_y + lda #>$4f + sta.z sin_idx_y+1 + // [3] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1] + // __start::@1 + // [4] call main + // [22] phi from __start::@1 to main [phi:__start::@1->main] + jsr main + // __start::@return + // [5] return + rts +} + // irq_vsync +// VSYNC Interrupt Routine +irq_vsync: { + .label __5 = $c + .label __6 = $e + .label __7 = $c + .label __8 = $e + // if(++sin_idx_x==241) + // [6] sin_idx_x = ++ sin_idx_x -- vwuz1=_inc_vwuz1 + inc.z sin_idx_x + bne !+ + inc.z sin_idx_x+1 + !: + // [7] if(sin_idx_x!=$f1) goto irq_vsync::@1 -- vwuz1_neq_vwuc1_then_la1 + lda.z sin_idx_x+1 + cmp #>$f1 + bne __b1 + lda.z sin_idx_x + cmp #<$f1 + bne __b1 + // irq_vsync::@3 + // sin_idx_x = 0 + // [8] sin_idx_x = 0 -- vwuz1=vbuc1 + lda #<0 + sta.z sin_idx_x + sta.z sin_idx_x+1 + // irq_vsync::@1 + __b1: + // if(--sin_idx_y==0xffff) + // [9] sin_idx_y = -- sin_idx_y -- vwuz1=_dec_vwuz1 + lda.z sin_idx_y + bne !+ + dec.z sin_idx_y+1 + !: + dec.z sin_idx_y + // [10] if(sin_idx_y!=$ffff) goto irq_vsync::@2 -- vwuz1_neq_vwuc1_then_la1 + lda.z sin_idx_y+1 + cmp #>$ffff + bne __b2 + lda.z sin_idx_y + cmp #<$ffff + bne __b2 + // irq_vsync::@4 + // sin_idx_y = 251-1 + // [11] sin_idx_y = $fb-1 -- vwuz1=vbuc1 + lda #<$fb-1 + sta.z sin_idx_y + lda #>$fb-1 + sta.z sin_idx_y+1 + // irq_vsync::@2 + __b2: + // SPRITE_ATTR.X = SINX[sin_idx_x] + // [12] irq_vsync::$5 = sin_idx_x << 1 -- vwuz1=vwuz2_rol_1 + lda.z sin_idx_x + asl + sta.z __5 + lda.z sin_idx_x+1 + rol + sta.z __5+1 + // [13] irq_vsync::$7 = SINX + irq_vsync::$5 -- pwuz1=pwuc1_plus_vwuz1 + clc + lda.z __7 + adc #SINX + sta.z __7+1 + // [14] *((word*)&SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_X) = *irq_vsync::$7 -- _deref_pwuc1=_deref_pwuz1 + ldy #0 + lda (__7),y + sta SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_X + iny + lda (__7),y + sta SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_X+1 + // SPRITE_ATTR.Y = SINY[sin_idx_y] + // [15] irq_vsync::$6 = sin_idx_y << 1 -- vwuz1=vwuz2_rol_1 + lda.z sin_idx_y + asl + sta.z __6 + lda.z sin_idx_y+1 + rol + sta.z __6+1 + // [16] irq_vsync::$8 = SINY + irq_vsync::$6 -- pwuz1=pwuc1_plus_vwuz1 + clc + lda.z __8 + adc #SINY + sta.z __8+1 + // [17] *((word*)&SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_Y) = *irq_vsync::$8 -- _deref_pwuc1=_deref_pwuz1 + ldy #0 + lda (__8),y + sta SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_Y + iny + lda (__8),y + sta SPRITE_ATTR+OFFSET_STRUCT_VERA_SPRITE_Y+1 + // memcpy_to_vram((char)>VERA_SPRITE_ATTR, memcpy_to_vram] + // [33] phi memcpy_to_vram::num#3 = 4 [phi:irq_vsync::@2->memcpy_to_vram#0] -- vwuz1=vbuc1 + lda #<4 + sta.z memcpy_to_vram.num + lda #>4 + sta.z memcpy_to_vram.num+1 + // [33] phi memcpy_to_vram::src#3 = (void*)&SPRITE_ATTR+2 [phi:irq_vsync::@2->memcpy_to_vram#1] -- pvoz1=pvoc1 + lda #SPRITE_ATTR+2 + sta.z memcpy_to_vram.src+1 + // [33] phi memcpy_to_vram::vbank#3 = (byte)>VERA_SPRITE_ATTR [phi:irq_vsync::@2->memcpy_to_vram#2] -- vbuxx=vbuc1 + ldx #VERA_SPRITE_ATTR>>$10 + // [33] phi memcpy_to_vram::vdest#3 = (void*)memcpy_to_vram#3] -- pvoz1=pvoc1 + lda #VERA_SPRITE_ATTR+2&$ffff + sta.z memcpy_to_vram.vdest+1 + jsr memcpy_to_vram + // irq_vsync::@5 + // *VERA_ISR = VERA_VSYNC + // [19] *VERA_ISR = VERA_VSYNC -- _deref_pbuc1=vbuc2 + // Reset the VSYNC interrupt + lda #VERA_VSYNC + sta VERA_ISR + // asm + // asm { jmp$e034 } + // Exit CX16 KERNAL IRQ + jmp $e034 + // irq_vsync::@return + // } + // [21] return +} + // main +main: { + // memcpy_to_vram((char)>SPRITE_PIXELS_VRAM, memcpy_to_vram] + // [33] phi memcpy_to_vram::num#3 = (word)$40*$40*SIZEOF_BYTE [phi:main->memcpy_to_vram#0] -- vwuz1=vwuc1 + lda #<$40*$40*SIZEOF_BYTE + sta.z memcpy_to_vram.num + lda #>$40*$40*SIZEOF_BYTE + sta.z memcpy_to_vram.num+1 + // [33] phi memcpy_to_vram::src#3 = (void*)SPRITE_PIXELS [phi:main->memcpy_to_vram#1] -- pvoz1=pvoc1 + lda #SPRITE_PIXELS + sta.z memcpy_to_vram.src+1 + // [33] phi memcpy_to_vram::vbank#3 = 0 [phi:main->memcpy_to_vram#2] -- vbuxx=vbuc1 + ldx #0 + // [33] phi memcpy_to_vram::vdest#3 = (void*)memcpy_to_vram#3] -- pvoz1=pvoc1 + lda #SPRITE_PIXELS_VRAM&$ffff + sta.z memcpy_to_vram.vdest+1 + jsr memcpy_to_vram + // [24] phi from main to main::@2 [phi:main->main::@2] + // main::@2 + // memcpy_to_vram((char)>VERA_SPRITE_ATTR, memcpy_to_vram] + // [33] phi memcpy_to_vram::num#3 = SIZEOF_STRUCT_VERA_SPRITE [phi:main::@2->memcpy_to_vram#0] -- vwuz1=vbuc1 + lda #SIZEOF_STRUCT_VERA_SPRITE + sta.z memcpy_to_vram.num+1 + // [33] phi memcpy_to_vram::src#3 = (void*)&SPRITE_ATTR [phi:main::@2->memcpy_to_vram#1] -- pvoz1=pvoc1 + lda #SPRITE_ATTR + sta.z memcpy_to_vram.src+1 + // [33] phi memcpy_to_vram::vbank#3 = (byte)>VERA_SPRITE_ATTR [phi:main::@2->memcpy_to_vram#2] -- vbuxx=vbuc1 + ldx #VERA_SPRITE_ATTR>>$10 + // [33] phi memcpy_to_vram::vdest#3 = (void*)memcpy_to_vram#3] -- pvoz1=pvoc1 + lda #VERA_SPRITE_ATTR&$ffff + sta.z memcpy_to_vram.vdest+1 + jsr memcpy_to_vram + // main::@3 + // *VERA_CTRL &= ~VERA_DCSEL + // [26] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2 + // Enable sprites + lda #VERA_DCSEL^$ff + and VERA_CTRL + sta VERA_CTRL + // *VERA_DC_VIDEO |= VERA_SPRITES_ENABLE + // [27] *VERA_DC_VIDEO = *VERA_DC_VIDEO | VERA_SPRITES_ENABLE -- _deref_pbuc1=_deref_pbuc1_bor_vbuc2 + lda #VERA_SPRITES_ENABLE + ora VERA_DC_VIDEO + sta VERA_DC_VIDEO + // main::SEI1 + // asm + // asm { sei } + sei + // main::@1 + // *KERNEL_IRQ = &irq_vsync + // [29] *KERNEL_IRQ = &irq_vsync -- _deref_qprc1=pprc2 + lda #irq_vsync + sta KERNEL_IRQ+1 + // *VERA_IEN = VERA_VSYNC + // [30] *VERA_IEN = VERA_VSYNC -- _deref_pbuc1=vbuc2 + lda #VERA_VSYNC + sta VERA_IEN + // main::CLI1 + // asm + // asm { cli } + cli + // main::@return + // } + // [32] return + rts +} + // memcpy_to_vram +// Copy block of memory (from RAM to VRAM) +// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination in VRAM. +// - vbank: Which 64K VRAM bank to put data into (0/1) +// - vdest: The destination address in VRAM +// - src: The source address in RAM +// - num: The number of bytes to copy +// memcpy_to_vram(byte register(X) vbank, void* zp(2) vdest, void* zp(4) src, word zp(6) num) +memcpy_to_vram: { + .label end = 6 + .label s = 4 + .label vdest = 2 + .label src = 4 + .label num = 6 + // *VERA_CTRL &= ~VERA_ADDRSEL + // [34] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2 + // Select DATA0 + lda #VERA_ADDRSEL^$ff + and VERA_CTRL + sta VERA_CTRL + // vdest + // [37] memcpy_to_vram::$1 = > memcpy_to_vram::vdest#3 -- vbuaa=_hi_pvoz1 + lda.z vdest+1 + // *VERA_ADDRX_M = >vdest + // [38] *VERA_ADDRX_M = memcpy_to_vram::$1 -- _deref_pbuc1=vbuaa + sta VERA_ADDRX_M + // VERA_INC_1 | vbank + // [39] memcpy_to_vram::$2 = VERA_INC_1 | memcpy_to_vram::vbank#3 -- vbuaa=vbuc1_bor_vbuxx + txa + ora #VERA_INC_1 + // *VERA_ADDRX_H = VERA_INC_1 | vbank + // [40] *VERA_ADDRX_H = memcpy_to_vram::$2 -- _deref_pbuc1=vbuaa + sta VERA_ADDRX_H + // end = (char*)src+num + // [41] memcpy_to_vram::end#0 = (byte*)memcpy_to_vram::src#3 + memcpy_to_vram::num#3 -- pbuz1=pbuz2_plus_vwuz1 + lda.z end + clc + adc.z src + sta.z end + lda.z end+1 + adc.z src+1 + sta.z end+1 + // [42] memcpy_to_vram::s#4 = (byte*)memcpy_to_vram::src#3 + // [43] phi from memcpy_to_vram memcpy_to_vram::@2 to memcpy_to_vram::@1 [phi:memcpy_to_vram/memcpy_to_vram::@2->memcpy_to_vram::@1] + // [43] phi memcpy_to_vram::s#2 = memcpy_to_vram::s#4 [phi:memcpy_to_vram/memcpy_to_vram::@2->memcpy_to_vram::@1#0] -- register_copy + // memcpy_to_vram::@1 + __b1: + // for(char *s = src; s!=end; s++) + // [44] if(memcpy_to_vram::s#2!=memcpy_to_vram::end#0) goto memcpy_to_vram::@2 -- pbuz1_neq_pbuz2_then_la1 + lda.z s+1 + cmp.z end+1 + bne __b2 + lda.z s + cmp.z end + bne __b2 + // memcpy_to_vram::@return + // } + // [45] return + rts + // memcpy_to_vram::@2 + __b2: + // *VERA_DATA0 = *s + // [46] *VERA_DATA0 = *memcpy_to_vram::s#2 -- _deref_pbuc1=_deref_pbuz1 + ldy #0 + lda (s),y + sta VERA_DATA0 + // for(char *s = src; s!=end; s++) + // [47] memcpy_to_vram::s#1 = ++ memcpy_to_vram::s#2 -- pbuz1=_inc_pbuz1 + inc.z s + bne !+ + inc.z s+1 + !: + jmp __b1 +} + // File Data +.segment Data + // A 64*64 8bpp sprite + .align $100 +SPRITE_PIXELS: +.var pic = LoadPicture("sprite.png", List().add($000000, $ffffff)) + .for (var x=0;x<64; x++) + .for (var y=0; y<64; y++) + .byte (pic.getPixel(x,y)==0) ? 0 : 1 + + // X sine [0;640-64] + .align $100 +SINX: +.fillword 256, 288+288*sin(i*2*PI/241) + + // Y sine [0;480-64] + .align $100 +SINY: +.fillword 256, 208+208*sin(i*2*PI/251) + + // Sprite attributes: 8bpp, in front, 64x64, address SPRITE_PIXELS_VRAM + SPRITE_ATTR: .word (SPRITE_PIXELS_VRAM/$20&$ffff)|VERA_SPRITE_8BPP, $140-$20, $f0-$20 + .byte $c, $f0 + diff --git a/src/test/ref/examples/cx16/sprite.sym b/src/test/ref/examples/cx16/sprite.sym new file mode 100644 index 000000000..0c8d212a5 --- /dev/null +++ b/src/test/ref/examples/cx16/sprite.sym @@ -0,0 +1,71 @@ +const nomodify void()** KERNEL_IRQ = (void()**) 788 +const byte OFFSET_STRUCT_VERA_SPRITE_X = 2 +const byte OFFSET_STRUCT_VERA_SPRITE_Y = 4 +const word* SINX[$f1] = kickasm {{ .fillword 256, 288+288*sin(i*2*PI/241) + }} +const word* SINY[$fb] = kickasm {{ .fillword 256, 208+208*sin(i*2*PI/251) + }} +const byte SIZEOF_BYTE = 1 +const byte SIZEOF_STRUCT_VERA_SPRITE = 8 +struct VERA_SPRITE SPRITE_ATTR loadstore mem[8] = { ADDR: src sta.z s+1 __b1: - // for(; s!=end; s++) + // for(char *s = src; s!=end; s++) lda.z s+1 cmp #>end bne __b2 @@ -129,7 +128,7 @@ memcpy_to_vram: { ldy #0 lda (s),y sta VERA_DATA0 - // for(; s!=end; s++) + // for(char *s = src; s!=end; s++) inc.z s bne !+ inc.z s+1 diff --git a/src/test/ref/examples/cx16/text.log b/src/test/ref/examples/cx16/text.log index 10452abcb..867732793 100644 --- a/src/test/ref/examples/cx16/text.log +++ b/src/test/ref/examples/cx16/text.log @@ -1,3 +1,4 @@ +Inlined call call __init CONTROL FLOW GRAPH SSA @@ -32,10 +33,10 @@ memcpy_to_vram: scope:[memcpy_to_vram] from main::@3 *VERA_ADDRX_M = memcpy_to_vram::$1 memcpy_to_vram::$2 = VERA_INC_1 | memcpy_to_vram::vbank#1 *VERA_ADDRX_H = memcpy_to_vram::$2 - memcpy_to_vram::s#0 = ((byte*)) memcpy_to_vram::src#1 memcpy_to_vram::$5 = (byte*)memcpy_to_vram::src#1 memcpy_to_vram::$3 = memcpy_to_vram::$5 + memcpy_to_vram::num#1 memcpy_to_vram::end#0 = memcpy_to_vram::$3 + memcpy_to_vram::s#0 = ((byte*)) memcpy_to_vram::src#1 to:memcpy_to_vram::@1 memcpy_to_vram::@1: scope:[memcpy_to_vram] from memcpy_to_vram memcpy_to_vram::@2 memcpy_to_vram::end#1 = phi( memcpy_to_vram/memcpy_to_vram::end#0, memcpy_to_vram::@2/memcpy_to_vram::end#2 ) @@ -54,7 +55,7 @@ memcpy_to_vram::@return: scope:[memcpy_to_vram] from memcpy_to_vram::@1 to:@return void main() -main: scope:[main] from __start +main: scope:[main] from __start::@1 main::vaddr#0 = DEFAULT_SCREEN main::i#0 = 0 to:main::@1 @@ -103,11 +104,15 @@ main::@return: scope:[main] from main::@6 void __start() __start: scope:[__start] from - call main + to:__start::__init1 +__start::__init1: scope:[__start] from __start to:__start::@1 -__start::@1: scope:[__start] from __start +__start::@1: scope:[__start] from __start::__init1 + call main + to:__start::@2 +__start::@2: scope:[__start] from __start::@1 to:__start::@return -__start::@return: scope:[__start] from __start::@1 +__start::@return: scope:[__start] from __start::@2 return to:@return @@ -249,8 +254,8 @@ Constant memcpy_to_vram::vbank#0 = 0 Constant memcpy_to_vram::vdest#0 = (void*)DEFAULT_SCREEN+$100 Constant memcpy_to_vram::src#0 = (void*)main::MSG2 Successful SSA optimization Pass2ConstantIdentification -Constant memcpy_to_vram::s#0 = (byte*)memcpy_to_vram::src#0 Constant memcpy_to_vram::$5 = (byte*)memcpy_to_vram::src#0 +Constant memcpy_to_vram::s#0 = (byte*)memcpy_to_vram::src#0 Successful SSA optimization Pass2ConstantIdentification Simplifying expression containing zero vpoke::vbank#2 in [6] vpoke::$2 = VERA_INC_0 | vpoke::vbank#2 Simplifying expression containing zero VERA_INC_1 in [16] memcpy_to_vram::$2 = VERA_INC_1 | memcpy_to_vram::vbank#0 @@ -260,7 +265,9 @@ Eliminating unused constant memcpy_to_vram::vbank#0 Successful SSA optimization PassNEliminateUnusedVars Removing unused procedure __start Removing unused procedure block __start +Removing unused procedure block __start::__init1 Removing unused procedure block __start::@1 +Removing unused procedure block __start::@2 Removing unused procedure block __start::@return Successful SSA optimization PassNEliminateEmptyStart Resolving string sizeof() sizeof main::MSG2 @@ -488,12 +495,14 @@ REGISTER UPLIFT SCOPES Uplift Scope [vpoke] 202: zp[1]:12 [ vpoke::$0 ] 202: zp[1]:13 [ vpoke::$1 ] 89: zp[2]:7 [ vpoke::vaddr#2 vpoke::vaddr#0 vpoke::vaddr#1 ] 38: zp[1]:9 [ vpoke::data#2 vpoke::data#0 ] Uplift Scope [memcpy_to_vram] 336.67: zp[2]:5 [ memcpy_to_vram::s#2 memcpy_to_vram::s#1 ] Uplift Scope [main] 26.89: zp[1]:2 [ main::i#2 main::i#1 ] 17.6: zp[2]:3 [ main::vaddr#3 main::vaddr#2 ] 11: zp[2]:10 [ main::vaddr#1 ] +Uplift Scope [VERA_SPRITE] Uplift Scope [MOS6522_VIA] Uplift Scope [] Uplifting [vpoke] best 1750 combination reg byte a [ vpoke::$0 ] reg byte a [ vpoke::$1 ] zp[2]:7 [ vpoke::vaddr#2 vpoke::vaddr#0 vpoke::vaddr#1 ] reg byte x [ vpoke::data#2 vpoke::data#0 ] Uplifting [memcpy_to_vram] best 1750 combination zp[2]:5 [ memcpy_to_vram::s#2 memcpy_to_vram::s#1 ] Uplifting [main] best 1630 combination reg byte y [ main::i#2 main::i#1 ] zp[2]:3 [ main::vaddr#3 main::vaddr#2 ] zp[2]:10 [ main::vaddr#1 ] +Uplifting [VERA_SPRITE] best 1630 combination Uplifting [MOS6522_VIA] best 1630 combination Uplifting [] best 1630 combination Coalescing zero page register [ zp[2]:3 [ main::vaddr#3 main::vaddr#2 ] ] with [ zp[2]:10 [ main::vaddr#1 ] ] - score: 2 @@ -638,7 +647,6 @@ memcpy_to_vram: { .label vdest = DEFAULT_SCREEN+$100 .label src = main.MSG2 .label end = src+num - // Transfer the data .label s = 4 // [14] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2 // Select DATA0 @@ -942,7 +950,6 @@ memcpy_to_vram: { .label vdest = DEFAULT_SCREEN+$100 .label src = main.MSG2 .label end = src+num - // Transfer the data .label s = 4 // *VERA_CTRL &= ~VERA_ADDRSEL // [14] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2 @@ -971,7 +978,7 @@ memcpy_to_vram: { sta.z s+1 // memcpy_to_vram::@1 __b1: - // for(; s!=end; s++) + // for(char *s = src; s!=end; s++) // [19] if(memcpy_to_vram::s#2!=memcpy_to_vram::end#0) goto memcpy_to_vram::@2 -- pbuz1_neq_pbuc1_then_la1 lda.z s+1 cmp #>end @@ -990,7 +997,7 @@ memcpy_to_vram: { ldy #0 lda (s),y sta VERA_DATA0 - // for(; s!=end; s++) + // for(char *s = src; s!=end; s++) // [22] memcpy_to_vram::s#1 = ++ memcpy_to_vram::s#2 -- pbuz1=_inc_pbuz1 inc.z s bne !+