1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-11-21 07:33:14 +00:00

c64: updates

This commit is contained in:
Steven Hugg 2024-10-20 21:04:21 -05:00
parent 41952d8655
commit e9fc216222
11 changed files with 212 additions and 23 deletions

View File

@ -92,9 +92,12 @@ typedef enum { false, true } bool; // boolean
// enable ROM and interrupts
#define DISABLE_HIMEM() \
POKE(1, PEEK(1) | 0b111); \
POKE(1, PEEK(1) | 0b110); \
asm("plp");
// are we on a PAL system?
#define IS_PAL() (PEEK(0x2a6) != 0)
///// FUNCTIONS /////
// wait until specific raster line

72
presets/c64/digisound.c Normal file
View File

@ -0,0 +1,72 @@
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <peekpoke.h>
#include <string.h>
#include <c64.h>
#include <cbm_petscii_charmap.h>
#include "sidmacros.h"
#include "common.h"
//#link "common.c"
void digi_setup(void) {
SID.v1.sr = 0xFF; // Voice 1 Sustain/Release
SID.v2.sr = 0xFF; // Voice 2 Sustain/Release
SID.v3.sr = 0xFF; // Voice 3 Sustain/Release
SID.v1.ctrl = 0x49; // Voice 1 Control Register
SID.v2.ctrl = 0x49; // Voice 2 Control Register
SID.v3.ctrl = 0x49; // Voice 3 Control Register
}
void cia2_wait() {
byte timer = CIA2.ta_lo;
while (CIA2.ta_lo < timer) ;
}
void digi_play(const char* snd, unsigned int len) {
unsigned int i; // loop counter
VIC.ctrl1 = 0; // disable video
asm("sei"); // disable interrupts
// setup CIA #2 timer
CIA2.cra = 0x00; // stop timer A
CIA2.ta_lo = IS_PAL() ? 123 : 128; // set lower timer value
CIA2.ta_hi = 0; // set upper timer value
CIA2.cra = 0x11; // start timer, continuous mode
// loop through all samples
for (i = 0; i < len; i++) {
// wait for timer to reset
cia2_wait();
// send upper 4-bit sample
SID.amp = snd[i] >> 4;
// wait for timer to reset
cia2_wait();
// send lower 4-bit sample
SID.amp = snd[i] & 15;
// make a video effect
VIC.bordercolor = i;
}
asm("cli"); // enable interrupts
VIC.ctrl1 = 0x1b; // enable video
CIA2.cra = 0x00; // stop timer A
VIC.bordercolor = COLOR_BLUE;
}
#ifdef __MAIN__
const char digisound[] = {
#embed "springchicken-b4.raw"
};
void main(void) {
clrscr();
digi_setup();
while (1) {
digi_play(digisound, 0xacf8L);
printf("\nPress ENTER to restart digi...\n");
getchar();
}
}
#endif

107
presets/c64/fld.c Normal file
View File

@ -0,0 +1,107 @@
#include "common.h"
//#link "common.c"
#include "rasterirq.h"
//#link "rasterirq.ca65"
#include "bcd.h"
//#link "bcd.c"
extern const unsigned char sinustable[0x100];
//#link "sinustable.c"
///// VARIABLES
byte frame = 0;
byte target_y;
byte fld_offsets[25];
///// FUNCTIONS
void line_crunch() {
// load scroll y
asm("lda %v", target_y);
asm("and #7");
asm("ora #$18");
asm("tax");
// get current raster line
asm("lda $d012");
// wait for next raster line
asm("@loop:");
asm("cmp $d012");
asm("beq @loop");
// set y scroll (ctrl1)
asm("stx $d011");
}
static byte target_line = 0;
static byte row;
static byte offset;
void display_list(void) {
VIC.bgcolor[0] = COLOR_CYAN;
VIC.bordercolor = COLOR_BLUE;
// set initial YSCROLL
SET_SCROLL_Y(fld_offsets[0]);
// set first target scanline
target_line = 48 + (fld_offsets[0] & 7);
// each row has its own FLD gap
for (row=1; row<25; row++) {
// get this row's gap distance
offset = fld_offsets[row];
// fire IRQ 3 lines before target
target_y = target_line - 3;
DLIST_NEXT(target_y);
// change Y scroll to avoid badline
line_crunch();
// set Y scroll for new badline
target_y = target_line + offset;
line_crunch();
// set target line for next IRQ
target_line += 8 + offset;
VIC.bgcolor[0] = row;
// exit loop if integer overflow
if (target_line < 48) break;
}
DLIST_RESTART(30);
}
void main() {
int i;
clrscr();
memset(COLOR_RAM, COLOR_BLUE, 1000);
for (i=0; i<40*25; i++)
POKE(0x400 + i, 205 + (rand() & 1));
for (i=40*25; i<1024; i++)
POKE(0x400 + i, i);
for (i=0; i<1024; i+=40)
POKE(0x400 + i, 122);
SET_VIC_BITMAP(0x1000);
DLIST_SETUP(display_list);
// game loop, repeat forever
while (1) {
// wait for end of frame
waitvsync();
// animate and set scroll_y
frame += 4;
// set FLD offsets via sinus table
for (i=0; i<25; i++) {
fld_offsets[i] = sinustable[frame + i*8] >> 5;
}
}
}

View File

@ -81,7 +81,6 @@ void main() {
SET_VIC_BITMAP(0x1000);
// setup rasterirq library for scoreboard split
DLIST_SETUP(display_list);
// game loop, repeat forever

View File

@ -20,11 +20,14 @@ static int sweep = 0;
#define BITMAP_START 0xe020
// recursive macros to quickly set bitmap memory
#define SID_SIGNAL(index) \
POKE(BITMAP_START + (index), SID.noise)
#define SID_SIGNAL_4(index) \
POKE(BITMAP_START + (index) + 0, SID.noise); \
POKE(BITMAP_START + (index) + 1, SID.noise); \
POKE(BITMAP_START + (index) + 2, SID.noise); \
POKE(BITMAP_START + (index) + 3, SID.noise);
SID_SIGNAL(index); \
SID_SIGNAL(index+1); \
SID_SIGNAL(index+2); \
SID_SIGNAL(index+3);
#define SID_SIGNAL_16(index) \
SID_SIGNAL_4(index); \

View File

@ -5,13 +5,9 @@ For more information, see "Making Arcade Games in C".
#include "common.h"
// BASL = text address of start of cursor line
byte** BASL = (byte**) 0xD1;
// get the character at a specfic x/y position
byte readcharxy(byte x, byte y) {
gotoxy(x,y); // set BASL
return (*BASL)[x]; // read character at (x,y)
return PEEK(SCRNADR(0x400, x, y));
}
// delay for 'count' frames
@ -27,11 +23,11 @@ typedef struct {
byte x; // x coordinate
byte y; // y coordinate
byte dir; // direction (0-3)
word score; // current score
byte score; // current score
char head_attr; // char to draw player
char tail_attr; // char to draw trail
int collided:1; // did we collide? (boolean)
int human:1; // is this player a human? (boolean)
bool collided; // did we collide?
bool human; // is this player a human?
} Player;
Player players[2]; // two player structs

File diff suppressed because one or more lines are too long

View File

@ -27,10 +27,10 @@ word score = 0; // current player score
// display list used by rasterirq.h
// draws scoreboard and sets scroll register
void display_list() {
// set x scroll register to scroll value
SET_SCROLL_X(scroll_x);
// set background color
VIC.bgcolor[0] = COLOR_CYAN;
// set x scroll register to scroll value
SET_SCROLL_X(scroll_x);
// next interrupt is two rows from bottom
DLIST_NEXT(250-16);

View File

@ -171,8 +171,6 @@ export enum WASIErrors {
NOTCAPABLE = 76,
}
export class WASIFileDescriptor {
fdindex: number = -1;
protected data: Uint8Array = new Uint8Array(16);
@ -622,9 +620,9 @@ export class WASIRunner {
if (dir == null) return WASIErrors.BADF;
if (dir.type !== FDType.DIRECTORY) return WASIErrors.NOTDIR;
const filename = this.peekUTF8(path_ptr, path_len);
const path = dir.name + '/' + filename;
const path = filename.startsWith('/') ? filename : dir.name + '/' + filename; // TODO?
const fd = this.fs.getFile(path);
console.log("path_filestat_get", dir+"", path, filestat_ptr, '->', fd+"");
console.log("path_filestat_get", dir+"", filename, path, filestat_ptr, '->', fd+"");
if (!fd) return WASIErrors.NOENT;
this.poke64(filestat_ptr, fd.fdindex); // dev
this.poke64(filestat_ptr + 8, 0); // ino
@ -637,6 +635,7 @@ export class WASIRunner {
}
path_readlink(dirfd: number, path_ptr: number, path_len: number, buf_ptr: number, buf_len: number, buf_used_ptr: number) {
const dir = this.fds[dirfd];
debug("path_readlink", dirfd, path_ptr, path_len, buf_ptr, buf_len, buf_used_ptr, dir+"");
if (dir == null) return WASIErrors.BADF;
if (dir.type !== FDType.DIRECTORY) return WASIErrors.NOTDIR;
const filename = this.peekUTF8(path_ptr, path_len);
@ -651,6 +650,9 @@ export class WASIRunner {
debug("path_readlink", path, '->', target);
return WASIErrors.SUCCESS;
}
path_readlinkat(dirfd: number, path_ptr: number, path_len: number, buf_ptr: number, buf_len: number, buf_used_ptr: number) {
return this.path_readlink(dirfd, path_ptr, path_len, buf_ptr, buf_len, buf_used_ptr);
}
path_unlink_file(dirfd: number, path_ptr: number, path_len: number) {
const dir = this.fds[dirfd];
if (dir == null) return WASIErrors.BADF;
@ -697,6 +699,10 @@ export class WASIRunner {
getEnv() {
return {
__syscall_unlinkat() { warning('TODO: unlink'); return WASIErrors.NOTSUP; },
__syscall_faccessat() { warning("TODO: faccessat"); return WASIErrors.NOTSUP; },
__syscall_readlinkat: this.path_readlinkat.bind(this),
__syscall_getcwd() { warning("TODO: getcwd"); return WASIErrors.NOTSUP; },
__syscall_rmdir() { warning("TODO: rmdir"); return WASIErrors.NOTSUP; },
}
}
}

View File

@ -6,8 +6,8 @@ import { BaseMAME6502Platform } from "../common/mameplatform";
const C64_PRESETS : Preset[] = [
{id:'helloc.c', name:'Hello World', category:'C'},
{id:'siegegame.c', name:'Siege Game'},
{id:'screen_ram.c', name:'Screen RAM'},
{id:'siegegame.c', name:'Siege Game'},
{id:'joymove.c', name:'Sprite Movement'},
{id:'sprite_collision.c', name:'Sprite Collision'},
{id:'scroll1.c', name:'Scrolling (Single Buffer)'},
@ -29,10 +29,12 @@ const C64_PRESETS : Preset[] = [
{id:'musicplayer.c', name:'Music Player'},
//{id:'sidtune.dasm', name:'Tiny SID Tune (ASM)'},
{id:'siddemo.c', name:'SID Player Demo'},
{id:'digisound.c', name:'Digi Sound Player'},
{id:'climber.c', name:'Climber Game'},
{id:'test_border_sprites.c', name:'Sprites in the Borders'},
{id:'sprite_stretch.c', name:'Sprite Stretching'},
{id:'linecrunch.c', name:'Linecrunch'},
{id:'fld.c', name:'Flexible Line Distance'},
{id:'plasma.c', name:'Plasma Demo'},
{id:'23matches.c', name:'23 Matches'},
{id:'tgidemo.c', name:'TGI Graphics Demo'},

View File

@ -88,10 +88,10 @@ describe('test WASI oscar64', function () {
let shim = await loadOscar64();
const zipdata = fs.readFileSync(`./src/worker/fs/oscar64-fs.zip`);
shim.fs = await unzipWASIFilesystem(zipdata, "/root/");
shim.addPreopenDirectory("/root");
shim.fs.putSymbolicLink("/proc/self/exe", "/root/bin/oscar64");
shim.fs.putFile("/root/main.c", "#include <stdio.h>\nint main() { return 0; }");
shim.addPreopenDirectory("");
shim.setArgs(["oscar64", '-v', '-o=foo.prg', '/root/main.c']);
shim.setArgs(["oscar64", '-v', '-o=foo.prg', 'main.c']);
let errno = shim.run();
const stdout = shim.fds[1].getBytesAsString();
console.log(stdout);