From 2d58a799d50d1e9cbc5cdef7a7f21787a4fd43cd Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Tue, 15 Dec 2020 01:00:39 +0100 Subject: [PATCH] Improved simple VRAM example. #581 --- src/main/kc/include/cx16.h | 19 +- src/main/kc/lib/cx16.c | 30 +- src/main/kc/target/cx16.tgt | 2 +- src/test/kc/examples/cx16/text.c | 13 +- src/test/ref/examples/cx16/text.asm | 101 +++- src/test/ref/examples/cx16/text.cfg | 81 ++- src/test/ref/examples/cx16/text.log | 849 ++++++++++++++++++++-------- src/test/ref/examples/cx16/text.sym | 32 +- 8 files changed, 825 insertions(+), 302 deletions(-) diff --git a/src/main/kc/include/cx16.h b/src/main/kc/include/cx16.h index 24749f7a3..6e27ea1db 100644 --- a/src/main/kc/include/cx16.h +++ b/src/main/kc/include/cx16.h @@ -35,9 +35,22 @@ void()** const KERNEL_IRQ = 0x0314; // $0316 (RAM) BRK vector - The vector used when the KERNAL serves IRQ caused by a BRK void()** const KERNEL_BRK = 0x0316; +// VRAM Address of the default screen +char * const DEFAULT_SCREEN = 0x0000; +// VRAM Bank (0/1) of the default screen +char * const DEFAULT_SCREEN_VBANK = 0; + // Put a single byte into VRAM. // Uses VERA DATA0 -// - bank: Which 64K VRAM bank to put data into (0/1) -// - addr: The address in VRAM +// - vbank: Which 64K VRAM bank to put data into (0/1) +// - vaddr: The address in VRAM // - data: The data to put into VRAM -void vpoke(char bank, char* addr, char data); \ No newline at end of file +void vpoke(char vbank, char* vaddr, char data); + +// 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 +void memcpy_to_vram(char vbank, void* vdest, void* src, unsigned int num ); diff --git a/src/main/kc/lib/cx16.c b/src/main/kc/lib/cx16.c index 65555da98..0570f200b 100644 --- a/src/main/kc/lib/cx16.c +++ b/src/main/kc/lib/cx16.c @@ -9,13 +9,33 @@ // - bank: Which 64K VRAM bank to put data into (0/1) // - addr: The address in VRAM // - data: The data to put into VRAM -void vpoke(char bank, char* addr, char data) { +void vpoke(char vbank, char* vaddr, char data) { // Select DATA0 *VERA_CTRL &= ~VERA_ADDRSEL; // Set address - *VERA_ADDRX_L = addr; - *VERA_ADDRX_H = VERA_INC_0 | bank; + *VERA_ADDRX_L = vaddr; + *VERA_ADDRX_H = VERA_INC_0 | vbank; // Set data *VERA_DATA0 = data; -} \ No newline at end of file +} + +// 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 +void memcpy_to_vram(char vbank, void* vdest, void* src, unsigned int num ) { + // Select DATA0 + *VERA_CTRL &= ~VERA_ADDRSEL; + // Set address + *VERA_ADDRX_L = vdest; + *VERA_ADDRX_H = VERA_INC_1 | vbank; + // Transfer the data + char *s = src; + char *end = (char*)src+num; + for(; s!=end; s++) + *VERA_DATA0 = *s; +} diff --git a/src/main/kc/target/cx16.tgt b/src/main/kc/target/cx16.tgt index bdf51bbdd..53863cd3c 100644 --- a/src/main/kc/target/cx16.tgt +++ b/src/main/kc/target/cx16.tgt @@ -4,7 +4,7 @@ "link": "cx16.ld", "start_address": "0x080d", "cpu": "WDC65C02", - "emulator": "x16emu -debug -run -prg", + "emulator": "x16emu -debug -run -scale 2 -prg", "defines": { "__CX16__": 1 } diff --git a/src/test/kc/examples/cx16/text.c b/src/test/kc/examples/cx16/text.c index e19279dba..17be9dc92 100644 --- a/src/test/kc/examples/cx16/text.c +++ b/src/test/kc/examples/cx16/text.c @@ -5,11 +5,18 @@ #include void main() { + + // Copy message to screen one char at a time char MSG[] = "hello world!"; - // Address of the default screen - char* vaddr = 0x0000; + char* vaddr = DEFAULT_SCREEN; for(char i=0;MSG[i];i++) { vpoke(0, vaddr++, MSG[i]); // Message vpoke(0, vaddr++, 0x21); // Red background, White foreground } -} \ No newline at end of file + + // 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)); + +} + diff --git a/src/test/ref/examples/cx16/text.asm b/src/test/ref/examples/cx16/text.asm index 195dd1e40..065e2851f 100644 --- a/src/test/ref/examples/cx16/text.asm +++ b/src/test/ref/examples/cx16/text.asm @@ -12,7 +12,9 @@ .segment Code + .const VERA_INC_1 = $10 .const VERA_ADDRSEL = 1 + .const SIZEOF_BYTE = 1 // $9F20 VRAM Address (7:0) .label VERA_ADDRX_L = $9f20 // $9F21 VRAM Address (15:8) @@ -30,19 +32,24 @@ // Bit 1: DCSEL // Bit 2: ADDRSEL .label VERA_CTRL = $9f25 + // VRAM Address of the default screen + .label DEFAULT_SCREEN = 0 .segment Code main: { - // Address of the default screen .label vaddr = 2 - lda #<0 + lda #DEFAULT_SCREEN sta.z vaddr+1 - tay + ldy #0 __b1: // for(char i=0;MSG[i];i++) lda MSG,y cmp #0 bne __b2 + // memcpy_to_vram(0, DEFAULT_SCREEN+0x100, MSG2, sizeof(MSG2)) + // Space is 0x20, red background black foreground + jsr memcpy_to_vram // } rts __b2: @@ -67,33 +74,91 @@ main: { iny jmp __b1 .segment Data + // Copy message to screen one char at a time MSG: .text "hello world!" .byte 0 + // Copy message (and colors) to screen using memcpy_to_vram + MSG2: .text "h e l l o w o r l d ! " + .byte 0 } .segment Code -// Put a single byte into VRAM. -// Uses VERA DATA0 -// - bank: Which 64K VRAM bank to put data into (0/1) -// - addr: The address in VRAM -// - data: The data to put into VRAM -// vpoke(byte* zp(2) addr, byte register(X) data) -vpoke: { - .label addr = 2 +// 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: { + .const num = $19*SIZEOF_BYTE + .label vdest = DEFAULT_SCREEN+$100 + .label src = main.MSG2 + .label end = src+num + // Transfer the data + .label s = 4 // *VERA_CTRL &= ~VERA_ADDRSEL // Select DATA0 lda #VERA_ADDRSEL^$ff and VERA_CTRL sta VERA_CTRL - // vdest + lda #>vdest + sta VERA_ADDRX_M + // *VERA_ADDRX_H = VERA_INC_1 | vbank + lda #VERA_INC_1 + sta VERA_ADDRX_H + lda #src + sta.z s+1 + __b1: + // for(; s!=end; s++) + lda.z s+1 + cmp #>end + bne __b2 + lda.z s + cmp #addr - lda.z addr+1 - // *VERA_ADDRX_M = >addr + // >vaddr + lda.z vaddr+1 + // *VERA_ADDRX_M = >vaddr sta VERA_ADDRX_M - // *VERA_ADDRX_H = VERA_INC_0 | bank + // *VERA_ADDRX_H = VERA_INC_0 | vbank lda #0 sta VERA_ADDRX_H // *VERA_DATA0 = data diff --git a/src/test/ref/examples/cx16/text.cfg b/src/test/ref/examples/cx16/text.cfg index 098b654c0..5131c2785 100644 --- a/src/test/ref/examples/cx16/text.cfg +++ b/src/test/ref/examples/cx16/text.cfg @@ -3,41 +3,64 @@ void main() main: scope:[main] from [0] phi() to:main::@1 -main::@1: scope:[main] from main main::@4 - [1] main::vaddr#3 = phi( main/(byte*) 0, main::@4/main::vaddr#2 ) - [1] main::i#2 = phi( main/0, main::@4/main::i#1 ) +main::@1: scope:[main] from main main::@5 + [1] main::vaddr#3 = phi( main/DEFAULT_SCREEN, main::@5/main::vaddr#2 ) + [1] main::i#2 = phi( main/0, main::@5/main::i#1 ) [2] if(0!=main::MSG[main::i#2]) goto main::@2 + to:main::@3 +main::@3: scope:[main] from main::@1 + [3] phi() + [4] call memcpy_to_vram to:main::@return -main::@return: scope:[main] from main::@1 - [3] return +main::@return: scope:[main] from main::@3 + [5] return to:@return main::@2: scope:[main] from main::@1 - [4] vpoke::addr#0 = main::vaddr#3 - [5] vpoke::data#0 = main::MSG[main::i#2] - [6] call vpoke - to:main::@3 -main::@3: scope:[main] from main::@2 - [7] main::vaddr#1 = ++ main::vaddr#3 - [8] vpoke::addr#1 = main::vaddr#1 - [9] call vpoke + [6] vpoke::vaddr#0 = main::vaddr#3 + [7] vpoke::data#0 = main::MSG[main::i#2] + [8] call vpoke to:main::@4 -main::@4: scope:[main] from main::@3 - [10] main::vaddr#2 = ++ main::vaddr#1 - [11] main::i#1 = ++ main::i#2 +main::@4: scope:[main] from main::@2 + [9] main::vaddr#1 = ++ main::vaddr#3 + [10] vpoke::vaddr#1 = main::vaddr#1 + [11] call vpoke + to:main::@5 +main::@5: scope:[main] from main::@4 + [12] main::vaddr#2 = ++ main::vaddr#1 + [13] main::i#1 = ++ main::i#2 to:main::@1 -void vpoke(byte vpoke::bank , byte* vpoke::addr , byte vpoke::data) -vpoke: scope:[vpoke] from main::@2 main::@3 - [12] vpoke::data#2 = phi( main::@2/vpoke::data#0, main::@3/$21 ) - [12] vpoke::addr#2 = phi( main::@2/vpoke::addr#0, main::@3/vpoke::addr#1 ) - [13] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL - [14] vpoke::$0 = < vpoke::addr#2 - [15] *VERA_ADDRX_L = vpoke::$0 - [16] vpoke::$1 = > vpoke::addr#2 - [17] *VERA_ADDRX_M = vpoke::$1 - [18] *VERA_ADDRX_H = 0 - [19] *VERA_DATA0 = vpoke::data#2 - to:vpoke::@return -vpoke::@return: scope:[vpoke] from vpoke +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 main::@3 + [14] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL + [15] *VERA_ADDRX_L = 0 + [16] *VERA_ADDRX_M = >memcpy_to_vram::vdest#0 + [17] *VERA_ADDRX_H = VERA_INC_1 + to:memcpy_to_vram::@1 +memcpy_to_vram::@1: scope:[memcpy_to_vram] from memcpy_to_vram memcpy_to_vram::@2 + [18] memcpy_to_vram::s#2 = phi( memcpy_to_vram/(byte*)memcpy_to_vram::src#0, memcpy_to_vram::@2/memcpy_to_vram::s#1 ) + [19] 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 [20] return to:@return +memcpy_to_vram::@2: scope:[memcpy_to_vram] from memcpy_to_vram::@1 + [21] *VERA_DATA0 = *memcpy_to_vram::s#2 + [22] memcpy_to_vram::s#1 = ++ memcpy_to_vram::s#2 + to:memcpy_to_vram::@1 + +void vpoke(byte vpoke::vbank , byte* vpoke::vaddr , byte vpoke::data) +vpoke: scope:[vpoke] from main::@2 main::@4 + [23] vpoke::data#2 = phi( main::@2/vpoke::data#0, main::@4/$21 ) + [23] vpoke::vaddr#2 = phi( main::@2/vpoke::vaddr#0, main::@4/vpoke::vaddr#1 ) + [24] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL + [25] vpoke::$0 = < vpoke::vaddr#2 + [26] *VERA_ADDRX_L = vpoke::$0 + [27] vpoke::$1 = > vpoke::vaddr#2 + [28] *VERA_ADDRX_M = vpoke::$1 + [29] *VERA_ADDRX_H = 0 + [30] *VERA_DATA0 = vpoke::data#2 + to:vpoke::@return +vpoke::@return: scope:[vpoke] from vpoke + [31] return + to:@return diff --git a/src/test/ref/examples/cx16/text.log b/src/test/ref/examples/cx16/text.log index 7678129de..10452abcb 100644 --- a/src/test/ref/examples/cx16/text.log +++ b/src/test/ref/examples/cx16/text.log @@ -1,17 +1,17 @@ CONTROL FLOW GRAPH SSA -void vpoke(byte vpoke::bank , byte* vpoke::addr , byte vpoke::data) -vpoke: scope:[vpoke] from main::@2 main::@3 - vpoke::data#2 = phi( main::@2/vpoke::data#0, main::@3/vpoke::data#1 ) - vpoke::bank#2 = phi( main::@2/vpoke::bank#0, main::@3/vpoke::bank#1 ) - vpoke::addr#2 = phi( main::@2/vpoke::addr#0, main::@3/vpoke::addr#1 ) +void vpoke(byte vpoke::vbank , byte* vpoke::vaddr , byte vpoke::data) +vpoke: scope:[vpoke] from main::@2 main::@4 + vpoke::data#2 = phi( main::@2/vpoke::data#0, main::@4/vpoke::data#1 ) + vpoke::vbank#2 = phi( main::@2/vpoke::vbank#0, main::@4/vpoke::vbank#1 ) + vpoke::vaddr#2 = phi( main::@2/vpoke::vaddr#0, main::@4/vpoke::vaddr#1 ) *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL - vpoke::$0 = < vpoke::addr#2 + vpoke::$0 = < vpoke::vaddr#2 *VERA_ADDRX_L = vpoke::$0 - vpoke::$1 = > vpoke::addr#2 + vpoke::$1 = > vpoke::vaddr#2 *VERA_ADDRX_M = vpoke::$1 - vpoke::$2 = VERA_INC_0 | vpoke::bank#2 + vpoke::$2 = VERA_INC_0 | vpoke::vbank#2 *VERA_ADDRX_H = vpoke::$2 *VERA_DATA0 = vpoke::data#2 to:vpoke::@return @@ -19,41 +19,85 @@ vpoke::@return: scope:[vpoke] from vpoke 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 main::@3 + memcpy_to_vram::num#1 = phi( main::@3/memcpy_to_vram::num#0 ) + memcpy_to_vram::src#1 = phi( main::@3/memcpy_to_vram::src#0 ) + memcpy_to_vram::vbank#1 = phi( main::@3/memcpy_to_vram::vbank#0 ) + memcpy_to_vram::vdest#1 = phi( main::@3/memcpy_to_vram::vdest#0 ) + *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL + memcpy_to_vram::$0 = < memcpy_to_vram::vdest#1 + *VERA_ADDRX_L = memcpy_to_vram::$0 + memcpy_to_vram::$1 = > memcpy_to_vram::vdest#1 + *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 + 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 - main::vaddr#0 = (byte*)0 + main::vaddr#0 = DEFAULT_SCREEN main::i#0 = 0 to:main::@1 -main::@1: scope:[main] from main main::@4 - main::vaddr#6 = phi( main/main::vaddr#0, main::@4/main::vaddr#2 ) - main::i#2 = phi( main/main::i#0, main::@4/main::i#1 ) - main::$2 = 0 != main::MSG[main::i#2] - if(main::$2) goto main::@2 - to:main::@return +main::@1: scope:[main] from main main::@5 + main::vaddr#6 = phi( main/main::vaddr#0, main::@5/main::vaddr#2 ) + main::i#2 = phi( main/main::i#0, main::@5/main::i#1 ) + main::$4 = 0 != main::MSG[main::i#2] + if(main::$4) goto main::@2 + to:main::@3 main::@2: scope:[main] from main::@1 main::i#3 = phi( main::@1/main::i#2 ) main::vaddr#3 = phi( main::@1/main::vaddr#6 ) - vpoke::bank#0 = 0 - vpoke::addr#0 = main::vaddr#3 + vpoke::vbank#0 = 0 + vpoke::vaddr#0 = main::vaddr#3 vpoke::data#0 = main::MSG[main::i#3] call vpoke - to:main::@3 -main::@3: scope:[main] from main::@2 + to:main::@4 +main::@4: scope:[main] from main::@2 main::i#5 = phi( main::@2/main::i#3 ) main::vaddr#4 = phi( main::@2/main::vaddr#3 ) main::vaddr#1 = ++ main::vaddr#4 - vpoke::bank#1 = 0 - vpoke::addr#1 = main::vaddr#1 + vpoke::vbank#1 = 0 + vpoke::vaddr#1 = main::vaddr#1 vpoke::data#1 = $21 call vpoke - to:main::@4 -main::@4: scope:[main] from main::@3 - main::i#4 = phi( main::@3/main::i#5 ) - main::vaddr#5 = phi( main::@3/main::vaddr#1 ) + to:main::@5 +main::@5: scope:[main] from main::@4 + main::i#4 = phi( main::@4/main::i#5 ) + main::vaddr#5 = phi( main::@4/main::vaddr#1 ) main::vaddr#2 = ++ main::vaddr#5 main::i#1 = ++ main::i#4 to:main::@1 -main::@return: scope:[main] from main::@1 +main::@3: scope:[main] from main::@1 + main::$0 = sizeof main::MSG2 + memcpy_to_vram::vbank#0 = 0 + memcpy_to_vram::vdest#0 = (void*)DEFAULT_SCREEN+$100 + memcpy_to_vram::src#0 = (void*)main::MSG2 + memcpy_to_vram::num#0 = main::$0 + call memcpy_to_vram + to:main::@6 +main::@6: scope:[main] from main::@3 + to:main::@return +main::@return: scope:[main] from main::@6 return to:@return @@ -68,6 +112,7 @@ __start::@return: scope:[__start] from __start::@1 to:@return SYMBOL TABLE SSA +const nomodify byte* DEFAULT_SCREEN = (byte*)0 const nomodify byte VERA_ADDRSEL = 1 const nomodify byte* VERA_ADDRX_H = (byte*)$9f22 const nomodify byte* VERA_ADDRX_L = (byte*)$9f20 @@ -75,10 +120,13 @@ const nomodify byte* VERA_ADDRX_M = (byte*)$9f21 const nomodify byte* VERA_CTRL = (byte*)$9f25 const nomodify byte* VERA_DATA0 = (byte*)$9f23 const nomodify byte VERA_INC_0 = 0 +const nomodify byte VERA_INC_1 = $10 void __start() void main() -bool~ main::$2 +byte~ main::$0 +bool~ main::$4 const byte* main::MSG[] = "hello world!" +const byte* main::MSG2[] = "h e l l o w o r l d ! " byte main::i byte main::i#0 byte main::i#1 @@ -94,31 +142,63 @@ byte* main::vaddr#3 byte* main::vaddr#4 byte* main::vaddr#5 byte* main::vaddr#6 -void vpoke(byte vpoke::bank , byte* vpoke::addr , byte vpoke::data) +void memcpy_to_vram(byte memcpy_to_vram::vbank , void* memcpy_to_vram::vdest , void* memcpy_to_vram::src , word memcpy_to_vram::num) +byte~ memcpy_to_vram::$0 +byte~ memcpy_to_vram::$1 +byte~ memcpy_to_vram::$2 +byte*~ memcpy_to_vram::$3 +bool~ memcpy_to_vram::$4 +byte*~ memcpy_to_vram::$5 +byte* memcpy_to_vram::end +byte* memcpy_to_vram::end#0 +byte* memcpy_to_vram::end#1 +byte* memcpy_to_vram::end#2 +word memcpy_to_vram::num +word memcpy_to_vram::num#0 +word memcpy_to_vram::num#1 +byte* memcpy_to_vram::s +byte* memcpy_to_vram::s#0 +byte* memcpy_to_vram::s#1 +byte* memcpy_to_vram::s#2 +byte* memcpy_to_vram::s#3 +void* memcpy_to_vram::src +void* memcpy_to_vram::src#0 +void* memcpy_to_vram::src#1 +byte memcpy_to_vram::vbank +byte memcpy_to_vram::vbank#0 +byte memcpy_to_vram::vbank#1 +void* memcpy_to_vram::vdest +void* memcpy_to_vram::vdest#0 +void* memcpy_to_vram::vdest#1 +void vpoke(byte vpoke::vbank , byte* vpoke::vaddr , byte vpoke::data) byte~ vpoke::$0 byte~ vpoke::$1 byte~ vpoke::$2 -byte* vpoke::addr -byte* vpoke::addr#0 -byte* vpoke::addr#1 -byte* vpoke::addr#2 -byte vpoke::bank -byte vpoke::bank#0 -byte vpoke::bank#1 -byte vpoke::bank#2 byte vpoke::data byte vpoke::data#0 byte vpoke::data#1 byte vpoke::data#2 +byte* vpoke::vaddr +byte* vpoke::vaddr#0 +byte* vpoke::vaddr#1 +byte* vpoke::vaddr#2 +byte vpoke::vbank +byte vpoke::vbank#0 +byte vpoke::vbank#1 +byte vpoke::vbank#2 -Adding number conversion cast (unumber) 0 in main::$2 = 0 != main::MSG[main::i#2] -Adding number conversion cast (unumber) 0 in vpoke::bank#0 = 0 -Adding number conversion cast (unumber) 0 in vpoke::bank#1 = 0 +Adding number conversion cast (unumber) 0 in main::$4 = 0 != main::MSG[main::i#2] +Adding number conversion cast (unumber) 0 in vpoke::vbank#0 = 0 +Adding number conversion cast (unumber) 0 in vpoke::vbank#1 = 0 Adding number conversion cast (unumber) $21 in vpoke::data#1 = $21 +Adding number conversion cast (unumber) 0 in memcpy_to_vram::vbank#0 = 0 +Adding number conversion cast (unumber) $100 in memcpy_to_vram::vdest#0 = (void*)DEFAULT_SCREEN+$100 Successful SSA optimization PassNAddNumberTypeConversions -Inlining cast vpoke::bank#0 = (unumber)0 -Inlining cast vpoke::bank#1 = (unumber)0 +Inlining cast memcpy_to_vram::s#0 = (byte*)memcpy_to_vram::src#1 +Inlining cast vpoke::vbank#0 = (unumber)0 +Inlining cast vpoke::vbank#1 = (unumber)0 Inlining cast vpoke::data#1 = (unumber)$21 +Inlining cast memcpy_to_vram::vbank#0 = (unumber)0 Successful SSA optimization Pass2InlineCast Simplifying constant pointer cast (byte*) 40736 Simplifying constant pointer cast (byte*) 40737 @@ -130,60 +210,116 @@ Simplifying constant integer cast 0 Simplifying constant integer cast 0 Simplifying constant integer cast 0 Simplifying constant integer cast $21 +Simplifying constant integer cast 0 +Simplifying constant integer cast $100 Successful SSA optimization PassNCastSimplification Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) $21 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (word) $100 Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias memcpy_to_vram::end#0 = memcpy_to_vram::$3 +Alias memcpy_to_vram::s#2 = memcpy_to_vram::s#3 +Alias memcpy_to_vram::end#1 = memcpy_to_vram::end#2 Alias main::vaddr#3 = main::vaddr#6 main::vaddr#4 Alias main::i#2 = main::i#3 main::i#5 main::i#4 Alias main::vaddr#1 = main::vaddr#5 +Alias memcpy_to_vram::num#0 = main::$0 Successful SSA optimization Pass2AliasElimination -Simple Condition main::$2 [14] if(0!=main::MSG[main::i#2]) goto main::@2 +Identical Phi Values memcpy_to_vram::vdest#1 memcpy_to_vram::vdest#0 +Identical Phi Values memcpy_to_vram::vbank#1 memcpy_to_vram::vbank#0 +Identical Phi Values memcpy_to_vram::src#1 memcpy_to_vram::src#0 +Identical Phi Values memcpy_to_vram::num#1 memcpy_to_vram::num#0 +Identical Phi Values memcpy_to_vram::end#1 memcpy_to_vram::end#0 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition memcpy_to_vram::$4 [23] if(memcpy_to_vram::s#2!=memcpy_to_vram::end#0) goto memcpy_to_vram::@2 +Simple Condition main::$4 [31] if(0!=main::MSG[main::i#2]) goto main::@2 Successful SSA optimization Pass2ConditionalJumpSimplification -Constant main::vaddr#0 = (byte*) 0 +Constant right-side identified [43] memcpy_to_vram::num#0 = sizeof main::MSG2 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant main::vaddr#0 = DEFAULT_SCREEN Constant main::i#0 = 0 -Constant vpoke::bank#0 = 0 -Constant vpoke::bank#1 = 0 +Constant vpoke::vbank#0 = 0 +Constant vpoke::vbank#1 = 0 Constant vpoke::data#1 = $21 +Constant memcpy_to_vram::num#0 = sizeof main::MSG2 +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 -Simplifying expression containing zero vpoke::bank#2 in [6] vpoke::$2 = VERA_INC_0 | vpoke::bank#2 +Constant memcpy_to_vram::s#0 = (byte*)memcpy_to_vram::src#0 +Constant memcpy_to_vram::$5 = (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 Successful SSA optimization PassNSimplifyExpressionWithZero Eliminating unused constant VERA_INC_0 +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::@1 Removing unused procedure block __start::@return Successful SSA optimization PassNEliminateEmptyStart -Alias vpoke::bank#2 = vpoke::$2 +Resolving string sizeof() sizeof main::MSG2 +Successful SSA optimization PassNSizeOfSimplification +Alias vpoke::vbank#2 = vpoke::$2 Successful SSA optimization Pass2AliasElimination -Inlining constant with var siblings vpoke::bank#0 -Inlining constant with var siblings vpoke::bank#1 +Constant right-side identified [10] memcpy_to_vram::$0 = < memcpy_to_vram::vdest#0 +Constant right-side identified [12] memcpy_to_vram::$1 = > memcpy_to_vram::vdest#0 +Constant right-side identified [16] memcpy_to_vram::end#0 = memcpy_to_vram::$5 + memcpy_to_vram::num#0 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant memcpy_to_vram::$0 = memcpy_to_vram::vdest#0 +Constant memcpy_to_vram::$2 = VERA_INC_1 +Constant memcpy_to_vram::end#0 = memcpy_to_vram::$5+memcpy_to_vram::num#0 +Successful SSA optimization Pass2ConstantIdentification +Simplifying constant evaluating to zero memcpy_to_vram::vdest#0 +Constant inlined vpoke::vbank#0 = 0 +Constant inlined memcpy_to_vram::$5 = (byte*)memcpy_to_vram::src#0 +Constant inlined vpoke::vbank#1 = 0 Constant inlined vpoke::data#1 = $21 Successful SSA optimization Pass2ConstantInlining -Identical Phi Values vpoke::bank#2 0 +Identical Phi Values vpoke::vbank#2 0 Successful SSA optimization Pass2IdenticalPhiElimination Adding NOP phi() at start of main +Adding NOP phi() at start of main::@3 +Adding NOP phi() at start of main::@6 CALL GRAPH -Calls in [main] to vpoke:8 vpoke:12 +Calls in [main] to memcpy_to_vram:4 vpoke:11 vpoke:15 -Created 4 initial phi equivalence classes -Coalesced [6] vpoke::addr#3 = vpoke::addr#0 -Coalesced [7] vpoke::data#3 = vpoke::data#0 -Coalesced [11] vpoke::addr#4 = vpoke::addr#1 -Coalesced [15] main::i#6 = main::i#1 -Coalesced [16] main::vaddr#7 = main::vaddr#2 -Coalesced down to 4 phi equivalence classes +Created 5 initial phi equivalence classes +Coalesced [9] vpoke::vaddr#3 = vpoke::vaddr#0 +Coalesced [10] vpoke::data#3 = vpoke::data#0 +Coalesced [14] vpoke::vaddr#4 = vpoke::vaddr#1 +Coalesced [18] main::i#6 = main::i#1 +Coalesced [19] main::vaddr#7 = main::vaddr#2 +Coalesced [29] memcpy_to_vram::s#4 = memcpy_to_vram::s#1 +Coalesced down to 5 phi equivalence classes +Culled Empty Block label main::@6 Adding NOP phi() at start of main +Adding NOP phi() at start of main::@3 FINAL CONTROL FLOW GRAPH @@ -191,43 +327,66 @@ void main() main: scope:[main] from [0] phi() to:main::@1 -main::@1: scope:[main] from main main::@4 - [1] main::vaddr#3 = phi( main/(byte*) 0, main::@4/main::vaddr#2 ) - [1] main::i#2 = phi( main/0, main::@4/main::i#1 ) +main::@1: scope:[main] from main main::@5 + [1] main::vaddr#3 = phi( main/DEFAULT_SCREEN, main::@5/main::vaddr#2 ) + [1] main::i#2 = phi( main/0, main::@5/main::i#1 ) [2] if(0!=main::MSG[main::i#2]) goto main::@2 + to:main::@3 +main::@3: scope:[main] from main::@1 + [3] phi() + [4] call memcpy_to_vram to:main::@return -main::@return: scope:[main] from main::@1 - [3] return +main::@return: scope:[main] from main::@3 + [5] return to:@return main::@2: scope:[main] from main::@1 - [4] vpoke::addr#0 = main::vaddr#3 - [5] vpoke::data#0 = main::MSG[main::i#2] - [6] call vpoke - to:main::@3 -main::@3: scope:[main] from main::@2 - [7] main::vaddr#1 = ++ main::vaddr#3 - [8] vpoke::addr#1 = main::vaddr#1 - [9] call vpoke + [6] vpoke::vaddr#0 = main::vaddr#3 + [7] vpoke::data#0 = main::MSG[main::i#2] + [8] call vpoke to:main::@4 -main::@4: scope:[main] from main::@3 - [10] main::vaddr#2 = ++ main::vaddr#1 - [11] main::i#1 = ++ main::i#2 +main::@4: scope:[main] from main::@2 + [9] main::vaddr#1 = ++ main::vaddr#3 + [10] vpoke::vaddr#1 = main::vaddr#1 + [11] call vpoke + to:main::@5 +main::@5: scope:[main] from main::@4 + [12] main::vaddr#2 = ++ main::vaddr#1 + [13] main::i#1 = ++ main::i#2 to:main::@1 -void vpoke(byte vpoke::bank , byte* vpoke::addr , byte vpoke::data) -vpoke: scope:[vpoke] from main::@2 main::@3 - [12] vpoke::data#2 = phi( main::@2/vpoke::data#0, main::@3/$21 ) - [12] vpoke::addr#2 = phi( main::@2/vpoke::addr#0, main::@3/vpoke::addr#1 ) - [13] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL - [14] vpoke::$0 = < vpoke::addr#2 - [15] *VERA_ADDRX_L = vpoke::$0 - [16] vpoke::$1 = > vpoke::addr#2 - [17] *VERA_ADDRX_M = vpoke::$1 - [18] *VERA_ADDRX_H = 0 - [19] *VERA_DATA0 = vpoke::data#2 +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 main::@3 + [14] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL + [15] *VERA_ADDRX_L = 0 + [16] *VERA_ADDRX_M = >memcpy_to_vram::vdest#0 + [17] *VERA_ADDRX_H = VERA_INC_1 + to:memcpy_to_vram::@1 +memcpy_to_vram::@1: scope:[memcpy_to_vram] from memcpy_to_vram memcpy_to_vram::@2 + [18] memcpy_to_vram::s#2 = phi( memcpy_to_vram/(byte*)memcpy_to_vram::src#0, memcpy_to_vram::@2/memcpy_to_vram::s#1 ) + [19] 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 + [20] return + to:@return +memcpy_to_vram::@2: scope:[memcpy_to_vram] from memcpy_to_vram::@1 + [21] *VERA_DATA0 = *memcpy_to_vram::s#2 + [22] memcpy_to_vram::s#1 = ++ memcpy_to_vram::s#2 + to:memcpy_to_vram::@1 + +void vpoke(byte vpoke::vbank , byte* vpoke::vaddr , byte vpoke::data) +vpoke: scope:[vpoke] from main::@2 main::@4 + [23] vpoke::data#2 = phi( main::@2/vpoke::data#0, main::@4/$21 ) + [23] vpoke::vaddr#2 = phi( main::@2/vpoke::vaddr#0, main::@4/vpoke::vaddr#1 ) + [24] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL + [25] vpoke::$0 = < vpoke::vaddr#2 + [26] *VERA_ADDRX_L = vpoke::$0 + [27] vpoke::$1 = > vpoke::vaddr#2 + [28] *VERA_ADDRX_M = vpoke::$1 + [29] *VERA_ADDRX_H = 0 + [30] *VERA_DATA0 = vpoke::data#2 to:vpoke::@return vpoke::@return: scope:[vpoke] from vpoke - [20] return + [31] return to:@return @@ -240,22 +399,32 @@ byte* main::vaddr byte* main::vaddr#1 11.0 byte* main::vaddr#2 11.0 byte* main::vaddr#3 6.6000000000000005 -void vpoke(byte vpoke::bank , byte* vpoke::addr , byte vpoke::data) +void memcpy_to_vram(byte memcpy_to_vram::vbank , void* memcpy_to_vram::vdest , void* memcpy_to_vram::src , word memcpy_to_vram::num) +byte* memcpy_to_vram::end +word memcpy_to_vram::num +byte* memcpy_to_vram::s +byte* memcpy_to_vram::s#1 202.0 +byte* memcpy_to_vram::s#2 134.66666666666666 +void* memcpy_to_vram::src +byte memcpy_to_vram::vbank +void* memcpy_to_vram::vdest +void vpoke(byte vpoke::vbank , byte* vpoke::vaddr , byte vpoke::data) byte~ vpoke::$0 202.0 byte~ vpoke::$1 202.0 -byte* vpoke::addr -byte* vpoke::addr#0 11.0 -byte* vpoke::addr#1 22.0 -byte* vpoke::addr#2 56.0 -byte vpoke::bank byte vpoke::data byte vpoke::data#0 22.0 byte vpoke::data#2 16.0 +byte* vpoke::vaddr +byte* vpoke::vaddr#0 11.0 +byte* vpoke::vaddr#1 22.0 +byte* vpoke::vaddr#2 56.0 +byte vpoke::vbank Initial phi equivalence classes [ main::i#2 main::i#1 ] [ main::vaddr#3 main::vaddr#2 ] -[ vpoke::addr#2 vpoke::addr#0 vpoke::addr#1 ] +[ memcpy_to_vram::s#2 memcpy_to_vram::s#1 ] +[ vpoke::vaddr#2 vpoke::vaddr#0 vpoke::vaddr#1 ] [ vpoke::data#2 vpoke::data#0 ] Added variable main::vaddr#1 to live range equivalence class [ main::vaddr#1 ] Added variable vpoke::$0 to live range equivalence class [ vpoke::$0 ] @@ -263,56 +432,74 @@ Added variable vpoke::$1 to live range equivalence class [ vpoke::$1 ] Complete equivalence classes [ main::i#2 main::i#1 ] [ main::vaddr#3 main::vaddr#2 ] -[ vpoke::addr#2 vpoke::addr#0 vpoke::addr#1 ] +[ memcpy_to_vram::s#2 memcpy_to_vram::s#1 ] +[ vpoke::vaddr#2 vpoke::vaddr#0 vpoke::vaddr#1 ] [ vpoke::data#2 vpoke::data#0 ] [ main::vaddr#1 ] [ vpoke::$0 ] [ vpoke::$1 ] Allocated zp[1]:2 [ main::i#2 main::i#1 ] Allocated zp[2]:3 [ main::vaddr#3 main::vaddr#2 ] -Allocated zp[2]:5 [ vpoke::addr#2 vpoke::addr#0 vpoke::addr#1 ] -Allocated zp[1]:7 [ vpoke::data#2 vpoke::data#0 ] -Allocated zp[2]:8 [ main::vaddr#1 ] -Allocated zp[1]:10 [ vpoke::$0 ] -Allocated zp[1]:11 [ vpoke::$1 ] +Allocated zp[2]:5 [ memcpy_to_vram::s#2 memcpy_to_vram::s#1 ] +Allocated zp[2]:7 [ vpoke::vaddr#2 vpoke::vaddr#0 vpoke::vaddr#1 ] +Allocated zp[1]:9 [ vpoke::data#2 vpoke::data#0 ] +Allocated zp[2]:10 [ main::vaddr#1 ] +Allocated zp[1]:12 [ vpoke::$0 ] +Allocated zp[1]:13 [ vpoke::$1 ] REGISTER UPLIFT POTENTIAL REGISTERS Statement [2] if(0!=main::MSG[main::i#2]) goto main::@2 [ main::i#2 main::vaddr#3 ] ( [ main::i#2 main::vaddr#3 ] { } ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ] -Statement [4] vpoke::addr#0 = main::vaddr#3 [ main::i#2 main::vaddr#3 vpoke::addr#0 ] ( [ main::i#2 main::vaddr#3 vpoke::addr#0 ] { { vpoke::addr#0 = vpoke::addr#2 main::vaddr#3 } { vpoke::data#0 = vpoke::data#2 } } ) always clobbers reg byte a -Statement [7] main::vaddr#1 = ++ main::vaddr#3 [ main::i#2 main::vaddr#1 ] ( [ main::i#2 main::vaddr#1 ] { { vpoke::addr#1 = vpoke::addr#2 main::vaddr#1 } } ) always clobbers reg byte a -Statement [8] vpoke::addr#1 = main::vaddr#1 [ main::i#2 main::vaddr#1 vpoke::addr#1 ] ( [ main::i#2 main::vaddr#1 vpoke::addr#1 ] { { vpoke::addr#1 = vpoke::addr#2 main::vaddr#1 } } ) always clobbers reg byte a -Statement [10] main::vaddr#2 = ++ main::vaddr#1 [ main::i#2 main::vaddr#2 ] ( [ main::i#2 main::vaddr#2 ] { } ) always clobbers reg byte a -Statement [13] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL [ vpoke::addr#2 vpoke::data#2 ] ( vpoke:6 [ main::i#2 main::vaddr#3 vpoke::addr#2 vpoke::data#2 ] { { vpoke::addr#0 = vpoke::addr#2 main::vaddr#3 } { vpoke::data#0 = vpoke::data#2 } } vpoke:9 [ main::i#2 main::vaddr#1 vpoke::addr#2 vpoke::data#2 ] { { vpoke::addr#1 = vpoke::addr#2 main::vaddr#1 } } ) always clobbers reg byte a -Removing always clobbered register reg byte a as potential for zp[1]:7 [ vpoke::data#2 vpoke::data#0 ] -Statement [18] *VERA_ADDRX_H = 0 [ vpoke::data#2 ] ( vpoke:6 [ main::i#2 main::vaddr#3 vpoke::data#2 ] { { vpoke::addr#0 = vpoke::addr#2 main::vaddr#3 } { vpoke::data#0 = vpoke::data#2 } } vpoke:9 [ main::i#2 main::vaddr#1 vpoke::data#2 ] { { vpoke::addr#1 = vpoke::addr#2 main::vaddr#1 } } ) always clobbers reg byte a +Statement [6] vpoke::vaddr#0 = main::vaddr#3 [ main::i#2 main::vaddr#3 vpoke::vaddr#0 ] ( [ main::i#2 main::vaddr#3 vpoke::vaddr#0 ] { { vpoke::vaddr#0 = vpoke::vaddr#2 main::vaddr#3 } { vpoke::data#0 = vpoke::data#2 } } ) always clobbers reg byte a +Statement [9] main::vaddr#1 = ++ main::vaddr#3 [ main::i#2 main::vaddr#1 ] ( [ main::i#2 main::vaddr#1 ] { { vpoke::vaddr#1 = vpoke::vaddr#2 main::vaddr#1 } } ) always clobbers reg byte a +Statement [10] vpoke::vaddr#1 = main::vaddr#1 [ main::i#2 main::vaddr#1 vpoke::vaddr#1 ] ( [ main::i#2 main::vaddr#1 vpoke::vaddr#1 ] { { vpoke::vaddr#1 = vpoke::vaddr#2 main::vaddr#1 } } ) always clobbers reg byte a +Statement [12] main::vaddr#2 = ++ main::vaddr#1 [ main::i#2 main::vaddr#2 ] ( [ main::i#2 main::vaddr#2 ] { } ) always clobbers reg byte a +Statement [14] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL [ ] ( memcpy_to_vram:4 [ ] { } ) always clobbers reg byte a +Statement [15] *VERA_ADDRX_L = 0 [ ] ( memcpy_to_vram:4 [ ] { } ) always clobbers reg byte a +Statement [16] *VERA_ADDRX_M = >memcpy_to_vram::vdest#0 [ ] ( memcpy_to_vram:4 [ ] { } ) always clobbers reg byte a +Statement [17] *VERA_ADDRX_H = VERA_INC_1 [ ] ( memcpy_to_vram:4 [ ] { } ) always clobbers reg byte a +Statement [19] if(memcpy_to_vram::s#2!=memcpy_to_vram::end#0) goto memcpy_to_vram::@2 [ memcpy_to_vram::s#2 ] ( memcpy_to_vram:4 [ memcpy_to_vram::s#2 ] { } ) always clobbers reg byte a +Statement [21] *VERA_DATA0 = *memcpy_to_vram::s#2 [ memcpy_to_vram::s#2 ] ( memcpy_to_vram:4 [ memcpy_to_vram::s#2 ] { } ) always clobbers reg byte a reg byte y +Statement [24] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL [ vpoke::vaddr#2 vpoke::data#2 ] ( vpoke:8 [ main::i#2 main::vaddr#3 vpoke::vaddr#2 vpoke::data#2 ] { { vpoke::vaddr#0 = vpoke::vaddr#2 main::vaddr#3 } { vpoke::data#0 = vpoke::data#2 } } vpoke:11 [ main::i#2 main::vaddr#1 vpoke::vaddr#2 vpoke::data#2 ] { { vpoke::vaddr#1 = vpoke::vaddr#2 main::vaddr#1 } } ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:9 [ vpoke::data#2 vpoke::data#0 ] +Statement [29] *VERA_ADDRX_H = 0 [ vpoke::data#2 ] ( vpoke:8 [ main::i#2 main::vaddr#3 vpoke::data#2 ] { { vpoke::vaddr#0 = vpoke::vaddr#2 main::vaddr#3 } { vpoke::data#0 = vpoke::data#2 } } vpoke:11 [ main::i#2 main::vaddr#1 vpoke::data#2 ] { { vpoke::vaddr#1 = vpoke::vaddr#2 main::vaddr#1 } } ) always clobbers reg byte a Statement [2] if(0!=main::MSG[main::i#2]) goto main::@2 [ main::i#2 main::vaddr#3 ] ( [ main::i#2 main::vaddr#3 ] { } ) always clobbers reg byte a -Statement [4] vpoke::addr#0 = main::vaddr#3 [ main::i#2 main::vaddr#3 vpoke::addr#0 ] ( [ main::i#2 main::vaddr#3 vpoke::addr#0 ] { { vpoke::addr#0 = vpoke::addr#2 main::vaddr#3 } { vpoke::data#0 = vpoke::data#2 } } ) always clobbers reg byte a -Statement [7] main::vaddr#1 = ++ main::vaddr#3 [ main::i#2 main::vaddr#1 ] ( [ main::i#2 main::vaddr#1 ] { { vpoke::addr#1 = vpoke::addr#2 main::vaddr#1 } } ) always clobbers reg byte a -Statement [8] vpoke::addr#1 = main::vaddr#1 [ main::i#2 main::vaddr#1 vpoke::addr#1 ] ( [ main::i#2 main::vaddr#1 vpoke::addr#1 ] { { vpoke::addr#1 = vpoke::addr#2 main::vaddr#1 } } ) always clobbers reg byte a -Statement [10] main::vaddr#2 = ++ main::vaddr#1 [ main::i#2 main::vaddr#2 ] ( [ main::i#2 main::vaddr#2 ] { } ) always clobbers reg byte a -Statement [13] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL [ vpoke::addr#2 vpoke::data#2 ] ( vpoke:6 [ main::i#2 main::vaddr#3 vpoke::addr#2 vpoke::data#2 ] { { vpoke::addr#0 = vpoke::addr#2 main::vaddr#3 } { vpoke::data#0 = vpoke::data#2 } } vpoke:9 [ main::i#2 main::vaddr#1 vpoke::addr#2 vpoke::data#2 ] { { vpoke::addr#1 = vpoke::addr#2 main::vaddr#1 } } ) always clobbers reg byte a -Statement [18] *VERA_ADDRX_H = 0 [ vpoke::data#2 ] ( vpoke:6 [ main::i#2 main::vaddr#3 vpoke::data#2 ] { { vpoke::addr#0 = vpoke::addr#2 main::vaddr#3 } { vpoke::data#0 = vpoke::data#2 } } vpoke:9 [ main::i#2 main::vaddr#1 vpoke::data#2 ] { { vpoke::addr#1 = vpoke::addr#2 main::vaddr#1 } } ) always clobbers reg byte a +Statement [6] vpoke::vaddr#0 = main::vaddr#3 [ main::i#2 main::vaddr#3 vpoke::vaddr#0 ] ( [ main::i#2 main::vaddr#3 vpoke::vaddr#0 ] { { vpoke::vaddr#0 = vpoke::vaddr#2 main::vaddr#3 } { vpoke::data#0 = vpoke::data#2 } } ) always clobbers reg byte a +Statement [9] main::vaddr#1 = ++ main::vaddr#3 [ main::i#2 main::vaddr#1 ] ( [ main::i#2 main::vaddr#1 ] { { vpoke::vaddr#1 = vpoke::vaddr#2 main::vaddr#1 } } ) always clobbers reg byte a +Statement [10] vpoke::vaddr#1 = main::vaddr#1 [ main::i#2 main::vaddr#1 vpoke::vaddr#1 ] ( [ main::i#2 main::vaddr#1 vpoke::vaddr#1 ] { { vpoke::vaddr#1 = vpoke::vaddr#2 main::vaddr#1 } } ) always clobbers reg byte a +Statement [12] main::vaddr#2 = ++ main::vaddr#1 [ main::i#2 main::vaddr#2 ] ( [ main::i#2 main::vaddr#2 ] { } ) always clobbers reg byte a +Statement [14] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL [ ] ( memcpy_to_vram:4 [ ] { } ) always clobbers reg byte a +Statement [15] *VERA_ADDRX_L = 0 [ ] ( memcpy_to_vram:4 [ ] { } ) always clobbers reg byte a +Statement [16] *VERA_ADDRX_M = >memcpy_to_vram::vdest#0 [ ] ( memcpy_to_vram:4 [ ] { } ) always clobbers reg byte a +Statement [17] *VERA_ADDRX_H = VERA_INC_1 [ ] ( memcpy_to_vram:4 [ ] { } ) always clobbers reg byte a +Statement [19] if(memcpy_to_vram::s#2!=memcpy_to_vram::end#0) goto memcpy_to_vram::@2 [ memcpy_to_vram::s#2 ] ( memcpy_to_vram:4 [ memcpy_to_vram::s#2 ] { } ) always clobbers reg byte a +Statement [21] *VERA_DATA0 = *memcpy_to_vram::s#2 [ memcpy_to_vram::s#2 ] ( memcpy_to_vram:4 [ memcpy_to_vram::s#2 ] { } ) always clobbers reg byte a reg byte y +Statement [24] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL [ vpoke::vaddr#2 vpoke::data#2 ] ( vpoke:8 [ main::i#2 main::vaddr#3 vpoke::vaddr#2 vpoke::data#2 ] { { vpoke::vaddr#0 = vpoke::vaddr#2 main::vaddr#3 } { vpoke::data#0 = vpoke::data#2 } } vpoke:11 [ main::i#2 main::vaddr#1 vpoke::vaddr#2 vpoke::data#2 ] { { vpoke::vaddr#1 = vpoke::vaddr#2 main::vaddr#1 } } ) always clobbers reg byte a +Statement [29] *VERA_ADDRX_H = 0 [ vpoke::data#2 ] ( vpoke:8 [ main::i#2 main::vaddr#3 vpoke::data#2 ] { { vpoke::vaddr#0 = vpoke::vaddr#2 main::vaddr#3 } { vpoke::data#0 = vpoke::data#2 } } vpoke:11 [ main::i#2 main::vaddr#1 vpoke::data#2 ] { { vpoke::vaddr#1 = vpoke::vaddr#2 main::vaddr#1 } } ) always clobbers reg byte a Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y , Potential registers zp[2]:3 [ main::vaddr#3 main::vaddr#2 ] : zp[2]:3 , -Potential registers zp[2]:5 [ vpoke::addr#2 vpoke::addr#0 vpoke::addr#1 ] : zp[2]:5 , -Potential registers zp[1]:7 [ vpoke::data#2 vpoke::data#0 ] : zp[1]:7 , reg byte x , reg byte y , -Potential registers zp[2]:8 [ main::vaddr#1 ] : zp[2]:8 , -Potential registers zp[1]:10 [ vpoke::$0 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y , -Potential registers zp[1]:11 [ vpoke::$1 ] : zp[1]:11 , reg byte a , reg byte x , reg byte y , +Potential registers zp[2]:5 [ memcpy_to_vram::s#2 memcpy_to_vram::s#1 ] : zp[2]:5 , +Potential registers zp[2]:7 [ vpoke::vaddr#2 vpoke::vaddr#0 vpoke::vaddr#1 ] : zp[2]:7 , +Potential registers zp[1]:9 [ vpoke::data#2 vpoke::data#0 ] : zp[1]:9 , reg byte x , reg byte y , +Potential registers zp[2]:10 [ main::vaddr#1 ] : zp[2]:10 , +Potential registers zp[1]:12 [ vpoke::$0 ] : zp[1]:12 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:13 [ vpoke::$1 ] : zp[1]:13 , reg byte a , reg byte x , reg byte y , REGISTER UPLIFT SCOPES -Uplift Scope [vpoke] 202: zp[1]:10 [ vpoke::$0 ] 202: zp[1]:11 [ vpoke::$1 ] 89: zp[2]:5 [ vpoke::addr#2 vpoke::addr#0 vpoke::addr#1 ] 38: zp[1]:7 [ vpoke::data#2 vpoke::data#0 ] -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]:8 [ main::vaddr#1 ] +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 [MOS6522_VIA] Uplift Scope [] -Uplifting [vpoke] best 1154 combination reg byte a [ vpoke::$0 ] reg byte a [ vpoke::$1 ] zp[2]:5 [ vpoke::addr#2 vpoke::addr#0 vpoke::addr#1 ] reg byte x [ vpoke::data#2 vpoke::data#0 ] -Uplifting [main] best 1034 combination reg byte y [ main::i#2 main::i#1 ] zp[2]:3 [ main::vaddr#3 main::vaddr#2 ] zp[2]:8 [ main::vaddr#1 ] -Uplifting [MOS6522_VIA] best 1034 combination -Uplifting [] best 1034 combination -Coalescing zero page register [ zp[2]:3 [ main::vaddr#3 main::vaddr#2 ] ] with [ zp[2]:8 [ main::vaddr#1 ] ] - score: 2 -Coalescing zero page register [ zp[2]:3 [ main::vaddr#3 main::vaddr#2 main::vaddr#1 ] ] with [ zp[2]:5 [ vpoke::addr#2 vpoke::addr#0 vpoke::addr#1 ] ] - score: 1 -Allocated (was zp[2]:3) zp[2]:2 [ main::vaddr#3 main::vaddr#2 main::vaddr#1 vpoke::addr#2 vpoke::addr#0 vpoke::addr#1 ] +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 [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 +Coalescing zero page register [ zp[2]:3 [ main::vaddr#3 main::vaddr#2 main::vaddr#1 ] ] with [ zp[2]:7 [ vpoke::vaddr#2 vpoke::vaddr#0 vpoke::vaddr#1 ] ] - score: 1 +Allocated (was zp[2]:3) zp[2]:2 [ main::vaddr#3 main::vaddr#2 main::vaddr#1 vpoke::vaddr#2 vpoke::vaddr#0 vpoke::vaddr#1 ] +Allocated (was zp[2]:5) zp[2]:4 [ memcpy_to_vram::s#2 memcpy_to_vram::s#1 ] ASSEMBLER BEFORE OPTIMIZATION // File Comments @@ -332,7 +519,9 @@ ASSEMBLER BEFORE OPTIMIZATION // Global Constants & labels + .const VERA_INC_1 = $10 .const VERA_ADDRSEL = 1 + .const SIZEOF_BYTE = 1 // $9F20 VRAM Address (7:0) .label VERA_ADDRX_L = $9f20 // $9F21 VRAM Address (15:8) @@ -350,17 +539,18 @@ ASSEMBLER BEFORE OPTIMIZATION // Bit 1: DCSEL // Bit 2: ADDRSEL .label VERA_CTRL = $9f25 + // VRAM Address of the default screen + .label DEFAULT_SCREEN = 0 .segment Code // main main: { - // Address of the default screen .label vaddr = 2 // [1] phi from main to main::@1 [phi:main->main::@1] __b1_from_main: - // [1] phi main::vaddr#3 = (byte*) 0 [phi:main->main::@1#0] -- pbuz1=pbuc1 - lda #<0 + // [1] phi main::vaddr#3 = DEFAULT_SCREEN [phi:main->main::@1#0] -- pbuz1=pbuc1 + lda #0 + lda #>DEFAULT_SCREEN sta.z vaddr+1 // [1] phi main::i#2 = 0 [phi:main->main::@1#1] -- vbuyy=vbuc1 ldy #0 @@ -371,125 +561,214 @@ main: { lda MSG,y cmp #0 bne __b2 - jmp __breturn - // main::@return - __breturn: - // [3] return - rts - // main::@2 - __b2: - // [4] vpoke::addr#0 = main::vaddr#3 - // [5] vpoke::data#0 = main::MSG[main::i#2] -- vbuxx=pbuc1_derefidx_vbuyy - ldx MSG,y - // [6] call vpoke - // [12] phi from main::@2 to vpoke [phi:main::@2->vpoke] - vpoke_from___b2: - // [12] phi vpoke::data#2 = vpoke::data#0 [phi:main::@2->vpoke#0] -- register_copy - // [12] phi vpoke::addr#2 = vpoke::addr#0 [phi:main::@2->vpoke#1] -- register_copy - jsr vpoke + // [3] phi from main::@1 to main::@3 [phi:main::@1->main::@3] + __b3_from___b1: jmp __b3 // main::@3 __b3: - // [7] main::vaddr#1 = ++ main::vaddr#3 -- pbuz1=_inc_pbuz1 - inc.z vaddr - bne !+ - inc.z vaddr+1 - !: - // [8] vpoke::addr#1 = main::vaddr#1 - // [9] call vpoke - // Message - // [12] phi from main::@3 to vpoke [phi:main::@3->vpoke] - vpoke_from___b3: - // [12] phi vpoke::data#2 = $21 [phi:main::@3->vpoke#0] -- vbuxx=vbuc1 - ldx #$21 - // [12] phi vpoke::addr#2 = vpoke::addr#1 [phi:main::@3->vpoke#1] -- register_copy + // [4] call memcpy_to_vram + // Space is 0x20, red background black foreground + jsr memcpy_to_vram + jmp __breturn + // main::@return + __breturn: + // [5] return + rts + // main::@2 + __b2: + // [6] vpoke::vaddr#0 = main::vaddr#3 + // [7] vpoke::data#0 = main::MSG[main::i#2] -- vbuxx=pbuc1_derefidx_vbuyy + ldx MSG,y + // [8] call vpoke + // [23] phi from main::@2 to vpoke [phi:main::@2->vpoke] + vpoke_from___b2: + // [23] phi vpoke::data#2 = vpoke::data#0 [phi:main::@2->vpoke#0] -- register_copy + // [23] phi vpoke::vaddr#2 = vpoke::vaddr#0 [phi:main::@2->vpoke#1] -- register_copy jsr vpoke jmp __b4 // main::@4 __b4: - // [10] main::vaddr#2 = ++ main::vaddr#1 -- pbuz1=_inc_pbuz1 + // [9] main::vaddr#1 = ++ main::vaddr#3 -- pbuz1=_inc_pbuz1 inc.z vaddr bne !+ inc.z vaddr+1 !: - // [11] main::i#1 = ++ main::i#2 -- vbuyy=_inc_vbuyy + // [10] vpoke::vaddr#1 = main::vaddr#1 + // [11] call vpoke + // Message + // [23] phi from main::@4 to vpoke [phi:main::@4->vpoke] + vpoke_from___b4: + // [23] phi vpoke::data#2 = $21 [phi:main::@4->vpoke#0] -- vbuxx=vbuc1 + ldx #$21 + // [23] phi vpoke::vaddr#2 = vpoke::vaddr#1 [phi:main::@4->vpoke#1] -- register_copy + jsr vpoke + jmp __b5 + // main::@5 + __b5: + // [12] main::vaddr#2 = ++ main::vaddr#1 -- pbuz1=_inc_pbuz1 + inc.z vaddr + bne !+ + inc.z vaddr+1 + !: + // [13] main::i#1 = ++ main::i#2 -- vbuyy=_inc_vbuyy iny - // [1] phi from main::@4 to main::@1 [phi:main::@4->main::@1] - __b1_from___b4: - // [1] phi main::vaddr#3 = main::vaddr#2 [phi:main::@4->main::@1#0] -- register_copy - // [1] phi main::i#2 = main::i#1 [phi:main::@4->main::@1#1] -- register_copy + // [1] phi from main::@5 to main::@1 [phi:main::@5->main::@1] + __b1_from___b5: + // [1] phi main::vaddr#3 = main::vaddr#2 [phi:main::@5->main::@1#0] -- register_copy + // [1] phi main::i#2 = main::i#1 [phi:main::@5->main::@1#1] -- register_copy jmp __b1 .segment Data + // Copy message to screen one char at a time MSG: .text "hello world!" .byte 0 + // Copy message (and colors) to screen using memcpy_to_vram + MSG2: .text "h e l l o w o r l d ! " + .byte 0 } .segment Code + // 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: { + .const num = $19*SIZEOF_BYTE + .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 + lda #VERA_ADDRSEL^$ff + and VERA_CTRL + sta VERA_CTRL + // [15] *VERA_ADDRX_L = 0 -- _deref_pbuc1=vbuc2 + // Set address + lda #0 + sta VERA_ADDRX_L + // [16] *VERA_ADDRX_M = >memcpy_to_vram::vdest#0 -- _deref_pbuc1=vbuc2 + lda #>vdest + sta VERA_ADDRX_M + // [17] *VERA_ADDRX_H = VERA_INC_1 -- _deref_pbuc1=vbuc2 + lda #VERA_INC_1 + sta VERA_ADDRX_H + // [18] phi from memcpy_to_vram to memcpy_to_vram::@1 [phi:memcpy_to_vram->memcpy_to_vram::@1] + __b1_from_memcpy_to_vram: + // [18] phi memcpy_to_vram::s#2 = (byte*)memcpy_to_vram::src#0 [phi:memcpy_to_vram->memcpy_to_vram::@1#0] -- pbuz1=pbuc1 + lda #src + sta.z s+1 + jmp __b1 + // memcpy_to_vram::@1 + __b1: + // [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 + bne __b2 + lda.z s + cmp #memcpy_to_vram::@1] + __b1_from___b2: + // [18] phi memcpy_to_vram::s#2 = memcpy_to_vram::s#1 [phi:memcpy_to_vram::@2->memcpy_to_vram::@1#0] -- register_copy + jmp __b1 +} // vpoke // Put a single byte into VRAM. // Uses VERA DATA0 // - bank: Which 64K VRAM bank to put data into (0/1) // - addr: The address in VRAM // - data: The data to put into VRAM -// vpoke(byte* zp(2) addr, byte register(X) data) +// vpoke(byte* zp(2) vaddr, byte register(X) data) vpoke: { - .label addr = 2 - // [13] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2 + .label vaddr = 2 + // [24] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2 // Select DATA0 lda #VERA_ADDRSEL^$ff and VERA_CTRL sta VERA_CTRL - // [14] vpoke::$0 = < vpoke::addr#2 -- vbuaa=_lo_pbuz1 - lda.z addr - // [15] *VERA_ADDRX_L = vpoke::$0 -- _deref_pbuc1=vbuaa + // [25] vpoke::$0 = < vpoke::vaddr#2 -- vbuaa=_lo_pbuz1 + lda.z vaddr + // [26] *VERA_ADDRX_L = vpoke::$0 -- _deref_pbuc1=vbuaa // Set address sta VERA_ADDRX_L - // [16] vpoke::$1 = > vpoke::addr#2 -- vbuaa=_hi_pbuz1 - lda.z addr+1 - // [17] *VERA_ADDRX_M = vpoke::$1 -- _deref_pbuc1=vbuaa + // [27] vpoke::$1 = > vpoke::vaddr#2 -- vbuaa=_hi_pbuz1 + lda.z vaddr+1 + // [28] *VERA_ADDRX_M = vpoke::$1 -- _deref_pbuc1=vbuaa sta VERA_ADDRX_M - // [18] *VERA_ADDRX_H = 0 -- _deref_pbuc1=vbuc2 + // [29] *VERA_ADDRX_H = 0 -- _deref_pbuc1=vbuc2 lda #0 sta VERA_ADDRX_H - // [19] *VERA_DATA0 = vpoke::data#2 -- _deref_pbuc1=vbuxx + // [30] *VERA_DATA0 = vpoke::data#2 -- _deref_pbuc1=vbuxx // Set data stx VERA_DATA0 jmp __breturn // vpoke::@return __breturn: - // [20] return + // [31] return rts } // File Data ASSEMBLER OPTIMIZATIONS Removing instruction jmp __b1 -Removing instruction jmp __breturn Removing instruction jmp __b3 +Removing instruction jmp __breturn Removing instruction jmp __b4 +Removing instruction jmp __b5 +Removing instruction jmp __b1 +Removing instruction jmp __breturn Removing instruction jmp __breturn Succesful ASM optimization Pass5NextJumpElimination -Removing instruction lda #>0 -Replacing instruction ldy #0 with TAY -Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction __b3_from___b1: +Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction __b1_from_main: +Removing instruction __b3: Removing instruction __breturn: Removing instruction vpoke_from___b2: -Removing instruction __b3: -Removing instruction vpoke_from___b3: Removing instruction __b4: -Removing instruction __b1_from___b4: +Removing instruction vpoke_from___b4: +Removing instruction __b5: +Removing instruction __b1_from___b5: +Removing instruction __b1_from_memcpy_to_vram: +Removing instruction __breturn: +Removing instruction __b1_from___b2: Removing instruction __breturn: Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE +const nomodify byte* DEFAULT_SCREEN = (byte*) 0 +const byte SIZEOF_BYTE = 1 const nomodify byte VERA_ADDRSEL = 1 const nomodify byte* VERA_ADDRX_H = (byte*) 40738 const nomodify byte* VERA_ADDRX_L = (byte*) 40736 const nomodify byte* VERA_ADDRX_M = (byte*) 40737 const nomodify byte* VERA_CTRL = (byte*) 40741 const nomodify byte* VERA_DATA0 = (byte*) 40739 +const nomodify byte VERA_INC_1 = $10 void main() const byte* main::MSG[] = "hello world!" +const byte* main::MSG2[] = "h e l l o w o r l d ! " byte main::i byte main::i#1 reg byte y 22.0 byte main::i#2 reg byte y 4.888888888888889 @@ -497,27 +776,41 @@ byte* main::vaddr byte* main::vaddr#1 vaddr zp[2]:2 11.0 byte* main::vaddr#2 vaddr zp[2]:2 11.0 byte* main::vaddr#3 vaddr zp[2]:2 6.6000000000000005 -void vpoke(byte vpoke::bank , byte* vpoke::addr , byte vpoke::data) +void memcpy_to_vram(byte memcpy_to_vram::vbank , void* memcpy_to_vram::vdest , void* memcpy_to_vram::src , word memcpy_to_vram::num) +byte* memcpy_to_vram::end +const byte* memcpy_to_vram::end#0 end = (byte*)memcpy_to_vram::src#0+memcpy_to_vram::num#0 +word memcpy_to_vram::num +const word memcpy_to_vram::num#0 num = $19*SIZEOF_BYTE +byte* memcpy_to_vram::s +byte* memcpy_to_vram::s#1 s zp[2]:4 202.0 +byte* memcpy_to_vram::s#2 s zp[2]:4 134.66666666666666 +void* memcpy_to_vram::src +const void* memcpy_to_vram::src#0 src = (void*)main::MSG2 +byte memcpy_to_vram::vbank +void* memcpy_to_vram::vdest +const void* memcpy_to_vram::vdest#0 vdest = (void*)DEFAULT_SCREEN+$100 +void vpoke(byte vpoke::vbank , byte* vpoke::vaddr , byte vpoke::data) byte~ vpoke::$0 reg byte a 202.0 byte~ vpoke::$1 reg byte a 202.0 -byte* vpoke::addr -byte* vpoke::addr#0 addr zp[2]:2 11.0 -byte* vpoke::addr#1 addr zp[2]:2 22.0 -byte* vpoke::addr#2 addr zp[2]:2 56.0 -byte vpoke::bank byte vpoke::data byte vpoke::data#0 reg byte x 22.0 byte vpoke::data#2 reg byte x 16.0 +byte* vpoke::vaddr +byte* vpoke::vaddr#0 vaddr zp[2]:2 11.0 +byte* vpoke::vaddr#1 vaddr zp[2]:2 22.0 +byte* vpoke::vaddr#2 vaddr zp[2]:2 56.0 +byte vpoke::vbank reg byte y [ main::i#2 main::i#1 ] -zp[2]:2 [ main::vaddr#3 main::vaddr#2 main::vaddr#1 vpoke::addr#2 vpoke::addr#0 vpoke::addr#1 ] +zp[2]:2 [ main::vaddr#3 main::vaddr#2 main::vaddr#1 vpoke::vaddr#2 vpoke::vaddr#0 vpoke::vaddr#1 ] +zp[2]:4 [ memcpy_to_vram::s#2 memcpy_to_vram::s#1 ] reg byte x [ vpoke::data#2 vpoke::data#0 ] reg byte a [ vpoke::$0 ] reg byte a [ vpoke::$1 ] FINAL ASSEMBLER -Score: 595 +Score: 1175 // File Comments // Example program for the Commander X16 @@ -536,7 +829,9 @@ Score: 595 // Global Constants & labels + .const VERA_INC_1 = $10 .const VERA_ADDRSEL = 1 + .const SIZEOF_BYTE = 1 // $9F20 VRAM Address (7:0) .label VERA_ADDRX_L = $9f20 // $9F21 VRAM Address (15:8) @@ -554,18 +849,20 @@ Score: 595 // Bit 1: DCSEL // Bit 2: ADDRSEL .label VERA_CTRL = $9f25 + // VRAM Address of the default screen + .label DEFAULT_SCREEN = 0 .segment Code // main main: { - // Address of the default screen .label vaddr = 2 // [1] phi from main to main::@1 [phi:main->main::@1] - // [1] phi main::vaddr#3 = (byte*) 0 [phi:main->main::@1#0] -- pbuz1=pbuc1 - lda #<0 + // [1] phi main::vaddr#3 = DEFAULT_SCREEN [phi:main->main::@1#0] -- pbuz1=pbuc1 + lda #DEFAULT_SCREEN sta.z vaddr+1 // [1] phi main::i#2 = 0 [phi:main->main::@1#1] -- vbuyy=vbuc1 - tay + ldy #0 // main::@1 __b1: // for(char i=0;MSG[i];i++) @@ -573,95 +870,175 @@ main: { lda MSG,y cmp #0 bne __b2 + // [3] phi from main::@1 to main::@3 [phi:main::@1->main::@3] + // main::@3 + // memcpy_to_vram(0, DEFAULT_SCREEN+0x100, MSG2, sizeof(MSG2)) + // [4] call memcpy_to_vram + // Space is 0x20, red background black foreground + jsr memcpy_to_vram // main::@return // } - // [3] return + // [5] return rts // main::@2 __b2: // vpoke(0, vaddr++, MSG[i]) - // [4] vpoke::addr#0 = main::vaddr#3 - // [5] vpoke::data#0 = main::MSG[main::i#2] -- vbuxx=pbuc1_derefidx_vbuyy + // [6] vpoke::vaddr#0 = main::vaddr#3 + // [7] vpoke::data#0 = main::MSG[main::i#2] -- vbuxx=pbuc1_derefidx_vbuyy ldx MSG,y - // [6] call vpoke - // [12] phi from main::@2 to vpoke [phi:main::@2->vpoke] - // [12] phi vpoke::data#2 = vpoke::data#0 [phi:main::@2->vpoke#0] -- register_copy - // [12] phi vpoke::addr#2 = vpoke::addr#0 [phi:main::@2->vpoke#1] -- register_copy + // [8] call vpoke + // [23] phi from main::@2 to vpoke [phi:main::@2->vpoke] + // [23] phi vpoke::data#2 = vpoke::data#0 [phi:main::@2->vpoke#0] -- register_copy + // [23] phi vpoke::vaddr#2 = vpoke::vaddr#0 [phi:main::@2->vpoke#1] -- register_copy jsr vpoke - // main::@3 + // main::@4 // vpoke(0, vaddr++, MSG[i]); - // [7] main::vaddr#1 = ++ main::vaddr#3 -- pbuz1=_inc_pbuz1 + // [9] main::vaddr#1 = ++ main::vaddr#3 -- pbuz1=_inc_pbuz1 inc.z vaddr bne !+ inc.z vaddr+1 !: // vpoke(0, vaddr++, 0x21) - // [8] vpoke::addr#1 = main::vaddr#1 - // [9] call vpoke + // [10] vpoke::vaddr#1 = main::vaddr#1 + // [11] call vpoke // Message - // [12] phi from main::@3 to vpoke [phi:main::@3->vpoke] - // [12] phi vpoke::data#2 = $21 [phi:main::@3->vpoke#0] -- vbuxx=vbuc1 + // [23] phi from main::@4 to vpoke [phi:main::@4->vpoke] + // [23] phi vpoke::data#2 = $21 [phi:main::@4->vpoke#0] -- vbuxx=vbuc1 ldx #$21 - // [12] phi vpoke::addr#2 = vpoke::addr#1 [phi:main::@3->vpoke#1] -- register_copy + // [23] phi vpoke::vaddr#2 = vpoke::vaddr#1 [phi:main::@4->vpoke#1] -- register_copy jsr vpoke - // main::@4 + // main::@5 // vpoke(0, vaddr++, 0x21); - // [10] main::vaddr#2 = ++ main::vaddr#1 -- pbuz1=_inc_pbuz1 + // [12] main::vaddr#2 = ++ main::vaddr#1 -- pbuz1=_inc_pbuz1 inc.z vaddr bne !+ inc.z vaddr+1 !: // for(char i=0;MSG[i];i++) - // [11] main::i#1 = ++ main::i#2 -- vbuyy=_inc_vbuyy + // [13] main::i#1 = ++ main::i#2 -- vbuyy=_inc_vbuyy iny - // [1] phi from main::@4 to main::@1 [phi:main::@4->main::@1] - // [1] phi main::vaddr#3 = main::vaddr#2 [phi:main::@4->main::@1#0] -- register_copy - // [1] phi main::i#2 = main::i#1 [phi:main::@4->main::@1#1] -- register_copy + // [1] phi from main::@5 to main::@1 [phi:main::@5->main::@1] + // [1] phi main::vaddr#3 = main::vaddr#2 [phi:main::@5->main::@1#0] -- register_copy + // [1] phi main::i#2 = main::i#1 [phi:main::@5->main::@1#1] -- register_copy jmp __b1 .segment Data + // Copy message to screen one char at a time MSG: .text "hello world!" .byte 0 + // Copy message (and colors) to screen using memcpy_to_vram + MSG2: .text "h e l l o w o r l d ! " + .byte 0 } .segment Code + // 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: { + .const num = $19*SIZEOF_BYTE + .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 + // Select DATA0 + lda #VERA_ADDRSEL^$ff + and VERA_CTRL + sta VERA_CTRL + // *VERA_ADDRX_L = vdest + // [16] *VERA_ADDRX_M = >memcpy_to_vram::vdest#0 -- _deref_pbuc1=vbuc2 + lda #>vdest + sta VERA_ADDRX_M + // *VERA_ADDRX_H = VERA_INC_1 | vbank + // [17] *VERA_ADDRX_H = VERA_INC_1 -- _deref_pbuc1=vbuc2 + lda #VERA_INC_1 + sta VERA_ADDRX_H + // [18] phi from memcpy_to_vram to memcpy_to_vram::@1 [phi:memcpy_to_vram->memcpy_to_vram::@1] + // [18] phi memcpy_to_vram::s#2 = (byte*)memcpy_to_vram::src#0 [phi:memcpy_to_vram->memcpy_to_vram::@1#0] -- pbuz1=pbuc1 + lda #src + sta.z s+1 + // memcpy_to_vram::@1 + __b1: + // for(; 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 + bne __b2 + lda.z s + cmp #memcpy_to_vram::@1] + // [18] phi memcpy_to_vram::s#2 = memcpy_to_vram::s#1 [phi:memcpy_to_vram::@2->memcpy_to_vram::@1#0] -- register_copy + jmp __b1 +} // vpoke // Put a single byte into VRAM. // Uses VERA DATA0 // - bank: Which 64K VRAM bank to put data into (0/1) // - addr: The address in VRAM // - data: The data to put into VRAM -// vpoke(byte* zp(2) addr, byte register(X) data) +// vpoke(byte* zp(2) vaddr, byte register(X) data) vpoke: { - .label addr = 2 + .label vaddr = 2 // *VERA_CTRL &= ~VERA_ADDRSEL - // [13] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2 + // [24] *VERA_CTRL = *VERA_CTRL & ~VERA_ADDRSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2 // Select DATA0 lda #VERA_ADDRSEL^$ff and VERA_CTRL sta VERA_CTRL - // addr - // [16] vpoke::$1 = > vpoke::addr#2 -- vbuaa=_hi_pbuz1 - lda.z addr+1 - // *VERA_ADDRX_M = >addr - // [17] *VERA_ADDRX_M = vpoke::$1 -- _deref_pbuc1=vbuaa + // >vaddr + // [27] vpoke::$1 = > vpoke::vaddr#2 -- vbuaa=_hi_pbuz1 + lda.z vaddr+1 + // *VERA_ADDRX_M = >vaddr + // [28] *VERA_ADDRX_M = vpoke::$1 -- _deref_pbuc1=vbuaa sta VERA_ADDRX_M - // *VERA_ADDRX_H = VERA_INC_0 | bank - // [18] *VERA_ADDRX_H = 0 -- _deref_pbuc1=vbuc2 + // *VERA_ADDRX_H = VERA_INC_0 | vbank + // [29] *VERA_ADDRX_H = 0 -- _deref_pbuc1=vbuc2 lda #0 sta VERA_ADDRX_H // *VERA_DATA0 = data - // [19] *VERA_DATA0 = vpoke::data#2 -- _deref_pbuc1=vbuxx + // [30] *VERA_DATA0 = vpoke::data#2 -- _deref_pbuc1=vbuxx // Set data stx VERA_DATA0 // vpoke::@return // } - // [20] return + // [31] return rts } // File Data diff --git a/src/test/ref/examples/cx16/text.sym b/src/test/ref/examples/cx16/text.sym index 9a80f9940..bc1d8819d 100644 --- a/src/test/ref/examples/cx16/text.sym +++ b/src/test/ref/examples/cx16/text.sym @@ -1,11 +1,15 @@ +const nomodify byte* DEFAULT_SCREEN = (byte*) 0 +const byte SIZEOF_BYTE = 1 const nomodify byte VERA_ADDRSEL = 1 const nomodify byte* VERA_ADDRX_H = (byte*) 40738 const nomodify byte* VERA_ADDRX_L = (byte*) 40736 const nomodify byte* VERA_ADDRX_M = (byte*) 40737 const nomodify byte* VERA_CTRL = (byte*) 40741 const nomodify byte* VERA_DATA0 = (byte*) 40739 +const nomodify byte VERA_INC_1 = $10 void main() const byte* main::MSG[] = "hello world!" +const byte* main::MSG2[] = "h e l l o w o r l d ! " byte main::i byte main::i#1 reg byte y 22.0 byte main::i#2 reg byte y 4.888888888888889 @@ -13,20 +17,34 @@ byte* main::vaddr byte* main::vaddr#1 vaddr zp[2]:2 11.0 byte* main::vaddr#2 vaddr zp[2]:2 11.0 byte* main::vaddr#3 vaddr zp[2]:2 6.6000000000000005 -void vpoke(byte vpoke::bank , byte* vpoke::addr , byte vpoke::data) +void memcpy_to_vram(byte memcpy_to_vram::vbank , void* memcpy_to_vram::vdest , void* memcpy_to_vram::src , word memcpy_to_vram::num) +byte* memcpy_to_vram::end +const byte* memcpy_to_vram::end#0 end = (byte*)memcpy_to_vram::src#0+memcpy_to_vram::num#0 +word memcpy_to_vram::num +const word memcpy_to_vram::num#0 num = $19*SIZEOF_BYTE +byte* memcpy_to_vram::s +byte* memcpy_to_vram::s#1 s zp[2]:4 202.0 +byte* memcpy_to_vram::s#2 s zp[2]:4 134.66666666666666 +void* memcpy_to_vram::src +const void* memcpy_to_vram::src#0 src = (void*)main::MSG2 +byte memcpy_to_vram::vbank +void* memcpy_to_vram::vdest +const void* memcpy_to_vram::vdest#0 vdest = (void*)DEFAULT_SCREEN+$100 +void vpoke(byte vpoke::vbank , byte* vpoke::vaddr , byte vpoke::data) byte~ vpoke::$0 reg byte a 202.0 byte~ vpoke::$1 reg byte a 202.0 -byte* vpoke::addr -byte* vpoke::addr#0 addr zp[2]:2 11.0 -byte* vpoke::addr#1 addr zp[2]:2 22.0 -byte* vpoke::addr#2 addr zp[2]:2 56.0 -byte vpoke::bank byte vpoke::data byte vpoke::data#0 reg byte x 22.0 byte vpoke::data#2 reg byte x 16.0 +byte* vpoke::vaddr +byte* vpoke::vaddr#0 vaddr zp[2]:2 11.0 +byte* vpoke::vaddr#1 vaddr zp[2]:2 22.0 +byte* vpoke::vaddr#2 vaddr zp[2]:2 56.0 +byte vpoke::vbank reg byte y [ main::i#2 main::i#1 ] -zp[2]:2 [ main::vaddr#3 main::vaddr#2 main::vaddr#1 vpoke::addr#2 vpoke::addr#0 vpoke::addr#1 ] +zp[2]:2 [ main::vaddr#3 main::vaddr#2 main::vaddr#1 vpoke::vaddr#2 vpoke::vaddr#0 vpoke::vaddr#1 ] +zp[2]:4 [ memcpy_to_vram::s#2 memcpy_to_vram::s#1 ] reg byte x [ vpoke::data#2 vpoke::data#0 ] reg byte a [ vpoke::$0 ] reg byte a [ vpoke::$1 ]