diff --git a/index.html b/index.html index 6a95a8c0..52c42c1b 100644 --- a/index.html +++ b/index.html @@ -208,6 +208,8 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
  • Atari 2600 (MAME)
  • ColecoVision (MAME)
  • NES (MAME)
  • +
    +
  • Williams (6809)
  • diff --git a/presets/williams/gfxtest.c b/presets/williams/gfxtest.c new file mode 100644 index 00000000..fb9f4614 --- /dev/null +++ b/presets/williams/gfxtest.c @@ -0,0 +1,83 @@ + +#include "williams.h" +//#link "williams.c" + +// 256x304x4bpp video memory + +#define LOCHAR 0x21 +#define HICHAR 0x5e + +const byte font8x8[HICHAR-LOCHAR+1][8] = { +{ 0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x00 }, { 0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00 }, { 0x66,0x66,0xff,0x66,0xff,0x66,0x66,0x00 }, { 0x18,0x3e,0x60,0x3c,0x06,0x7c,0x18,0x00 }, { 0x62,0x66,0x0c,0x18,0x30,0x66,0x46,0x00 }, { 0x3c,0x66,0x3c,0x38,0x67,0x66,0x3f,0x00 }, { 0x06,0x0c,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x18,0x30,0x30,0x30,0x18,0x0c,0x00 }, { 0x30,0x18,0x0c,0x0c,0x0c,0x18,0x30,0x00 }, { 0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00 }, { 0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30 }, { 0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00 }, { 0x00,0x03,0x06,0x0c,0x18,0x30,0x60,0x00 }, { 0x3c,0x66,0x6e,0x76,0x66,0x66,0x3c,0x00 }, { 0x18,0x18,0x38,0x18,0x18,0x18,0x7e,0x00 }, { 0x3c,0x66,0x06,0x0c,0x30,0x60,0x7e,0x00 }, { 0x3c,0x66,0x06,0x1c,0x06,0x66,0x3c,0x00 }, { 0x06,0x0e,0x1e,0x66,0x7f,0x06,0x06,0x00 }, { 0x7e,0x60,0x7c,0x06,0x06,0x66,0x3c,0x00 }, { 0x3c,0x66,0x60,0x7c,0x66,0x66,0x3c,0x00 }, { 0x7e,0x66,0x0c,0x18,0x18,0x18,0x18,0x00 }, { 0x3c,0x66,0x66,0x3c,0x66,0x66,0x3c,0x00 }, { 0x3c,0x66,0x66,0x3e,0x06,0x66,0x3c,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30 }, { 0x0e,0x18,0x30,0x60,0x30,0x18,0x0e,0x00 }, { 0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00 }, { 0x70,0x18,0x0c,0x06,0x0c,0x18,0x70,0x00 }, { 0x3c,0x66,0x06,0x0c,0x18,0x00,0x18,0x00 }, { 0x3c,0x66,0x6e,0x6e,0x60,0x62,0x3c,0x00 }, { 0x18,0x3c,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x7c,0x66,0x66,0x7c,0x66,0x66,0x7c,0x00 }, { 0x3c,0x66,0x60,0x60,0x60,0x66,0x3c,0x00 }, { 0x78,0x6c,0x66,0x66,0x66,0x6c,0x78,0x00 }, { 0x7e,0x60,0x60,0x78,0x60,0x60,0x7e,0x00 }, { 0x7e,0x60,0x60,0x78,0x60,0x60,0x60,0x00 }, { 0x3c,0x66,0x60,0x6e,0x66,0x66,0x3c,0x00 }, { 0x66,0x66,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0x00 }, { 0x1e,0x0c,0x0c,0x0c,0x0c,0x6c,0x38,0x00 }, { 0x66,0x6c,0x78,0x70,0x78,0x6c,0x66,0x00 }, { 0x60,0x60,0x60,0x60,0x60,0x60,0x7e,0x00 }, { 0x63,0x77,0x7f,0x6b,0x63,0x63,0x63,0x00 }, { 0x66,0x76,0x7e,0x7e,0x6e,0x66,0x66,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x66,0x3c,0x00 }, { 0x7c,0x66,0x66,0x7c,0x60,0x60,0x60,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x3c,0x0e,0x00 }, { 0x7c,0x66,0x66,0x7c,0x78,0x6c,0x66,0x00 }, { 0x3c,0x66,0x60,0x3c,0x06,0x66,0x3c,0x00 }, { 0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x00 }, { 0x66,0x66,0x66,0x66,0x66,0x66,0x3c,0x00 }, { 0x66,0x66,0x66,0x66,0x66,0x3c,0x18,0x00 }, { 0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00 }, { 0x66,0x66,0x3c,0x18,0x3c,0x66,0x66,0x00 }, { 0x66,0x66,0x66,0x3c,0x18,0x18,0x18,0x00 }, { 0x7e,0x06,0x0c,0x18,0x30,0x60,0x7e,0x00 }, { 0x3c,0x30,0x30,0x30,0x30,0x30,0x3c,0x00 }, { 0x00,0x60,0x30,0x18,0x0c,0x06,0x03,0x00 }, { 0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00 }, { 0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18 } +}; + +const byte sprite1[] = { +8,16, +0x00,0x09,0x99,0x00,0x00,0x99,0x90,0x00, +0x00,0x94,0x94,0x90,0x09,0x49,0x49,0x00, +0x04,0x49,0x49,0x90,0x09,0x94,0x94,0x90, +0x94,0x99,0x94,0x90,0x09,0x49,0x99,0x49, +0x99,0x99,0x49,0x93,0x39,0x94,0x99,0x99, +0x04,0x49,0x99,0x94,0x49,0x99,0x94,0x90, +0x00,0x94,0x94,0x43,0x34,0x49,0x49,0x00, +0x00,0x09,0x43,0x94,0x49,0x34,0x90,0x00, +0x00,0x90,0x00,0x39,0x93,0x00,0x09,0x00, +0x00,0x09,0x83,0x33,0x33,0x33,0x90,0x00, +0x00,0x09,0x32,0x23,0x32,0x23,0x90,0x00, +0x00,0x03,0x03,0x23,0x82,0x30,0x30,0x00, +0x03,0x30,0x00,0x33,0x33,0x00,0x03,0x30, +0x00,0x30,0x03,0x00,0x00,0x30,0x03,0x00, +0x00,0x00,0x00,0x30,0x03,0x00,0x00,0x00, +0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00, +}; + +void draw_char(char ch, byte x, byte y, byte color) { + byte data[8][4]; + const byte* src = &font8x8[ch-LOCHAR][0]; + int i,j,pixels; + if (ch < LOCHAR || ch > HICHAR) return; + for (i=0; i<8; i++) { + byte b = *src++; + for (j=0; j<4; j++) { + pixels = 0; + if (b & 0x80) pixels |= color & 0xf0; + if (b & 0x40) pixels |= color & 0x0f; + data[i][j] = (byte)pixels; + b <<= 2; + } + } + blit_copy(x, y, 4, 8, (byte*)data); +} + +void draw_string(const char* str, byte x, byte y, byte color) { + char ch; + do { + ch = *str++; + draw_char(ch, x, y, color); + x += 4; + } while (ch); +} + +int main(void) { + byte i; + rom_select = 1; + blit_solid(0, 0, 152, 255, 0x00); + for (i=0; i<16; i++) + palette[i] = (byte)(i*7); + for (i=0; i<152; i++) { + vidmem[0][i] = 16; + vidmem[i][2] = 32; + blit_pixel(i, i, 0x77); + blit_pixel(i+1, i, 0x33); + } + while (1) { + watchdog0x39 = 0x39; + draw_sprite(sprite1, 35, 20); + draw_sprite_solid(sprite1, 55, 20, 0x24); + blit_solid(75, 20, 40, 20, 0x35); + draw_string("HELLO WORLD", 20, 5, 0x88); + } + return 0; +} + + diff --git a/presets/williams/williams.c b/presets/williams/williams.c new file mode 100644 index 00000000..1bad3294 --- /dev/null +++ b/presets/williams/williams.c @@ -0,0 +1,75 @@ + +#include "williams.h" + +// x1: 0-151 +// y1: 0-255 +void blit_solid(byte x1, byte y1, byte w, byte h, byte color) { + blitter.width = w^4; + blitter.height = h^4; + blitter.dstart = ((word)x1<<8)+y1; // swapped + blitter.solid = color; + blitter.flags = DSTSCREEN|SOLID; +} + +void blit_copy(byte x1, byte y1, byte w, byte h, const byte* data) { + blitter.width = w^4; + blitter.height = h^4; + blitter.sstart = (word)data; + blitter.dstart = ((word)x1<<8)+y1; // swapped + blitter.solid = 0; + blitter.flags = DSTSCREEN|FGONLY; +} + +void blit_copy_solid(byte x1, byte y1, byte w, byte h, const byte* data, byte solid) { + blitter.width = w^4; + blitter.height = h^4; + blitter.sstart = (word)data; + blitter.dstart = ((word)x1<<8)+y1; // swapped + blitter.solid = solid; + blitter.flags = DSTSCREEN|FGONLY|SOLID; +} + +void draw_sprite(const byte* data, byte x, byte y) { + blitter.width = data[0]^4; + blitter.height = data[1]^4; + blitter.sstart = (word)(data+2); + blitter.dstart = ((word)x<<8)+y; // swapped + blitter.solid = 0; + blitter.flags = DSTSCREEN|FGONLY; +} + +void blit_pixel(word xx, byte y, byte color) { + blitter.width = 1^4; + blitter.height = 1^4; + blitter.dstart = (((xx>>1)&0xff)<<8)+y; // swapped + blitter.solid = color; + blitter.flags = (xx&1) ? SOLID|ODDONLY : SOLID|EVENONLY; +} + +void draw_sprite_solid(const byte* data, byte x, byte y, byte color) { + blitter.width = data[0]^4; + blitter.height = data[1]^4; + blitter.sstart = (word)(data+2); + blitter.dstart = ((word)x<<8)+y; // swapped + blitter.solid = color; + blitter.flags = DSTSCREEN|FGONLY|SOLID; +} + +void erase_sprite_rect(const byte* data, byte x, byte y) { + blitter.width = data[0]^4; + blitter.height = data[1]^4; + blitter.dstart = ((word)x<<8)+y; // swapped + blitter.solid = 0; + blitter.flags = DSTSCREEN|SOLID; +} + +void draw_sprite_strided(const byte* data, byte x, byte y, byte stride) { + const byte* src = data+2; + byte height = data[1]^4; + byte width = data[0]^4; + while (height--) { + blit_copy(x, y, width, 1, src); + y += stride; + src += width; + } +} diff --git a/presets/williams/williams.h b/presets/williams/williams.h new file mode 100644 index 00000000..36ec034c --- /dev/null +++ b/presets/williams/williams.h @@ -0,0 +1,100 @@ + +#ifndef _WILLIAMS_H +#define _WILLIAMS_H + +typedef unsigned char byte; +typedef unsigned short word; + +byte* palette = 0xc000; +byte* nvram = 0xcc00; + +#define input0 (*(byte*)0xc804) +#define input1 (*(byte*)0xc806) +#define input2 (*(byte*)0xc80c) +#define sound_pia (*(byte*)0xc80c) +#define rom_select *((byte*)0xc900) +#define video_counter *((byte*)0xcb00) +#define watchdog0x39 *((byte*)0xcbff) + +// switch flags + +#define UP1 (input0 & 0x1) +#define DOWN1 (input0 & 0x2) +#define LEFT1 (input0 & 0x4) +#define RIGHT1 (input0 & 0x8) +#define START1 (input0 & 0x10) +#define START2 (input0 & 0x20) +#define UP2 (input0 & 0x40) +#define DOWN2 (input0 & 0x80) +#define LEFT2 (input1 & 0x1) +#define RIGHT2 (input1 & 0x2) +#define AUTOUP (input2 & 0x1) +#define ADVANCE (input2 & 0x2) +#define COIN2 (input2 & 0x4) +#define HIGHSCORERESET (input2 & 0x8) +#define COIN1 (input2 & 0x10) +#define COIN3 (input2 & 0x20) +#define TILTSWITCH (input2 & 0x40) +#define SOUNDACK (input2 & 0x80) + +// blitter flags +#define SRCSCREEN 0x1 +#define DSTSCREEN 0x2 +#define ESYNC 0x4 +#define FGONLY 0x8 +#define SOLID 0x10 +#define RSHIFT 0x20 +#define EVENONLY 0x40 +#define ODDONLY 0x80 + +struct { + byte flags; + byte solid; + word sstart; + word dstart; + byte width; + byte height; +} *_blitter = 0xca00; + +#define blitter (*_blitter) + +struct { + byte mem[152][256]; +} *_vid = 0x0; + +#define vidmem (_vid->mem) + +#define BLIT_OP(_x,_y,_w,_h,_src,_color,_flags) do {\ + blitter.width = (_w)^4; \ + blitter.height = (_h)^4; \ + blitter.sstart = (word)(_src); \ + blitter.dstart = ((word)(_x)<<8)+(_y); \ + blitter.solid = (_color); \ + blitter.flags = (_flags); \ + } while (0) + +#define BLIT_SOLID(x, y, w, h, color) \ + BLIT_OP(x, y, w, h, 0, color, DSTSCREEN|SOLID) + + +// x1: 0-151 +// y1: 0-255 +void blit_solid(byte x1, byte y1, byte w, byte h, byte color); + +void blit_copy(byte x1, byte y1, byte w, byte h, const byte* data); + +void blit_copy_solid(byte x1, byte y1, byte w, byte h, const byte* data, byte solid); + +void draw_sprite(const byte* data, byte x, byte y); + +void draw_sprite_solid(const byte* data, byte x, byte y, byte color); + +void erase_sprite_rect(const byte* data, byte x, byte y); + +void draw_sprite_strided(const byte* data, byte x, byte y, byte stride); + +// x1: 0-303 +// y1: 0-255 +void blit_pixel(word xx, byte y, byte color); + +#endif diff --git a/src/platform/williams.ts b/src/platform/williams.ts index f678bc72..7c2275ca 100644 --- a/src/platform/williams.ts +++ b/src/platform/williams.ts @@ -98,7 +98,7 @@ var WilliamsPlatform = function(mainElement, proto, isDefender) { var iowrite_defender = newAddressDecoder([ [0x0, 0xf, 0xf, setPalette], - [0x3fc, 0x3ff, 0, function(a, v) { if (v == 0x38) watchdog_counter = INITIAL_WATCHDOG; }], + [0x3fc, 0x3ff, 0, function(a, v) { if (v == 0x38) watchdog_counter = INITIAL_WATCHDOG; watchdog_enabled=true; }], [0x400, 0x5ff, 0x1ff, function(a, v) { nvram.mem[a] = v; }], [0xc02, 0xc02, 0x1, function(a, v) { if (worker) worker.postMessage({ command: v & 0x3f }); }], [0xc00, 0xc07, 0x7, function(a, v) { pia6821[a] = v; }], @@ -145,7 +145,7 @@ var WilliamsPlatform = function(mainElement, proto, isDefender) { //[0x80c, 0x80f, 0x3, function(a,v) { console.log('iowrite',a+4); }], // TODO: sound [0x900, 0x9ff, 0, function(a, v) { banksel = v & 0x1; }], [0xa00, 0xa07, 0x7, setBlitter], - [0xbff, 0xbff, 0, function(a, v) { if (v == 0x39) watchdog_counter = INITIAL_WATCHDOG; }], + [0xbff, 0xbff, 0, function(a, v) { if (v == 0x39) { watchdog_counter = INITIAL_WATCHDOG; watchdog_enabled=true; } }], [0xc00, 0xfff, 0x3ff, function(a, v) { nvram.mem[a] = v; }], //[0x0, 0xfff, 0, function(a,v) { console.log('iowrite',hex(a),hex(v)); }], ]); @@ -418,6 +418,7 @@ var WilliamsPlatform = function(mainElement, proto, isDefender) { this.reset = function() { cpu.reset(); watchdog_counter = INITIAL_WATCHDOG; + watchdog_enabled = false; banksel = 1; } this.scaleCPUFrequency = function(scale) { diff --git a/src/worker/lib/williams/assert.h b/src/worker/lib/williams/assert.h new file mode 100644 index 00000000..45d9fba0 --- /dev/null +++ b/src/worker/lib/williams/assert.h @@ -0,0 +1,20 @@ +/* assert.h - Assert macro for CMOC + + By Pierre Sarrazin . + This file is in the public domain. +*/ + +#ifndef _ASSERT_H +#define _ASSERT_H + +#include "cmoc.h" + +#ifdef NDEBUG +#define assert(cond) +#else +#define assert(cond) do { if (!(cond)) { \ + printf("***ASSERT FAILED: %s:%u: %s\n", __FILE__, __LINE__, #cond); \ + for (;;); } } while (0) +#endif + +#endif /* _ASSERT_H */ diff --git a/src/worker/lib/williams/cmoc.h b/src/worker/lib/williams/cmoc.h new file mode 100644 index 00000000..090f69ef --- /dev/null +++ b/src/worker/lib/williams/cmoc.h @@ -0,0 +1,345 @@ +// cmoc.h - CMOC's standard library functions. +// +// By Pierre Sarrazin . +// This file is in the public domain. +// +// Functions not documented here should be assumed to behave as in C. + +#ifndef _H_CMOC +#define _H_CMOC + +#ifndef __GNUC__ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + + +#ifndef _CMOC_CONST_ +#define _CMOC_CONST_ const +#endif + + +// Gives the offset in bytes of the specified 'member' in the struct +// or union named 'Type'. +// +#define offsetof(Type, member) ((unsigned) &((Type *) 0)->member) + +typedef unsigned size_t; + + +#ifndef VECTREX +// Supports %u, %d, %x, %X, %p, %s, %c and %%. Specifying a field width is +// allowed, but a left justification is only supported for strings, i.e., +// %-15s will work, but %-6u will not. Zero padding for a number is supported +// (e.g., %04x). +// +int printf(_CMOC_CONST_ char *format, ...); +#endif + + +// Writes to 'dest'. Not thread-safe. Does not check for buffer overflow. +int sprintf(char *dest, _CMOC_CONST_ char *format, ...); + + +#ifndef VECTREX +// Writes the first 'n' characters designated by 's', regardless of any +// null characters encountered among them. +// +void putstr(_CMOC_CONST_ char *s, size_t n); + +void putchar(int c); +#endif + +int strcmp(_CMOC_CONST_ char *s1, _CMOC_CONST_ char *s2); +int stricmp(_CMOC_CONST_ char *s1, _CMOC_CONST_ char *s2); +int memcmp(_CMOC_CONST_ void *s1, _CMOC_CONST_ void *s2, size_t n); +int memicmp(_CMOC_CONST_ void *s1, _CMOC_CONST_ void *s2, size_t n); +void *memcpy(void *dest, _CMOC_CONST_ void *src, size_t n); +void *memset(void *s, int c, size_t n); +size_t strlen(_CMOC_CONST_ char *s); +char *strcpy(char *dest, _CMOC_CONST_ char *src); +char *strcat(char *dest, _CMOC_CONST_ char *src); +char *strncpy(char *dest, _CMOC_CONST_ char *src, size_t n); +char *strchr(_CMOC_CONST_ char *s, int c); +char *strstr(const char *haystack, const char *needle); +char *strlwr(char *s); +char *strupr(char *s); + + +// Converts an ASCII unsigned decimal string into an unsigned word. +// +unsigned atoui(_CMOC_CONST_ char *s); + + +// Converts an ASCII signed decimal string into a signed word. +// +int atoi(_CMOC_CONST_ char *s); + + +// Converts an integer to a NUL-terminated ASCII signed decimal string. +// Returns 'str'. +// The caller must be careful to pass an array of sufficient size, +// including room for the terminating '\0'. +// +char *itoa10(int value, char *str); + + +// Converts an integer to a NUL-terminated ASCII signed decimal string. +// N.B.: 'base' must be 10. No other base is supported by this implementation. +// Returns 'str'. +// The caller must be careful to pass an array of sufficient size, +// including room for the terminating '\0'. +// +#define itoa(value, str, base) (itoa10((value), (str))) + + +// Like itoa10(), but 'value' can be in the range 32768..65535. +// +char *utoa10(unsigned value, char *str); + + +// Like itoa(), but 'value' can be in the range 32768..65535. +// N.B.: 'base' must be 10. No other base is supported by this implementation. +// +#define utoa(value, str, base) (utoa10((value), (str))) + + +// Like itoa10(), but 'value' can be 32 bits. +// +char *ltoa10(long value, char *str); + + +// Like itoa(), but 'value' can be 32 bits. +// N.B.: 'base' must be 10. No other base is supported by this implementation. +// +#define ltoa(value, str, base) (ltoa10((value), (str))) + + +// Like utoa10(), but 'value' can be 32 bits. +// +char *ultoa10(unsigned long value, char *str); + + +// Like utoa(), but 'value' can be 32 bits. +// N.B.: 'base' must be 10. No other base is supported by this implementation. +// +#define ultoa(value, str, base) (ultoa10((value), (str))) + + +// Double-word to ASCII. +// Converts the unsigned 32-bit integer formed by hi * 65536 + lo into +// an ASCII decimal representation that gets written to 'out'. +// 'out' must point to at least 11 bytes. The string written there will +// be terminated by a null character. +// Returns the address of the first non-'0' character in the 11-byte +// buffer, or to "0" if hi and lo are both zero. +// Example: char s[11]; char *p = dwtoa(s, 1, 2); +// s will get the string " +// NOTE: This operation can also be done with the 'long' type and by +// calling sprintf() with the "%lu" or "%ld" placeholders. +// +char *dwtoa(char *out, unsigned hi, unsigned lo); + + +// Returns the integer part of the square root of n. +// +unsigned char sqrt16(unsigned n); + + +// Returns the quotient and remainder of a 16-bit unsigned division +// in a single operation. +// +void divmod16(unsigned dividend, unsigned divisor, + unsigned *quotient, unsigned *remainder); + + +// Returns the quotient and remainder of an 8-bit unsigned division +// in a single operation. +// +void divmod8(unsigned char dividend, unsigned char divisor, + unsigned char *quotient, unsigned char *remainder); + + +// Divides an unsigned 32-bit integer by an unsigned 8-bit integer. +// The two words designated by 'dividendInQuotientOut' are the input dividend. +// The 32-bit quotient is left in those two words. +// +void divdwb(unsigned dividendInQuotientOut[2], unsigned char divisor); + + +// Previous name of divdwb(). +// +#define div328 divdwb + + +// Divides an unsigned 32-bit integer by an unsigned 16-bit integer. +// The two words designated by 'dividendInQuotientOut' are the input dividend. +// The 32-bit quotient is left in those two words. +// +void divdww(unsigned dividendInQuotientOut[2], unsigned divisor); + + +// Multiply a word by a byte. +// Stores the high word of the product in *hi and returns the low word. +// +unsigned mulwb(unsigned char *hi, unsigned wordFactor, unsigned char byteFactor); + + +// Similar to mulwb(). +unsigned mulww(unsigned *hi, unsigned factor0, unsigned factor1); + + +// Stores 0 in twoWords[0], twoWords[1]. +// +void zerodw(unsigned *twoWords); + + +// Adds the 16-bit integer 'term' to the 32-bit integer designated by +// twoWords[0] and twoWords[1]. +// +void adddww(unsigned *twoWords, unsigned term); + + +// Subtracts the 16-bit integer 'term' from the 32-bit integer designated by +// twoWords[0] and twoWords[1]. +// +void subdww(unsigned *twoWords, unsigned term); + + +// Returns 0 if the 32-bit unsigned word composed of left[0] and left[1] +// (where left[0] is the high word) is equal to 'right'; +// returns +1 if left > right; -1 if left < right. +// +char cmpdww(unsigned left[2], unsigned right); + + +#ifdef _COCO_BASIC_ + +// Converts an ASCII decimal floating point number to a float. +// The string is allowed to contain a suffix (e.g., "1.2E6XYZ"); +// endptr: Receives the address where the parsing stopped. +// Caution: Passing a string whose value does not fit in a float +// may have undefined behavior. +// An 'E' used in exponential notation must be in upper-case. +// +float strtof(_CMOC_CONST_ char *nptr, char **endptr); + + +// Like strtof(), but does not return the end pointer. +// +float atoff(_CMOC_CONST_ char *nptr); + + +// Writes an ASCII decimal representation of 'f' in the buffer +// at 'out' which must contain at least 38 bytes. +// Returns 'out' upon success, or null upon failure. +// +char *ftoa(char out[38], float f); + +#endif /* _COCO_BASIC_ */ + + +// CAUTION: base is ignored, only base 10 is supported. +// +unsigned long strtoul(_CMOC_CONST_ char *nptr, char **endptr, int base); + +unsigned long atoul(_CMOC_CONST_ char *nptr); + +// CAUTION: base is ignored, only base 10 is supported. +// +long strtol(_CMOC_CONST_ char *nptr, char **endptr, int base); + +long atol(_CMOC_CONST_ char *nptr); + +int tolower(int c); +int toupper(int c); +void exit(int status); + +#define RAND_MAX 0x7FFF +void srand(unsigned seed); +int rand(); + +// See the CMOC manual. +void *sbrk(size_t increment); +size_t sbrkmax(); +void set_null_ptr_handler(void (*newHandler)(void *)); +void set_stack_overflow_handler(void (*newHandler)(void *, void *)); + + +// Function pointer type used by setConsoleOutHook(). +// +typedef void (*ConsoleOutHook)(); + + +// Redirect printf() et al. to the function at 'routine', which will +// receive each character to be printed in register A. +// +// That routine MUST preserve registers B, X, Y and U. +// +// If this function is never called, printf() et al. write to the +// system's standard character output routine. +// +// Returns the original output routine address. +// To uninstall the new routine, call this function again with +// the original routine address. +// +ConsoleOutHook setConsoleOutHook(ConsoleOutHook routine); + + +#ifndef VECTREX + +// Blocks the execution for the specified time in 60ths of a second. +// +void delay(size_t sixtiethsOfASecond); + + +// Reads a line from standard input, converts an expected 16-bit decimal +// number and returns it. Not thread-safe. +// +unsigned readword(); + + +// Reads a line from standard input and returns it. +// Not thread-safe. +// Returns a null pointer if the operation failed (e.g., end of file +// encountered). +// +char *readline(); + +#endif /* ndef VECTREX */ + + +// Sorts an array that starts at 'base', that has 'nmemb' elements, whose +// elements are 'size' bytes each. +// compar: Pointer to a function that receives pointers to two array elements +// and that returns -1, 0 or +1 depending on whether the first element +// comes before, is equal to, or comes after the second element. +// This function is recursive and will thus use stack space. +// +void qsort(void *base, size_t nmemb, size_t size, int (*compar)(_CMOC_CONST_ void *, _CMOC_CONST_ void *)); + + +// Searches for the value pointed to by 'key' in the array starting at 'base', +// that has 'nmemb' elements, whose elements are 'size' bytes each. +// compar: Pointer to a function that receives pointers to the targeted key and +// to an array element. It must return -1, 0 or +1 depending on whether +// the targeted key comes before, is equal to, or comes after the second element. +// Returns a pointer to the element of the array that matches the targeted key, +// or NULL if none is found. +// The time taken by this function is proportional to the logarithm of the array size. +// This function is recursive and will thus use stack space. +// +void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, + int (*compar)(_CMOC_CONST_ void *key, _CMOC_CONST_ void *element)); + + +#else + +#include +#include +#include + +#endif /* __GNUC__ */ + +#endif /* _H_CMOC */ diff --git a/src/worker/lib/williams/stdarg.h b/src/worker/lib/williams/stdarg.h new file mode 100644 index 00000000..e3d0b345 --- /dev/null +++ b/src/worker/lib/williams/stdarg.h @@ -0,0 +1,22 @@ +/* stdarg.h - Support for variable argument functions + + By Pierre Sarrazin . + This file is in the public domain. +*/ + +#ifndef _stdarg_h_ +#define _stdarg_h_ + + +typedef char *va_list; + + +char *__va_arg(va_list *app, unsigned int sizeInBytes); + + +#define va_start(ap, lastFixed) do { (ap) = (char *) &(lastFixed) + sizeof(lastFixed); } while (0) +#define va_arg(ap, type) (* (type *) __va_arg(&(ap), sizeof(type))) +#define va_end(ap) do {} while (0) + + +#endif /* _stdarg_h_ */ diff --git a/src/worker/lib/williams/stdlib.h b/src/worker/lib/williams/stdlib.h new file mode 100644 index 00000000..3da92a0e --- /dev/null +++ b/src/worker/lib/williams/stdlib.h @@ -0,0 +1,13 @@ +#ifndef __vectrex_stdlib_h__ +#define __vectrex_stdlib_h__ + +/** + * Most stdlib functions are supported on the Vectrex, except those that imply having a keyboard and console: + * printf, putsr, putchar, readword, readline. + * Also delay is not implemented as it does not seem to make much sense to have a delay function on the Vectrex. + */ + +//#include "vectrex.h" +#include "cmoc.h" + +#endif // __vectrex_stdlib_h__ diff --git a/src/worker/tools/m6809.ts b/src/worker/tools/m6809.ts index 538fa8c4..2ea6ddbc 100644 --- a/src/worker/tools/m6809.ts +++ b/src/worker/tools/m6809.ts @@ -116,6 +116,9 @@ export function compileCMOC(step: BuildStep): BuildStepResult { if (errors.length) return { errors: errors }; var asmout = FS.readFile(destpath, { encoding: 'utf8' }); + if (step.params.set_stack_end) + asmout = asmout.replace('stack space in bytes', `\n lds #${step.params.set_stack_end}\n`) + console.log(asmout); putWorkFile(destpath, asmout); } return { @@ -240,6 +243,8 @@ export function linkLWLINK(step: BuildStep): BuildStepResult { // * Line //threed.c:117: init of variable e var srclines = parseSourceLines(lstout, /Line .+?:(\d+)/i, /^([0-9A-F]{4})/i); putWorkFile(fn, lstout); + // strip out left margin + lstout = lstout.split('\n').map(l => l.substring(0,15) + l.substring(56)).join('\n') // TODO: you have to get rid of all source lines to get asm listing listings[fn] = { asmlines: srclines.length ? asmlines : null, diff --git a/src/worker/workermain.ts b/src/worker/workermain.ts index 3c2d07ac..fc5347f4 100644 --- a/src/worker/workermain.ts +++ b/src/worker/workermain.ts @@ -127,9 +127,11 @@ var PLATFORM_PARAMS = { data_start: 0x9800, data_size: 0x2800, stack_end: 0xc000, + set_stack_end: 0xc000, extra_link_files: ['williams.scr', 'libcmoc-crt-vec.a', 'libcmoc-std-vec.a'], extra_link_args: ['-swilliams.scr', '-lcmoc-crt-vec', '-lcmoc-std-vec'], - extra_compile_files: ['assert.h','cmoc.h','stdarg.h','vectrex.h','stdlib.h','bios.h'], + extra_compile_files: ['assert.h','cmoc.h','stdarg.h','stdlib.h'], + //extra_compile_args: ['--vectrex'], }, 'williams-defender': { arch: '6809',