1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-26 12:49:21 +00:00

Improved simple VRAM example. #581

This commit is contained in:
jespergravgaard 2020-12-15 01:00:39 +01:00
parent 02e57b06cb
commit 2d58a799d5
8 changed files with 825 additions and 302 deletions

View File

@ -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);
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 );

View File

@ -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_M = >addr;
*VERA_ADDRX_H = VERA_INC_0 | bank;
*VERA_ADDRX_L = <vaddr;
*VERA_ADDRX_M = >vaddr;
*VERA_ADDRX_H = VERA_INC_0 | vbank;
// Set data
*VERA_DATA0 = 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 ) {
// Select DATA0
*VERA_CTRL &= ~VERA_ADDRSEL;
// Set address
*VERA_ADDRX_L = <vdest;
*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++)
*VERA_DATA0 = *s;
}

View File

@ -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
}

View File

@ -5,11 +5,18 @@
#include <cx16.h>
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
}
}
// Copy message (and colors) to screen using memcpy_to_vram
char MSG2[] = "h e l l o w o r l d ! "; // Space is 0x20, red background black foreground
memcpy_to_vram(0, DEFAULT_SCREEN+0x100, MSG2, sizeof(MSG2));
}

View File

@ -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
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
// <addr
lda.z addr
// *VERA_ADDRX_L = <addr
// *VERA_ADDRX_L = <vdest
// Set address
lda #0
sta VERA_ADDRX_L
// *VERA_ADDRX_M = >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
lda #>src
sta.z s+1
__b1:
// for(; s!=end; s++)
lda.z s+1
cmp #>end
bne __b2
lda.z s
cmp #<end
bne __b2
// }
rts
__b2:
// *VERA_DATA0 = *s
ldy #0
lda (s),y
sta VERA_DATA0
// for(; s!=end; s++)
inc.z s
bne !+
inc.z s+1
!:
jmp __b1
}
// 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) vaddr, byte register(X) data)
vpoke: {
.label vaddr = 2
// *VERA_CTRL &= ~VERA_ADDRSEL
// Select DATA0
lda #VERA_ADDRSEL^$ff
and VERA_CTRL
sta VERA_CTRL
// <vaddr
lda.z vaddr
// *VERA_ADDRX_L = <vaddr
// Set address
sta VERA_ADDRX_L
// >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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 ]