From fc432a3bbf4c841f543c106e9b3aaf373c97e584 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Thu, 2 Nov 2023 08:17:15 -0500 Subject: [PATCH] c64: .wiz --- presets/c64/c64.wiz | 127 ++++++++++++++++++++++++++++ presets/c64/hello.wiz | 181 ++++++++++++++++++++++++++++++++++++++++ presets/c64/upandaway.c | 55 +++++++----- scripts/serveit.py | 2 +- src/platform/c64.ts | 1 + 5 files changed, 343 insertions(+), 23 deletions(-) create mode 100644 presets/c64/c64.wiz create mode 100644 presets/c64/hello.wiz diff --git a/presets/c64/c64.wiz b/presets/c64/c64.wiz new file mode 100644 index 00000000..05241c27 --- /dev/null +++ b/presets/c64/c64.wiz @@ -0,0 +1,127 @@ + +struct CoordXY { + x : u8, + y : u8 +} + +struct SIDVoice { + freq : u16, /* Frequency */ + pw : u16, /* Pulse width */ + ctrl : u16, /* Control register */ + ad : u16, /* Attack/decay */ + sr : u16 /* Sustain/release */ +} + +typealias SpriteData : [u8; 64]; + +union VICBank { + spritedata : [SpriteData; 256], + data : [u8; 0x4000] +} + +namespace c64 { + extern var colorram @ 0xD800 : [u8; 0x400]; + + namespace color { + let BLACK = 0x00; + let WHITE = 0x01; + let RED = 0x02; + let CYAN = 0x03; + let PURPLE = 0x04; + let GREEN = 0x05; + let BLUE = 0x06; + let YELLOW = 0x07; + let ORANGE = 0x08; + let BROWN = 0x09; + let LIGHTRED = 0x0A; + let GRAY1 = 0x0B; + let GRAY2 = 0x0C; + let LIGHTGREEN = 0x0D; + let LIGHTBLUE = 0x0E; + let GRAY3 = 0x0F; + } + + namespace vic { + namespace sprite { + extern var pos @ 0xD000 : [CoordXY; 8]; + extern var coord @ 0xD000 : [u8; 16]; + extern var hi_x @ 0xD010 : u8; + extern var enable @ 0xD015 : u8; + extern var expand_y @ 0xD017 : u8; + extern var priority @ 0xD01B : u8; + extern var multicolor @ 0xD01C : u8; + extern var expand_x @ 0xD01D : u8; + extern var coll @ 0xD01E : u8; + extern var coll_bg @ 0xD01F : u8; + extern var mcolor @ 0xD025 : [u8; 2]; + extern var color @ 0xD027 : [u8; 8]; + } + extern var control1 @ 0xD011 : u8; + extern var rasterline @ 0xD012 : u8; + extern var lightpen @ 0xD013 : CoordXY; + extern var control2 @ 0xD016 : u8; + extern var mem @ 0xD018 : u8; + extern var irr @ 0xD019 : u8; + extern var imr @ 0xD01A : u8; + extern var bordercolor @ 0xD020 : u8; + extern var bgcolor @ 0xD021 : [u8; 4]; + } + + namespace sid { + extern writeonly v1 @ 0xd400 : [SIDVoice; 3]; + + extern writeonly flt_freq @ 0xd415 : u16;/* Filter frequency */ + extern writeonly flt_ctrl @ 0xd417 : u8; /* Filter control register */ + extern writeonly amp @ 0xd418 : u8; /* Amplitude */ + extern writeonly ad1 @ 0xd419 : u8; /* A/D converter 1 */ + extern writeonly ad2 @ 0xd41a : u8; /* A/D converter 2 */ + extern writeonly noise @ 0xd41b : u8; /* Noise generator */ + extern const read3 @ 0xd41c : u8; /* Value of voice 3 */ + } + + namespace cia1 { + // CIA1 Registers + extern writeonly port_a @ 0xDC00 : u8; + extern const port_b @ 0xDC01 : u8; + extern writeonly data_direction_a @ 0xDC02 : u8; + extern writeonly data_direction_b @ 0xDC03 : u8; + extern const timer_a_lo @ 0xDC04 : u8; + extern const timer_a_hi @ 0xDC05 : u8; + extern const timer_b_lo @ 0xDC06 : u8; + extern const timer_b_hi @ 0xDC07 : u8; + extern const sdr @ 0xDC0C : u8; + extern const icr @ 0xDC0D : u8; + extern const cra @ 0xDC0E : u8; + extern const crb @ 0xDC0F : u8; + } + + namespace cia2 { + // CIA2 Registers + extern writeonly port_a @ 0xDD00 : u8; + extern const port_b @ 0xDD01 : u8; + extern writeonly data_direction_a @ 0xDD02 : u8; + extern writeonly data_direction_b @ 0xDD03 : u8; + extern const timer_a_lo @ 0xDD04 : u8; + extern const timer_a_hi @ 0xDD05 : u8; + extern const timer_b_lo @ 0xDD06 : u8; + extern const timer_b_hi @ 0xDD07 : u8; + extern const sdr @ 0xDD0C : u8; + extern const icr @ 0xDD0D : u8; + extern const cra @ 0xDD0E : u8; + extern const crb @ 0xDD0F : u8; + } + + namespace kernal { + let ioinit = 0xFDA3 as func; + let rantam = 0xFD50 as func; + let restor = 0xFD15 as func; + let cint = 0xFF5B as func; + let scnkey = 0xEA87 as func; + let chrin = 0xF157 as func : u8 in a; + let chrout = 0xF1CA as func(char : u8 in a); + let screen = 0xE505 as func : u16 in xy; + let plot_save = 0xE50A as func(save : bool in carry) : u16 in xy; + let plot_restore = 0xE50A as func(x : u8 in x, y : u8 in y, save : bool in carry); + } +} + diff --git a/presets/c64/hello.wiz b/presets/c64/hello.wiz new file mode 100644 index 00000000..e86a3603 --- /dev/null +++ b/presets/c64/hello.wiz @@ -0,0 +1,181 @@ + + +import "c64.wiz"; + +bank zeropage @ 0x02 : [vardata; 254]; +bank stackpage @ 0x100 : [vardata; 256]; +bank textscrn @ 0x400 : [vardata; 0x400]; +bank ram @ 0x2000 : [vardata; 0x7800]; +bank prghdr @ 0x7ff : [prgdata; 0x2]; +bank prg @ 0x801 : [varinitdata; 0x7000]; + +in textscrn { + var scrn: [u8; 40*25]; + var _unused: [u8; 16]; + var spriteptr: [u8; 8]; +} + +extern var vicbank @ 0x0000 : VICBank; + +// PRG file header +in prghdr { + const prgstart : u16 = 0x801; +} + +// BASIC header +in prg { + namespace prgheader { + const nextline = &BASIC_END; + const linenum : u16 = 10; + const sysstmt = "\x9e 2062\0"; +BASIC_END: + const hdrend : u16 = 0; + } +PRG_START: + /* + c64.kernal.ioinit(); + c64.kernal.rantam(); + c64.kernal.restor(); + c64.kernal.cint(); + */ + c64.vic.bordercolor = a = c64.color.ORANGE; + c64.kernal.chrout('A'); + for x in 0..250 { +// scrn[x] = a = x; +// (&scrn[40*8])[x] = a = x; +// (0x600 as *u8)[x] = a = x; + (&scrn[40*12])[x] = a = message[x] + 0xc0; + } + for x in 0..255 { + a = message[x]; + break if zero; + a += 0xc0; + (&scrn[40*20])[x] = a; + } + upandaway(); + return; + + const message = "HELLO WORLD!\0"; + + const SPRITE : [u8; 3*21] = [ + /*{w:24,h:21,bpp:1,brev:1}*/ + 0x00,0x7F,0x00,0x01,0xFF,0xC0,0x03,0xFF,0xE0, + 0x03,0xE7,0xE0,0x07,0xD9,0xF0,0x07,0xDF,0xF0, + 0x07,0xD9,0xF0,0x03,0xE7,0xE0,0x03,0xFF,0xE0, + 0x03,0xFF,0xE0,0x02,0xFF,0xA0,0x01,0x7F,0x40, + 0x01,0x3E,0x40,0x00,0x9C,0x80,0x00,0x9C,0x80, + 0x00,0x49,0x00,0x00,0x49,0x00,0x00,0x3E,0x00, + 0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x1C,0x00 + ]; + + const yValues : [u8] = [ + 32, 35, 38, 41, 44, 47, 49, 52, + 54, 56, 58, 60, 61, 62, 63, 63, + 64, 63, 63, 62, 61, 60, 58, 56, + 54, 52, 49, 47, 44, 41, 38, 35, + 32, 28, 25, 22, 19, 16, 14, 11, + 9, 7, 5, 3, 2, 1, 0, 0, + 0, 0, 0, 1, 2, 3, 5, 7, + 9, 11, 14, 16, 19, 22, 25, 28 + ]; + + const pwr2 : [u8] = [ + 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 + ]; + + in zeropage { + var b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 : u8; + var w0 @ &b0, w2 @ &b2, w4 @ &b4, w6 @ &b6, w8 @ &b8, w10 @ &b10 : u16; + var ptr0 @ &b0, ptr2 @ &b2, ptr4 @ &b4, ptr6 @ &b6, ptr8 @ &b8, ptr10 @ &b10 : *u8; + } + + inline func rasterWait(line : u8 in a) { + while (c64.vic.rasterline < line) { } + } + + func upandaway() { + //unsigned char n, t; + //int rx, x; + //char sx, msb; + var xp : u16 in w0; + var rx : u16 in w2; + var msb : u8 in b4; + let sprdata = &vicbank.spritedata[13] as *u8; + + c64.vic.bgcolor[0] = a = 3; + nointerrupt = true; // clear interrupts to avoid glitching + + for y in 0..(sizeof(typeof(SPRITE)) - 1) { + sprdata[y] = a = SPRITE[y]; + //POKE(832 + n, sprite[n]); + } + c64.vic.sprite.enable = a = 255; + for x in 0..7 { + spriteptr[x] = a = 13; + y = a = x<<1; + c64.vic.sprite.coord[y] = a = 50; + y ++; + c64.vic.sprite.coord[y] = a = 50; + //POKE(2040 + t, 13); // Set sprite x data from 13th block for all sprites + } + do { + <:xp = a = 0; + >:xp = a = 0; + //while (xp < 550) { + while (true) { + <:xp = a = <:xp + 1; + >:xp = a = >:xp +# 0; + msb = a = 0; // MSB of X coordinates + // Wait until raster hits position 250 before drawing upper sprites + rasterWait(250); + // Set border color, which indicates the raster position + c64.vic.bordercolor = a = 1; + <:rx = a = <:xp; + >:rx = a = >:xp; + for x in 0..7 { + <:rx = a = <:rx - 24; + >:rx = a = >:rx -# 0; + //if (rx >= 0 && rx < 366) + if (true) { + // if (rx > 255) + a = >:rx; + if (!zero) { + // Set MSB of x coordinate for sprite if x position > 255 + a = msb; + a |= pwr2[x]; + msb = a; + } + y = a = x<<1; + c64.vic.sprite.coord[y] = a = <:rx; + // Y position is an indirect Sinus function of X, using array + // index for retrieving the Y value + y = a = <:rx & 63; + a = yValues[y] + 40; + push(a); + y = a = (x<<1) + 1; + a = pop(); + c64.vic.sprite.coord[y] = a; + } else { + c64.vic.sprite.pos[y].x = 0; + } + } + c64.vic.sprite.hi_x = a = msb; // Set MSB of x coordinate + // Wait until raster hits position 135 before drawing lower sprites + rasterWait(135); + c64.vic.bordercolor = a = 2; // Set border color + for x in 0..7 { + // Add 128 to current sprite Y position + y = a = (x<<1) + 1; + c64.vic.sprite.coord[y] = a = c64.vic.sprite.coord[y]+128; + } + cmp(a = >:xp, >:550); + if (zero) { + cmp(a = <:xp, <:550); + break if zero; + } + } + } while (true); + return; + } + +} diff --git a/presets/c64/upandaway.c b/presets/c64/upandaway.c index cf6a9b9d..967f3b92 100644 --- a/presets/c64/upandaway.c +++ b/presets/c64/upandaway.c @@ -1,7 +1,10 @@ + // ported from // https://odensskjegg.home.blog/2018/12/29/recreating-the-commodore-64-user-guide-code-samples-in-cc65-part-three-sprites/ -#include "common.h" +//#include "common.h" +#include +#include /*{w:24,h:21,bpp:1,brev:1}*/ const char sprite[3*21] = { @@ -15,7 +18,7 @@ const char sprite[3*21] = { }; // Pre-calculated sinus values -const char yValues[] = { +const char yValues[64] = { 32, 35, 38, 41, 44, 47, 49, 52, 54, 56, 58, 60, 61, 62, 63, 63, 64, 63, 63, 62, 61, 60, 58, 56, @@ -31,58 +34,66 @@ void rasterWait(unsigned char line) { while (VIC.rasterline < line) ; } +const char LUT[8] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 }; + int main (void) { unsigned char n, t; int rx, x; - char sx, msb; + unsigned char msb; - VIC.bgcolor0 = 3; + VIC.bgcolor0 = COLOR_CYAN; // set background color __asm__("SEI"); // clear interrupts to avoid glitching + // Set 13th sprite bitmap for (n = 0 ; n < sizeof(sprite) ; n++) { POKE(832 + n, sprite[n]); } + // enable all sprites VIC.spr_ena = 255; + // Set all sprite pointers to 13th sprite for (t = 0 ; t < 8 ; t++) { - POKE(2040 + t, 13); // Set sprite x data from 13th block for all sprites + POKE(2040 + t, 13); } - do { + // loop forever + while(1) { for (x = 0 ; x < 550; x++) { - msb = 0; // MSB of X coordinates + // MSB of each sprite's X coordinate (i.e. if X >= 256) + msb = 0; // Wait until raster hits position 250 before drawing upper sprites rasterWait(250); // Set border color, which indicates the raster position - VIC.bordercolor = 1; + VIC.bordercolor = COLOR_RED; rx = x; + // iterate over all 8 sprites for (t = 0 ; t < 8 ; t++) { + VIC.bordercolor = t; rx -= 24; if (rx >= 0 && rx < 366) { - // Usually I would calculate the sprite X coordinate using - // the expression sx = rx % 256, but bitwise operation is - // significant faster - sx = rx & 255; - if (rx > 255) { - // Set MSB of x coordinate for sprite if x position > 255 - msb |= 1 << t; + // Set MSB of x coordinate for sprite if x position > 255 + if (x >= 256) { + msb |= LUT[t]; // look up 1 << t } - VIC.spr_pos[t].x = sx; + VIC.spr_pos[t].x = x; // Y position is an indirect Sinus function of X, using array // index for retrieving the Y value - VIC.spr_pos[t].y = yValues[sx & 63] + 40; + VIC.spr_pos[t].y = yValues[x & 63] + 40; } else { VIC.spr_pos[t].x = 0; } } - VIC.spr_hi_x = msb; // Set MSB of x coordinate + // Set MSB of x coordinate + VIC.spr_hi_x = msb; // Wait until raster hits position 135 before drawing lower sprites + VIC.bordercolor = COLOR_BLUE; rasterWait(135); - VIC.bordercolor = 2; // Set border color + VIC.bordercolor = COLOR_RED; + // Add 128 to current sprite Y positions for (t = 0 ; t < 8 ; t++) { - // Add 128 to current sprite Y position VIC.spr_pos[t].y += 128; } } - } while (1); - return EXIT_SUCCESS; + } + return 0; } + diff --git a/scripts/serveit.py b/scripts/serveit.py index 91fa6b6c..180ac694 100755 --- a/scripts/serveit.py +++ b/scripts/serveit.py @@ -13,4 +13,4 @@ class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): if __name__ == '__main__': - http.server.test(HandlerClass=MyHTTPRequestHandler) + http.server.test(HandlerClass=MyHTTPRequestHandler, port=8000) diff --git a/src/platform/c64.ts b/src/platform/c64.ts index f28dabb9..0c4e5505 100644 --- a/src/platform/c64.ts +++ b/src/platform/c64.ts @@ -28,6 +28,7 @@ const C64_PRESETS = [ //{id:'sidtune.dasm', name:'Tiny SID Tune (ASM)'}, {id:'siddemo.c', name:'SID Player Demo'}, {id:'climber.c', name:'Climber Game'}, + {id:'hello.wiz', name:'Hello Wiz (Wiz)'}, ]; const C64_MEMORY_MAP = { main:[