From 2e0d00bf4e8f8481dab15284ff67e2ac5e1b2513 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 26 Jan 2021 21:55:20 +0100 Subject: [PATCH] Created new functions to: - generate bitmap load files. - load bitmap files into banked memory on the cx16, cross banks between address space A000 and BFFF. - added cx16-kernal.c and cx16-kernal.h to load files. - created arithmetic to determine bank addressing using dwords over the 512K of memory (used in bnkcpy_vram_address() and LoadFileBanked()). - optimized functions for vera and conio. --- .../cache/fragment-cache-wdc65c02.asm | 760 ++++++++++++++++++ src/main/kc/include/conio.h | 6 +- src/main/kc/include/cx16-kernal.h | 14 + src/main/kc/include/cx16-vera.h | 3 +- src/main/kc/include/cx16.h | 23 + src/main/kc/lib/cx16-kernal.c | 50 ++ src/main/kc/lib/cx16.c | 86 +- src/main/kc/lib/veralib.c | 2 +- src/test/kc/examples/cx16/bankaddressing.c | 34 + src/test/kc/examples/cx16/cx16-sprites.c | 2 +- src/test/kc/examples/cx16/cx16-vera.c | 1 + src/test/kc/examples/cx16/input.c | 8 + src/test/kc/examples/cx16/load.ld | 10 + src/test/kc/examples/cx16/load_file_in_bank.c | 102 +++ src/test/kc/examples/cx16/ship.png | Bin 0 -> 1142 bytes 15 files changed, 1096 insertions(+), 5 deletions(-) create mode 100644 src/main/kc/include/cx16-kernal.h create mode 100644 src/main/kc/lib/cx16-kernal.c create mode 100644 src/test/kc/examples/cx16/bankaddressing.c create mode 100644 src/test/kc/examples/cx16/input.c create mode 100644 src/test/kc/examples/cx16/load.ld create mode 100644 src/test/kc/examples/cx16/load_file_in_bank.c create mode 100644 src/test/kc/examples/cx16/ship.png diff --git a/src/main/fragment/cache/fragment-cache-wdc65c02.asm b/src/main/fragment/cache/fragment-cache-wdc65c02.asm index 5e156ee9c..b0fdac930 100644 --- a/src/main/fragment/cache/fragment-cache-wdc65c02.asm +++ b/src/main/fragment/cache/fragment-cache-wdc65c02.asm @@ -3052,3 +3052,763 @@ sta {z1}+1 //FRAGMENT vbuz1=vbuaa_bor_vbuz1 ora {z1} sta {z1} +//FRAGMENT _deref_pbuz1=_deref_pbuz1 +ldy #0 +lda ({z1}),y +ldy #0 +sta ({z1}),y +//FRAGMENT _deref_pbuz1=vbuc1 +lda #{c1} +ldy #0 +sta ({z1}),y +//FRAGMENT vbuaa_neq_0_then_la1 +cmp #0 +bne {la1} +//FRAGMENT pbuc1_derefidx_vbuaa=vbuc2 +tay +lda #{c2} +sta {c1},y +//FRAGMENT pbuc1_derefidx_vbuyy=vbuc2 +lda #{c2} +sta {c1},y +//FRAGMENT vbuz1=_byte_vwuz2 +lda {z2} +sta {z1} +//FRAGMENT _deref_pbuz1=pbuc1_derefidx_vbuz2 +ldy {z2} +lda {c1},y +ldy #0 +sta ({z1}),y +//FRAGMENT pbuz1=_inc_pbuz2 +clc +lda {z2} +adc #1 +sta {z1} +lda {z2}+1 +adc #0 +sta {z1}+1 +//FRAGMENT vbuz1_ge_vbuz2_then_la1 +lda {z1} +cmp {z2} +bcs {la1} +//FRAGMENT 0_neq__deref_pbuz1_then_la1 +ldy #0 +lda ({z1}),y +cmp #0 +bne {la1} +//FRAGMENT vbuz1=vbuz1_minus_vbuz2 +lda {z1} +sec +sbc {z2} +sta {z1} +//FRAGMENT vbuaa_lt_vbuc1_then_la1 +cmp #{c1} +bcc {la1} +//FRAGMENT _deref_pbuz1=pbuc1_derefidx_vbuaa +tay +lda {c1},y +ldy #0 +sta ({z1}),y +//FRAGMENT _deref_pbuz1=pbuc1_derefidx_vbuxx +lda {c1},x +ldy #0 +sta ({z1}),y +//FRAGMENT _deref_pbuz1=pbuc1_derefidx_vbuyy +lda {c1},y +ldy #0 +sta ({z1}),y +//FRAGMENT vbuaa_ge_vbuz1_then_la1 +cmp {z1} +bcs {la1} +//FRAGMENT vbuxx=vbuxx_minus_vbuz1 +txa +sec +sbc {z1} +tax +//FRAGMENT vbuz1=vbuz1_minus_vbuaa +eor #$ff +sec +adc {z1} +sta {z1} +//FRAGMENT vbuxx=vbuxx_minus_vbuaa +sta $ff +txa +sec +sbc $ff +tax +//FRAGMENT vbuz1=vbuz1_minus_vbuxx +txa +eor #$ff +sec +adc {z1} +sta {z1} +//FRAGMENT vbuxx=vbuxx_minus_vbuxx +lda #0 +tax +//FRAGMENT vbuz1=vbuz1_minus_vbuyy +tya +eor #$ff +sec +adc {z1} +sta {z1} +//FRAGMENT vbuxx=vbuxx_minus_vbuyy +txa +sty $ff +sec +sbc $ff +tax +//FRAGMENT vbuxx_ge_vbuz1_then_la1 +cpx {z1} +bcs {la1} +//FRAGMENT vbuz1_ge_vbuxx_then_la1 +lda {z1} +stx $ff +cmp $ff +bcs {la1} +//FRAGMENT vbuz1_ge_vbuyy_then_la1 +lda {z1} +sty $ff +cmp $ff +bcs {la1} +//FRAGMENT vbuxx_ge_vbuyy_then_la1 +sty $ff +cpx $ff +bcs {la1} +//FRAGMENT vbuyy_ge_vbuz1_then_la1 +cpy {z1} +bcs {la1} +//FRAGMENT _deref_pwuc1=_deref_pwuc1_plus_vbuc2 +NO_SYNTHESIS +//FRAGMENT _deref_pwuc1=_deref_pwuc1_plus_vbsc2 +NO_SYNTHESIS +//FRAGMENT _deref_pwuc1=_deref_pwuc1_plus_vwuc2 +lda #<{c2} +clc +adc {c1} +sta {c1} +lda #>{c2} +adc {c1}+1 +sta {c1}+1 +//FRAGMENT _deref_pwuc1=vbuc2 +lda #0 +sta {c1}+1 +lda #<{c2} +sta {c1} +//FRAGMENT pbuz1_neq_pbuc1_then_la1 +lda {z1}+1 +cmp #>{c1} +bne {la1} +lda {z1} +cmp #<{c1} +bne {la1} +//FRAGMENT vbuaa=_byte_vwuz1 +lda {z1} +//FRAGMENT vbuxx=_byte_vwuz1 +lda {z1} +tax +//FRAGMENT vbuyy=_byte_vwuz1 +lda {z1} +tay +//FRAGMENT vduz1_lt_vwuc1_then_la1 +NO_SYNTHESIS +//FRAGMENT vduz1_lt_vduc1_then_la1 +lda {z1}+3 +cmp #>{c1}>>$10 +bcc {la1} +bne !+ +lda {z1}+2 +cmp #<{c1}>>$10 +bcc {la1} +bne !+ +lda {z1}+1 +cmp #>{c1} +bcc {la1} +bne !+ +lda {z1} +cmp #<{c1} +bcc {la1} +!: +//FRAGMENT vduz1=vduz2_plus_vwuc1 +lda {z2} +clc +adc #<{c1} +sta {z1} +lda {z2}+1 +adc #>{c1} +sta {z1}+1 +lda {z2}+2 +adc #0 +sta {z1}+2 +lda {z2}+3 +adc #0 +sta {z1}+3 +//FRAGMENT vwuz1=vwuz2_bor_vbuz3 +lda {z3} +ora {z2} +sta {z1} +lda {z2}+1 +sta {z1}+1 +//FRAGMENT vwuz1=vwuz2_ror_5 +lda {z2}+1 +lsr +sta {z1}+1 +lda {z2} +ror +sta {z1} +lsr {z1}+1 +ror {z1} +lsr {z1}+1 +ror {z1} +lsr {z1}+1 +ror {z1} +lsr {z1}+1 +ror {z1} +//FRAGMENT vwuz1=vwuz2_band_vwuc1 +lda {z2} +and #<{c1} +sta {z1} +lda {z2}+1 +and #>{c1} +sta {z1}+1 +//FRAGMENT vwuz1=vwuz2_plus_vwuc1 +clc +lda {z2} +adc #<{c1} +sta {z1} +lda {z2}+1 +adc #>{c1} +sta {z1}+1 +//FRAGMENT vduz1=vduz1_plus_vwuc1 +lda {z1} +clc +adc #<{c1} +sta {z1} +lda {z1}+1 +adc #>{c1} +sta {z1}+1 +lda {z1}+2 +adc #0 +sta {z1}+2 +lda {z1}+3 +adc #0 +sta {z1}+3 +//FRAGMENT vwuz1=vwuz2_bor_vbuxx +txa +ora {z2} +sta {z1} +lda {z2}+1 +sta {z1}+1 +//FRAGMENT vwuz1=vwuz2_bor_vbuyy +tya +ora {z2} +sta {z1} +lda {z2}+1 +sta {z1}+1 +//FRAGMENT vwuz1=vwuz1_rol_8 +lda {z1} +sta {z1}+1 +lda #0 +sta {z1} +//FRAGMENT vwuz1=vwuz1_bor_vbuyy +tya +ora {z1} +sta {z1} +//FRAGMENT vwuz1=vwuz1_band_vwuc1 +lda {z1} +and #<{c1} +sta {z1} +lda {z1}+1 +and #>{c1} +sta {z1}+1 +//FRAGMENT vwuz1=vwuz1_ror_5 +lsr {z1}+1 +ror {z1} +lsr {z1}+1 +ror {z1} +lsr {z1}+1 +ror {z1} +lsr {z1}+1 +ror {z1} +lsr {z1}+1 +ror {z1} +//FRAGMENT vbuz1=_byte_vduz2 +lda {z2} +sta {z1} +//FRAGMENT vduz1=pduc1_derefidx_vbuz2 +ldy {z2} +lda {c1},y +sta {z1} +lda {c1}+1,y +sta {z1}+1 +lda {c1}+2,y +sta {z1}+2 +lda {c1}+3,y +sta {z1}+3 +//FRAGMENT vduz1_ge_vduz2_then_la1 +lda {z1}+3 +cmp {z2}+3 +bcc !+ +bne {la1} +lda {z1}+2 +cmp {z2}+2 +bcc !+ +bne {la1} +lda {z1}+1 +cmp {z2}+1 +bcc !+ +bne {la1} +lda {z1} +cmp {z2} +bcs {la1} +!: +//FRAGMENT vbsz1=_sbyte_vwuz2 +lda {z2} +sta {z1} +//FRAGMENT vbsz1=_inc_vbsz1 +inc {z1} +//FRAGMENT vbsz1=vbsz2_minus_vbsz3 +lda {z2} +sec +sbc {z3} +sta {z1} +//FRAGMENT vbsz1=vbsc1 +lda #{c1} +sta {z1} +//FRAGMENT 0_neq_vbsz1_then_la1 +lda {z1} +cmp #0 +bne {la1} +//FRAGMENT vduz1=vduz1_minus_vduz2 +lda {z1} +sec +sbc {z2} +sta {z1} +lda {z1}+1 +sbc {z2}+1 +sta {z1}+1 +lda {z1}+2 +sbc {z2}+2 +sta {z1}+2 +lda {z1}+3 +sbc {z2}+3 +sta {z1}+3 +//FRAGMENT vbuz1_le_vbuc1_then_la1 +lda #{c1} +cmp {z1} +bcs {la1} +//FRAGMENT vbuaa=_byte_vduz1 +lda {z1} +//FRAGMENT vbuxx=_byte_vduz1 +lda {z1} +tax +//FRAGMENT vbuyy=_byte_vduz1 +lda {z1} +tay +//FRAGMENT vbuz1=vbuaa_rol_2 +asl +asl +sta {z1} +//FRAGMENT vbuz1=vbuyy_rol_2 +tya +asl +asl +sta {z1} +//FRAGMENT vbuaa=vbuaa_rol_2 +asl +asl +//FRAGMENT vbuaa=vbuxx_rol_2 +txa +asl +asl +//FRAGMENT vbuaa=vbuyy_rol_2 +tya +asl +asl +//FRAGMENT vbuxx=vbuaa_rol_2 +asl +asl +tax +//FRAGMENT vbuxx=vbuyy_rol_2 +tya +asl +asl +tax +//FRAGMENT vbuyy=vbuaa_rol_2 +asl +asl +tay +//FRAGMENT vbuyy=vbuxx_rol_2 +txa +asl +asl +tay +//FRAGMENT vbuyy=vbuyy_rol_2 +tya +asl +asl +tay +//FRAGMENT vduz1=pduc1_derefidx_vbuaa +tay +lda {c1},y +sta {z1} +lda {c1}+1,y +sta {z1}+1 +lda {c1}+2,y +sta {z1}+2 +lda {c1}+3,y +sta {z1}+3 +//FRAGMENT vduz1=pduc1_derefidx_vbuxx +lda {c1},x +sta {z1} +lda {c1}+1,x +sta {z1}+1 +lda {c1}+2,x +sta {z1}+2 +lda {c1}+3,x +sta {z1}+3 +//FRAGMENT vduz1=pduc1_derefidx_vbuyy +lda {c1},y +sta {z1} +lda {c1}+1,y +sta {z1}+1 +lda {c1}+2,y +sta {z1}+2 +lda {c1}+3,y +sta {z1}+3 +//FRAGMENT vbsaa=_sbyte_vwuz1 +lda {z1} +//FRAGMENT vbsxx=_sbyte_vwuz1 +ldx {z1} +//FRAGMENT vbsz1=vbsz2_minus_vbsxx +txa +eor #$ff +sec +adc {z2} +sta {z1} +//FRAGMENT vbsz1=vbsz2_minus_vbsyy +tya +eor #$ff +sec +adc {z2} +sta {z1} +//FRAGMENT vbsz1=vbsxx_minus_vbsz2 +txa +sec +sbc {z2} +sta {z1} +//FRAGMENT vbsz1=vbsxx_minus_vbsxx +lda #0 +sta {z1} +//FRAGMENT vbsz1=vbsxx_minus_vbsyy +txa +sty $ff +sec +sbc $ff +sta {z1} +//FRAGMENT vbsz1=vbsyy_minus_vbsz2 +tya +sec +sbc {z2} +sta {z1} +//FRAGMENT vbsz1=vbsyy_minus_vbsxx +tya +stx $ff +sec +sbc $ff +sta {z1} +//FRAGMENT vbsz1=vbsyy_minus_vbsyy +lda #0 +sta {z1} +//FRAGMENT _deref_pbuz1=vbuaa +ldy #0 +sta ({z1}),y +//FRAGMENT vbuaa_le_vbuc1_then_la1 +cmp #{c1} +bcc {la1} +beq {la1} +//FRAGMENT vbuaa=vbuaa_plus_vbuc1 +clc +adc #{c1} +//FRAGMENT vbuxx_le_vbuc1_then_la1 +cpx #{c1} +bcc {la1} +beq {la1} +//FRAGMENT vbuyy_lt_vbuc1_then_la1 +cpy #{c1} +bcc {la1} +//FRAGMENT vbuyy_le_vbuc1_then_la1 +cpy #{c1} +bcc {la1} +beq {la1} +//FRAGMENT vbsxx=_inc_vbsxx +inx +//FRAGMENT vbsyy=_sbyte_vwuz1 +ldy {z1} +//FRAGMENT vbsyy=_inc_vbsyy +iny +//FRAGMENT vbuz1=vbuz2_plus_vbuxx +txa +clc +adc {z2} +sta {z1} +//FRAGMENT vbuaa=vbuz1_plus_vbuxx +txa +clc +adc {z1} +//FRAGMENT vbuxx=vbuz1_plus_vbuxx +txa +clc +adc {z1} +tax +//FRAGMENT vbuyy=vbuz1_plus_vbuxx +txa +clc +adc {z1} +tay +//FRAGMENT vbuz1=vbuaa_plus_vbuxx +stx $ff +clc +adc $ff +sta {z1} +//FRAGMENT vbuaa=vbuaa_plus_vbuxx +stx $ff +clc +adc $ff +//FRAGMENT vbuxx=vbuaa_plus_vbuxx +stx $ff +clc +adc $ff +tax +//FRAGMENT vbuyy=vbuaa_plus_vbuxx +stx $ff +clc +adc $ff +tay +//FRAGMENT vbuz1=vbuxx_plus_vbuxx +txa +asl +sta {z1} +//FRAGMENT vbuaa=vbuxx_plus_vbuxx +txa +asl +//FRAGMENT vbuxx=vbuxx_plus_vbuxx +txa +asl +tax +//FRAGMENT vbuyy=vbuxx_plus_vbuxx +txa +asl +tay +//FRAGMENT vbuz1=vbuyy_plus_vbuxx +txa +sty $ff +clc +adc $ff +sta {z1} +//FRAGMENT vbuaa=vbuyy_plus_vbuxx +txa +sty $ff +clc +adc $ff +//FRAGMENT vbuxx=vbuyy_plus_vbuxx +txa +sty $ff +clc +adc $ff +tax +//FRAGMENT vbuyy=vbuyy_plus_vbuxx +txa +sty $ff +clc +adc $ff +tay +//FRAGMENT vbuz1=vbuz2_plus_vbuyy +tya +clc +adc {z2} +sta {z1} +//FRAGMENT vbuaa=vbuz1_plus_vbuyy +tya +clc +adc {z1} +//FRAGMENT vbuxx=vbuz1_plus_vbuyy +tya +clc +adc {z1} +tax +//FRAGMENT vbuyy=vbuz1_plus_vbuyy +tya +clc +adc {z1} +tay +//FRAGMENT vbuz1=vbuaa_plus_vbuyy +sty $ff +clc +adc $ff +sta {z1} +//FRAGMENT vbuaa=vbuaa_plus_vbuyy +sty $ff +clc +adc $ff +//FRAGMENT vbuxx=vbuaa_plus_vbuyy +sty $ff +clc +adc $ff +tax +//FRAGMENT vbuyy=vbuaa_plus_vbuyy +sty $ff +clc +adc $ff +tay +//FRAGMENT vbuz1=vbuxx_plus_vbuyy +txa +sty $ff +clc +adc $ff +sta {z1} +//FRAGMENT vbuaa=vbuxx_plus_vbuyy +txa +sty $ff +clc +adc $ff +//FRAGMENT vbuxx=vbuxx_plus_vbuyy +txa +sty $ff +clc +adc $ff +tax +//FRAGMENT vbuyy=vbuxx_plus_vbuyy +txa +sty $ff +clc +adc $ff +tay +//FRAGMENT vbuz1=vbuyy_plus_vbuyy +tya +asl +sta {z1} +//FRAGMENT vbuaa=vbuyy_plus_vbuyy +tya +asl +//FRAGMENT vbuxx=vbuyy_plus_vbuyy +tya +asl +tax +//FRAGMENT vbuyy=vbuyy_plus_vbuyy +tya +asl +tay +//FRAGMENT vwuz1=vwuz1_bor_vbuxx +txa +ora {z1} +sta {z1} +//FRAGMENT vbuz1=vbuaa_plus_vbuz1 +clc +adc {z1} +sta {z1} +//FRAGMENT vwuz1=vwuz2_rol_3 +lda {z2} +asl +sta {z1} +lda {z2}+1 +rol +sta {z1}+1 +asl {z1} +rol {z1}+1 +asl {z1} +rol {z1}+1 +//FRAGMENT vwuz1=_word_vbuaa +sta {z1} +lda #0 +sta {z1}+1 +//FRAGMENT vwuz1=vwuz1_rol_3 +asl {z1} +rol {z1}+1 +asl {z1} +rol {z1}+1 +asl {z1} +rol {z1}+1 +//FRAGMENT _deref_pssc1=_deref_pssc2_memcpy_vbuc3 +ldy #{c3} +!: +lda {c2}-1,y +sta {c1}-1,y +dey +bne !- +//FRAGMENT pbuz1=pbuz2_plus_vwuc1 +clc +lda {z2} +adc #<{c1} +sta {z1} +lda {z2}+1 +adc #>{c1} +sta {z1}+1 +//FRAGMENT pbuz1_neq_vwuc1_then_la1 +lda {z1}+1 +cmp #>{c1} +bne {la1} +lda {z1} +cmp #<{c1} +bne {la1} +//FRAGMENT vduz1=vduz2_plus_vduz1 +lda {z1} +clc +adc {z2} +sta {z1} +lda {z1}+1 +adc {z2}+1 +sta {z1}+1 +lda {z1}+2 +adc {z2}+2 +sta {z1}+2 +lda {z1}+3 +adc {z2}+3 +sta {z1}+3 +//FRAGMENT pbuz1=pbuz1_plus_vwuc1 +clc +lda {z1} +adc #<{c1} +sta {z1} +lda {z1}+1 +adc #>{c1} +sta {z1}+1 +//FRAGMENT vduz1=vduz2_plus_vduc1 +lda {z2} +clc +adc #<{c1} +sta {z1} +lda {z2}+1 +adc #>{c1} +sta {z1}+1 +lda {z2}+2 +adc #<{c1}>>$10 +sta {z1}+2 +lda {z2}+3 +adc #>{c1}>>$10 +sta {z1}+3 +//FRAGMENT vduz1=vduz2_plus_vbuc1 +lda #{c1} +clc +adc {z2} +sta {z1} +lda {z2}+1 +adc #0 +sta {z1}+1 +lda {z2}+2 +adc #0 +sta {z1}+2 +lda {z2}+3 +adc #0 +sta {z1}+3 +//FRAGMENT vduz1=vduz1_plus_vbuc1 +lda {z1} +clc +adc #{c1} +sta {z1} +bcc !+ +inc {z1}+1 +bne !+ +inc {z1}+2 +bne !+ +inc {z1}+3 +!: diff --git a/src/main/kc/include/conio.h b/src/main/kc/include/conio.h index f1823abe9..d12fdb02b 100644 --- a/src/main/kc/include/conio.h +++ b/src/main/kc/include/conio.h @@ -62,4 +62,8 @@ unsigned char cursor(unsigned char onoff); // If onoff is 1, scrolling is enabled when outputting past the end of the screen // If onoff is 0, scrolling is disabled and the cursor instead moves to (0,0) // The function returns the old scroll setting. -unsigned char scroll(unsigned char onoff); \ No newline at end of file +unsigned char scroll(unsigned char onoff); + +// Set the layer with which the conio will interact. +// - layer: value of 0 or 1. +void screenlayer(unsigned byte layer); \ No newline at end of file diff --git a/src/main/kc/include/cx16-kernal.h b/src/main/kc/include/cx16-kernal.h new file mode 100644 index 000000000..7be139a95 --- /dev/null +++ b/src/main/kc/include/cx16-kernal.h @@ -0,0 +1,14 @@ +// Kernal SETNAM function +// SETNAM. Set file name parameters. +void setnam(char* filename); + + +// SETLFS. Set file parameters. +void setlfs(char device); + + +// LOAD. Load or verify file. (Must call SETLFS and SETNAM beforehands.) +// - verify: 0 = Load, 1-255 = Verify +// +// Returns a status, 0xff: Success other: Kernal Error Code +char load(char* address, char verify); diff --git a/src/main/kc/include/cx16-vera.h b/src/main/kc/include/cx16-vera.h index 8c77d1a2c..079feb49d 100644 --- a/src/main/kc/include/cx16-vera.h +++ b/src/main/kc/include/cx16-vera.h @@ -262,5 +262,6 @@ struct VERA_SPRITE { // - 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) +// xBPP sprite modes +const unsigned int VERA_SPRITE_4BPP = 0x0000; const unsigned int VERA_SPRITE_8BPP = 0x8000; diff --git a/src/main/kc/include/cx16.h b/src/main/kc/include/cx16.h index fc089da43..9d05812e8 100644 --- a/src/main/kc/include/cx16.h +++ b/src/main/kc/include/cx16.h @@ -7,6 +7,9 @@ #include #include +// to POKE the address space. +#define POKE(addr,val) (*(unsigned char*) (addr) = (val)) + // The VIA#1: ROM/RAM Bank Control // Port A Bits 0-7 RAM bank // Port B Bits 0-2 ROM bank @@ -37,11 +40,19 @@ 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; + +// Load a file to memory +// Returns a status: +// - 0xff: Success +// - other: Kernal Error Code (https://commodore.ca/manuals/pdfs/commodore_error_messages.pdf) +char LoadFileBanked( char device, char* filename, dword address); + // Put a single byte into VRAM. // Uses VERA DATA0 // - vbank: Which 64K VRAM bank to put data into (0/1) @@ -64,6 +75,15 @@ char vpeek(char vbank, char* vaddr); // - num: The number of bytes to copy void memcpy_to_vram(char vbank, void* vdest, void* src, unsigned int num ); +void memcpy_vram_address(dword vdest, byte* src, unsigned int num ); + +// Copy block of banked internal memory (256 banks at A000-BFFF) to VERA 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. +// - vdest: dword of the destination address in VRAM +// - src: dword of source banked address in RAM. This address is a linair project of the banked memory of 512K to 2048K. +// - num: dword of the number of bytes to copy +void bnkcpy_vram_address(dword vdest, dword src, dword num ); + // Copy block of memory (from VRAM to VRAM) // Copies the values from the location pointed by src to the location pointed by dest. // The method uses the VERA access ports 0 and 1 to copy data from and to in VRAM. @@ -76,3 +96,6 @@ void memcpy_to_vram(char vbank, void* vdest, void* src, unsigned int num ); // - num: The number of bytes to copy void memcpy_in_vram(char dest_bank, void *dest, char dest_increment, char src_bank, void *src, char src_increment, unsigned int num ); +void memset_vram_address(dword vdest_address, byte data, dword num); + +void memset_vram_word(dword vdest_address, word data, dword num); diff --git a/src/main/kc/lib/cx16-kernal.c b/src/main/kc/lib/cx16-kernal.c new file mode 100644 index 000000000..e3fa4e6da --- /dev/null +++ b/src/main/kc/lib/cx16-kernal.c @@ -0,0 +1,50 @@ +#include + +// Kernal SETNAM function +// SETNAM. Set file name parameters. +void setnam(char* filename) { + char filename_len = (char)strlen(filename); + asm { + // Kernal SETNAM function + // SETNAM. Set file name parameters. + // Input: A = File name length; X/Y = Pointer to file name. + lda filename_len + ldx filename + ldy filename+1 + jsr $ffbd + } +} + +// SETLFS. Set file parameters. +void setlfs(char device) { + asm { + // SETLFS. Set file parameters. + // Input: A = Logical number; X = Device number; Y = Secondary address. + ldx device + lda #1 + ldy #0 + jsr $ffba + } +} + +// LOAD. Load or verify file. (Must call SETLFS and SETNAM beforehands.) +// - verify: 0 = Load, 1-255 = Verify +// +// Returns a status, 0xff: Success other: Kernal Error Code +char load(char* address, char verify) { + char status; + asm { + //LOAD. Load or verify file. (Must call SETLFS and SETNAM beforehands.) + // Input: A: 0 = Load, 1-255 = Verify; X/Y = Load address (if secondary address = 0). + // Output: Carry: 0 = No errors, 1 = Error; A = KERNAL error code (if Carry = 1); X/Y = Address of last byte loaded/verified (if Carry = 0). + ldx address + ldy address+1 + lda verify + jsr $ffd5 + bcs error + lda #$ff + error: + sta status + } + return status; +} diff --git a/src/main/kc/lib/cx16.c b/src/main/kc/lib/cx16.c index 925bf3848..e4bb8562c 100644 --- a/src/main/kc/lib/cx16.c +++ b/src/main/kc/lib/cx16.c @@ -3,6 +3,24 @@ // https://github.com/commanderx16/x16-docs/blob/master/Commander%20X16%20Programmer's%20Reference%20Guide.md #include +#include + +#define POKE(addr,val) (*(unsigned char*) (addr) = (val)) + +// Load a file to memory +// Returns a status: +// - 0xff: Success +// - other: Kernal Error Code (https://commodore.ca/manuals/pdfs/commodore_error_messages.pdf) +char LoadFileBanked( char device, char* filename, dword address) { + setnam(filename); + setlfs(device); + byte bank = (byte)(((((word)<(>address)<<8)|>(>5)+((word)<(>address)<<3)); + byte* addr = (((vdest); + *VERA_ADDRX_H |= VERA_INC_1; + // Transfer the data + for(word c=0; c(vdest); + *VERA_ADDRX_H |= VERA_INC_1; + + dword beg = src; + dword end = src+num; + + byte bank = (byte)(((((word)<(>beg)<<8)|>(>5)+((word)<(>beg)<<3)); + + byte* addr = (((vdest_address); + *VERA_ADDRX_H |= VERA_INC_1; + // Transfer the data + for(dword i = 0; idata; + } +} + // Copy block of memory (from VRAM to VRAM) // Copies the values from the location pointed by src to the location pointed by dest. // The method uses the VERA access ports 0 and 1 to copy data from and to in VRAM. diff --git a/src/main/kc/lib/veralib.c b/src/main/kc/lib/veralib.c index 74fd95727..e268b516b 100644 --- a/src/main/kc/lib/veralib.c +++ b/src/main/kc/lib/veralib.c @@ -6,6 +6,7 @@ #include #include + // --- VERA function encapsulation --- // --- VERA layer management --- @@ -714,4 +715,3 @@ void vera_tile_area(byte layer, word tileindex, byte x, byte y, byte w, byte h, } } - diff --git a/src/test/kc/examples/cx16/bankaddressing.c b/src/test/kc/examples/cx16/bankaddressing.c new file mode 100644 index 000000000..28adfa717 --- /dev/null +++ b/src/test/kc/examples/cx16/bankaddressing.c @@ -0,0 +1,34 @@ +// Example program for the Commander X16 + + +#include +#include <6502.h> +#include +#include +#include +#include + +void main() { + + dword src = (dword)0x02000; + dword num = 64*64*2; + + word inc = 0x0123; + + for(dword src=0x0000;src<0x3F000;src+=num) { + + dword calcbeg = src; + dword calcend = src+num+(-1); // TODO code fragment needed. + byte bankbeg = (byte)(((((word)<(>calcbeg)<<8)|>(>5)+((word)<(>calcbeg)<<3)); + byte bankend = (byte)(((((word)<(>calcend)<<8)|>(>5)+((word)<(>calcend)<<3)); + const word borderbeg = 0xA000; + const word borderend = 0xA000+0x1FFF; + word beg = ((idx .var palette = Hashtable() diff --git a/src/test/kc/examples/cx16/cx16-vera.c b/src/test/kc/examples/cx16/cx16-vera.c index c353ed2b6..0699d2a78 100644 --- a/src/test/kc/examples/cx16/cx16-vera.c +++ b/src/test/kc/examples/cx16/cx16-vera.c @@ -43,6 +43,7 @@ void main() { printf( "\n0. exit.\n"); byte menu = 0; + while(menu==0) { menu = fgetc(); } diff --git a/src/test/kc/examples/cx16/input.c b/src/test/kc/examples/cx16/input.c new file mode 100644 index 000000000..436dd8f7b --- /dev/null +++ b/src/test/kc/examples/cx16/input.c @@ -0,0 +1,8 @@ +#include + + +void main() { + byte test = 0; + while(test==0) test=fgetc(); + printf("\nchar = %u\n", test); +} \ No newline at end of file diff --git a/src/test/kc/examples/cx16/load.ld b/src/test/kc/examples/cx16/load.ld new file mode 100644 index 000000000..accfb1b93 --- /dev/null +++ b/src/test/kc/examples/cx16/load.ld @@ -0,0 +1,10 @@ +// Create a D64 disk containing the program and a sprite file +.file [name="%O", type="prg", segments="Program"] +.file [name="SPRITE", type="bin", segments="Sprite"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=%P] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(%E) +.segmentdef Sprite diff --git a/src/test/kc/examples/cx16/load_file_in_bank.c b/src/test/kc/examples/cx16/load_file_in_bank.c new file mode 100644 index 000000000..d60831ea3 --- /dev/null +++ b/src/test/kc/examples/cx16/load_file_in_bank.c @@ -0,0 +1,102 @@ +// Example program for the Commander X16 + +#pragma link("load.ld") + + +#include +#include +#include <6502.h> +#include +#include +#include +#include +#include + + +#pragma data_seg(Sprite) +export char SPRITE_PIXELS[] = kickasm(resource "ship.png") {{ + .var pic = LoadPicture("ship.png") + // palette: rgb->idx + .var palette = Hashtable() + // RGB value for each palette index + .var palList = List() + // Next palette index + .var nxt_idx = 0; + // Extract palette while outputting pixels as palete index values + .for (var y=0; y<64; y++) { + .for (var x=0;x<64; x++) { + // Find palette index (add if not known) + .var rgb = pic.getPixel(x,y); + .var idx = palette.get(rgb) + .if(idx==null) { + .eval idx = nxt_idx++; + .eval palette.put(rgb,idx); + .eval palList.add(rgb) + } + } + } + .if(nxt_idx>16) .error "Image has too many colours "+nxt_idx + + .for(var i=0;i<16;i++) { + .var rgb = palList.get(i) + .var red = floor(rgb / [256*256]) + .var green = floor(rgb/256) & 255 + .var blue = rgb & 255 + // bits 4-8: green, bits 0-3 blue + .byte green&$f0 | blue/16 + // bits bits 0-3 red + .byte red/16 + } + + .for (var y=0; y<64; y++) { + .for (var x=0;x<64; x+=2) { + // Find palette index (add if not known) + .var rgb = pic.getPixel(x,y); + .var idx1 = palette.get(rgb) + .if(idx1==null) { + .printnow "unknown rgb value!" + } + // Find palette index (add if not known) + .eval rgb = pic.getPixel(x+1,y); + .var idx2 = palette.get(rgb) + .if(idx2==null) { + .printnow "unknown rgb value!" + } + .byte idx1*16+idx2; + } + } +}}; + +#pragma data_seg(Data) + + + + + +void main() { + + vera_layer_set_text_color_mode( 1, VERA_LAYER_CONFIG_16C ); + screenlayer(1); + clrscr(); + printf("\n\nsprite banked file load and display demo.\n"); + + const dword BANK_SPRITE = 0x12000; // Load in bank 9. + const dword VRAM_SPRITE = 0x10000; // Load in bank 9. + // Sprite attributes: 8bpp, in front, 64x64, address SPRITE_PIXELS_VRAM + struct VERA_SPRITE SPRITE_ATTR = { <(VRAM_SPRITE/32)|VERA_SPRITE_8BPP, 320-32, 240-32, 0x0c, 0xf1 }; + + char status = LoadFileBanked(8, "SPRITE", BANK_SPRITE ); + + bnkcpy_vram_address(VERA_PALETTE+32, BANK_SPRITE-2, 32); + bnkcpy_vram_address(VRAM_SPRITE, BANK_SPRITE+32-2, 64*32); + + SPRITE_ATTR.ADDR = <(VRAM_SPRITE/32)|VERA_SPRITE_4BPP; + SPRITE_ATTR.X = 100; + SPRITE_ATTR.Y = 100; + memcpy_to_vram((char)>VERA_SPRITE_ATTR, ;WN_#AGYF%pP%5%M)gIY`=-lY)c*40u~QWzWnvX%R@x|&+(@2Za;*8Xwg(kNkI649uXl@JtfyF zg4I>|DJ7BC+Q7fe)kOePmD`Z2CIhzURVH?sa<{uYR+j;!i?G5+{0tzC z2rU}X(sclxXCPcF{KF0@CgLwP_0_)Cxn6D6+>cLjWGeR!bgQa zVZ(TP{;pOtH+lThU(f*>)PZMk9ZK+A&F=5?*J8#^^TFZCT#?XgOzmp5qJLT;`#|-X zo2*Z5VRf=UQ} zo6Ck`(pnb>PM5aXA_2$sHvp(bB?wCZZC)~*h5*)@t0Jg%NG{%VXAwJ}0Wh1#qwD}= zLtLuRWay2V^OYi}@3SLoK!B+Me${x&0NDP=|41htfn(Hs7mnkE|_ z7$0gA`_O_o;6tY5?d^pRKCBmd{{-=|Lh;2!$3905+gI(*7LPNY0y@ z09zT*$mZf6LZ=g81`ldnDL$(W<-DN)zZGoB(-VW6bpe)BPOL5JyPr+{{~xRg+BP z{;r_yIyjuYG2lXRxxoFP@|v*%bc2gN=)WUCg-X|fvVpkp+}qFbBvq>0U()|J;V}bsOlxZZ;F3t(6u!0xSfb* zo!^FM(X$#%fR6iw>^%+j4xOgxc@6-;vqx8*DD9#Kt8UFsIp19YxQ$x&!bd;K0+3WM zk%$`#5&{)MS=3T0S4@~3tm&it$Q2T+mT^oUEqE0Dc)$7`;7A(ja)@QCK1*WD<-~a#s literal 0 HcmV?d00001