vectrex: got xasm and c working

This commit is contained in:
Steven Hugg 2020-06-09 10:05:46 -05:00
parent f1961bc9bf
commit 01b01b169a
16 changed files with 794 additions and 33 deletions

22
presets/vectrex/hello.c Normal file
View File

@ -0,0 +1,22 @@
#pragma vx_copyright "2020"
#pragma vx_title_pos -100, -80
#pragma vx_title_size -8, 80
#pragma vx_title "HELLO WORLD"
#pragma vx_music vx_music_1
#include "vectrex.h"
#include "bios.h"
int main()
{
while(1)
{
wait_retrace();
intensity(0x7f);
print_str_c( 0x10, -0x50, (char*)"HELLO WORLD!" );
intensity(0x3f);
print_str_c( -0x10, -0x50, (char*)"THIS IS CMOC" );
}
return 0;
}

View File

@ -0,0 +1,48 @@
; http://vide.malban.de/help/vectrex-tutorial-ii-starting-with-bios
;***************************************************************************
; DEFINE SECTION
;***************************************************************************
Intensity_5F EQU $F2A5 ; BIOS Intensity routine
Print_Str_d EQU $F37A ; BIOS print routine
Wait_Recal EQU $F192 ; BIOS recalibration
music1 EQU $FF8F ; address of a (BIOS ROM)
; music
; start of vectrex memory with cartridge name...
ORG 0
;***************************************************************************
; HEADER SECTION
;***************************************************************************
FCC "g GCE 1982"
DB $80 ; 'g' is copyright sign
DW music1 ; music from the rom
DB $F8
DB $50
DB $20
DB -$56 ; height, width, rel y, rel x
; (from 0,0)
FCC "HELLO WORLD PROG 1"
DB $80 ; some game information,
; ending with $80
DB 0 ; end of game header
;***************************************************************************
; CODE SECTION
;***************************************************************************
; here the cartridge program starts off
main:
JSR Wait_Recal ; Vectrex BIOS recalibration
JSR Intensity_5F ; Sets the intensity of the
; vector beam to $5f
LDU #hello ; address of string
LDA #$10 ; Text position relative Y
LDB #-$50 ; Text position relative X
JSR Print_Str_d ; Vectrex BIOS print routine
BRA main ; and repeat forever
;***************************************************************************
; DATA SECTION
;***************************************************************************
hello:
FCC "HELLO WORLD" ; only capital letters
DB $80 ; $80 is end of string
;***************************************************************************
END main
;***************************************************************************

View File

@ -589,9 +589,6 @@ export abstract class Base6809Platform extends BaseZ80Platform {
return cpu;
}
getPC() { return this._cpu.PC; }
getSP() { return this._cpu.SP; }
cpuStateToLongString(c:CpuState) {
return cpuStateToLongString_6809(c);
}

View File

@ -2371,6 +2371,7 @@ return {
reset();
},
getPC: function() { return PC; },
getSP: function() { return rS; },
saveState: function() {
return {
PC:PC,

View File

@ -349,6 +349,8 @@ export const Keys = {
B: {c: 16, n: "Shift", plyr:0, button:1},
GP_A: {c: 88, n: "X", plyr:0, button:0},
GP_B: {c: 90, n: "Z", plyr:0, button:1},
GP_C: {c: 83, n: "S", plyr:0, button:2},
GP_D: {c: 65, n: "A", plyr:0, button:3},
SELECT: {c: 220, n: "\\", plyr:0, button:8},
START: {c: 13, n: "Enter", plyr:0, button:9},
// gamepad and keyboard (player 1)

View File

@ -3,6 +3,8 @@ import { Platform, BaseZ80Platform, Base6502Platform, Base6809Platform } from ".
import { PLATFORMS, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, VectorVideo, Keys, makeKeycodeMap } from "../common/emu";
import { hex, lzgmini, stringToByteArray, safe_extend } from "../common/util";
import { MasterAudio, AY38910_Audio } from "../common/audio";
import { ProbeRecorder } from "../common/recorder";
import { NullProbe, Probeable, ProbeAll } from "../common/devices";
// emulator from https://github.com/raz0red/jsvecx
// https://roadsidethoughts.com/vectrex/vectrex-memory-map.htm
@ -14,19 +16,19 @@ import { MasterAudio, AY38910_Audio } from "../common/audio";
var VECTREX_PRESETS = [
{ id: 'hello.xasm', name: 'Hello World (ASM)' },
{ id: 'hello.c', name: 'Hello World (CMOC)' },
]
// TODO: player 2
var VECTREX_KEYCODE_MAP = makeKeycodeMap([
[Keys.B, 3, 0xff],
[Keys.A, 4, 0xff],
[Keys.SELECT, 8, 0xff],
[Keys.VK_6, 9, 0xff],
[Keys.VK_7, 10, 0xff],
[Keys.START, 11, 0xff],
[Keys.P2_START, 12, 0xff],
[Keys.UP, 13, 0xff],
[Keys.RIGHT, 14, 0xff],
[Keys.LEFT, 15, 0xff],
[Keys.LEFT, 0, 0x01],
[Keys.RIGHT, 0, 0x02],
[Keys.DOWN, 0, 0x04],
[Keys.UP, 0, 0x08],
[Keys.GP_A, 2, 0x01],
[Keys.GP_B, 2, 0x02],
[Keys.GP_C, 2, 0x04],
[Keys.GP_D, 2, 0x08],
]);
//
@ -137,7 +139,7 @@ class VIA6522 {
/* continuous interrupt mode */
this.ifr |= 0x40;
this.int_update();
this.t1pb7 = 0x80 - this.t1pb7;
this.t1pb7 ^= 0x80;
/* reload counter */
this.t1c = (this.t1lh << 8) | this.t1ll;
}
@ -284,6 +286,7 @@ class VIA6522 {
if ((this.orb & 0x18) == 0x08) {
/* the snd chip is driving port a */
data = this.vectrex.psg.readData();
//console.log(this.vectrex.psg.currentRegister(), data);
}
else {
data = this.ora;
@ -484,10 +487,14 @@ const Globals =
VECTREX_COLORS: 128, /* number of possible colors ... grayscale */
ALG_MAX_X: 33000,
ALG_MAX_Y: 41000,
VECTREX_PDECAY: 30, /* phosphor decay rate */
VECTOR_HASH: 65521,
SCREEN_X_DEFAULT: 330,
SCREEN_Y_DEFAULT: 410
//VECTREX_PDECAY: 30, /* phosphor decay rate */
//VECTOR_HASH: 65521,
SCREEN_X_DEFAULT: 900,
SCREEN_Y_DEFAULT: 1100,
BOUNDS_MIN_X: 0,
BOUNDS_MAX_X: 30000,
BOUNDS_MIN_Y: 41000,
BOUNDS_MAX_Y: 0,
};
class VectrexAnalog {
@ -616,14 +623,14 @@ class VectrexAnalog {
var sig_ramp = 0;
var sig_blank = 0;
if ((via.acr & 0x10) == 0x10) {
if (via.acr & 0x10) {
sig_blank = via.cb2s;
}
else {
sig_blank = via.cb2h;
}
if (via.ca2) // pulse mode
if (via.ca2 == 0)
{
/* need to force the current point to the 'orgin' so just
* calculate distance to origin and use that as dx,dy.
@ -648,6 +655,7 @@ class VectrexAnalog {
sig_dy = 0;
}
}
//if (sig_dx || sig_dy) console.log(via.ca2, this.curr_x, this.curr_y, this.dx, this.dy, sig_dx, sig_dy, sig_ramp, sig_blank);
if (!this.vectoring) {
if (sig_blank == 1 &&
@ -724,6 +732,11 @@ class VectrexAnalog {
addline(x0, y0, x1, y1, color) {
// TODO
//console.log(x0, y0, x1, y1, color);
x0 = (x0 - Globals.BOUNDS_MIN_X) / (Globals.BOUNDS_MAX_X - Globals.BOUNDS_MIN_X) * Globals.SCREEN_X_DEFAULT;
x1 = (x1 - Globals.BOUNDS_MIN_X) / (Globals.BOUNDS_MAX_X - Globals.BOUNDS_MIN_X) * Globals.SCREEN_X_DEFAULT;
y0 = (y0 - Globals.BOUNDS_MIN_Y) / (Globals.BOUNDS_MAX_Y - Globals.BOUNDS_MIN_Y) * Globals.SCREEN_Y_DEFAULT;
y1 = (y1 - Globals.BOUNDS_MIN_Y) / (Globals.BOUNDS_MAX_Y - Globals.BOUNDS_MIN_Y) * Globals.SCREEN_Y_DEFAULT;
this.vectrex.video.drawLine(x0, y0, x1, y1, color, 7);
}
saveState() {
@ -772,9 +785,8 @@ class VectrexPlatform extends Base6809Platform {
this.alg = new VectrexAnalog(this);
this.bios = padBytes(new lzgmini().decode(stringToByteArray(atob(VECTREX_FASTROM_LZG))), 0x2000);
this.ram = new Uint8Array(0x400);
this.inputs = new Uint8Array(16);
this.bus = {
this.inputs = new Uint8Array(4);
var mbus = {
read: newAddressDecoder([
[0x0000, 0x7fff, 0, (a) => { return this.rom && this.rom[a]; }],
[0xc800, 0xcfff, 0x3ff, (a) => { return this.ram[a]; }],
@ -787,26 +799,43 @@ class VectrexPlatform extends Base6809Platform {
[0xd000, 0xd7ff, 0x3ff, (a, v) => { this.via.write(a & 0xf, v); }],
[0xd800, 0xdfff, 0x3ff, (a, v) => { this.ram[a] = v; this.via.write(a & 0xf, v); }],
])
};
this.bus = {
read: (a) => { var v = mbus.read(a); this.probe.logRead(a,v); return v; },
write: (a,v) => { this.probe.logWrite(a,v); mbus.write(a,v); }
};
this._cpu = this.newCPU(this.bus);
// create video/audio
this.video = new VectorVideo(this.mainElement, 660, 820);
this.video = new VectorVideo(this.mainElement, Globals.SCREEN_X_DEFAULT, Globals.SCREEN_Y_DEFAULT);
this.video.persistenceAlpha = 0.2;
this.audio = new MasterAudio();
this.psg = new AY38910_Audio(this.audio);
this.video.create();
this.timer = new AnimationTimer(60, this.nextFrame.bind(this));
setKeyboardFromMap(this.video, this.inputs, VECTREX_KEYCODE_MAP);
setKeyboardFromMap(this.video, this.inputs, VECTREX_KEYCODE_MAP); // true = always send function);
}
advance() {
updateControls() {
// joystick (analog simulation)
this.alg.jch0 = (this.inputs[0] & 0x1) ? 0x00 : (this.inputs[0] & 0x2) ? 0xff : 0x80;
this.alg.jch1 = (this.inputs[0] & 0x4) ? 0x00 : (this.inputs[0] & 0x8) ? 0xff : 0x80;
// buttons (digital)
this.psg.psg.register[14] = ~this.inputs[2];
}
advance(novideo:boolean) {
if (!novideo) this.video.clear();
this.updateControls();
this.probe.logNewFrame();
var cycles = 1500000 / 60;
while (cycles > 0) {
this.probe.logExecute(this.getPC(), this.getSP());
if (this.via.ifr & 0x80) {
this._cpu.interrupt();
}
var n = this.runCPU(this._cpu, 1);
if (n == 0) n = 1; // TODO?
this.probe.logClocks(n);
cycles -= n;
for (; n > 0; n--) {
this.via.step0();
@ -919,6 +948,22 @@ class VectrexPlatform extends Base6809Platform {
default: return super.getDebugInfo(category, state);
}
}
// probing
nullProbe = new NullProbe();
probe : ProbeAll = this.nullProbe;
startProbing?() : ProbeRecorder {
var rec = new ProbeRecorder(this);
this.connectProbe(rec);
return rec;
}
stopProbing?() : void {
this.connectProbe(null);
}
connectProbe(probe:ProbeAll) {
this.probe = probe || this.nullProbe;
}
}
//

View File

@ -0,0 +1,20 @@
/* assert.h - Assert macro for CMOC
By Pierre Sarrazin <http://sarrazip.com/>.
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 */

View File

@ -0,0 +1,203 @@
#ifndef __vectrex_bios_h__
#define __vectrex_bios_h__
#include "vectrex.h"
// Expose Vectrex music addreses
#define vx_music_1 (char*) 0xFD0D
#define vx_music_2 (char*) 0xFD1D
#define vx_music_3 (char*) 0xFD81
#define vx_music_4 (char*) 0xFDD3
#define vx_music_5 (char*) 0xFE38
#define vx_music_6 (char*) 0xFE76
#define vx_music_7 (char*) 0xFEC6
#define vx_music_8 (char*) 0xFEF8
#define vx_music_9 (char*) 0xFF26
#define vx_music_10 (char*) 0xFF44
#define vx_music_11 (char*) 0xFF62
#define vx_music_12 (char*) 0xFF7A
#define vx_music_13 (char*) 0xFF8F
#define JOY1_BTN1 0
#define JOY1_BTN2 1
#define JOY1_BTN3 2
#define JOY1_BTN4 3
#define JOY2_BTN1 4
#define JOY2_BTN2 5
#define JOY2_BTN3 6
#define JOY2_BTN4 7
#define JOY1_BTN1_MASK (1<<JOY1_BTN1)
#define JOY1_BTN2_MASK (1<<JOY1_BTN2)
#define JOY1_BTN3_MASK (1<<JOY1_BTN3)
#define JOY1_BTN4_MASK (1<<JOY1_BTN4)
#define JOY2_BTN1_MASK (1<<JOY2_BTN1)
#define JOY2_BTN2_MASK (1<<JOY2_BTN2)
#define JOY2_BTN3_MASK (1<<JOY2_BTN3)
#define JOY2_BTN4_MASK (1<<JOY2_BTN4)
#define JOY_UP 0
#define JOY_DOWN 1
#define JOY_LEFT 2
#define JOY_RIGHT 3
#define JOY_UP_MASK (1<<JOY_UP)
#define JOY_DOWN_MASK (1<<JOY_DOWN)
#define JOY_LEFT_MASK (1<<JOY_RIGHT)
#define JOY_RIGHT_MASK (1<<JOY_LEFT)
#define JOY_UP_MASK_ASM 1
#define JOY_DOWN_MASK_ASM 2
#define JOY_LEFT_MASK_ASM 4
#define JOY_RIGHT_MASK_ASM 8
// Read the joystick buttons.
// uint8_t buttons = read_buttons();
// if (buttons & JOY1_BTN1_MASK) {
// do stuff when joystick one button one is pressed
// ...
// }
uint8_t read_buttons();
// Read the joystick positions. This is an expensive call, as the Vectrex makes use of measring time over
// an RC network to do AD conversion for the joystick positions. For the moment, only digital positions are
// measured with this routine.
// You can use this routine as follows:
// uint8_t joystick = read_joystick(1);
// if ( joystick & JOY_UP_MASK) {
// do joystick up stuff
// ...
// }
uint8_t read_joystick(uint8_t joystick);
// This call waits for timer two to timeout and restarts it, it then recalibrates the vector generators to
// coordinate (0, 0) it also calls the BIOS routine behind reset_beam in the process.
void wait_retrace();
// Set the beam intensity. The value 0x7f is often used and is rather bright.
void intensity(uint8_t i);
// Reset the beam to the middle of the screen.
// This is necassary from time to time as there is drift on the Vectrex integrators.
// Caling this makes coordinate (0,0) the middle of the screen.
void reset_beam();
// Set the text width and height. Negative values are needed for the y coordinate. Otherwise text will be upside down.
void set_text_size(int8_t height, int8_t width);
// Print a string to the screen. The string must end with 0x80
void print_str(int8_t y, int8_t x, char* string);
// Print a C string (ends with 0).
void print_str_c(int8_t y, int8_t x, char* string);
// Draw one dot at the relative y and x coordinate from the last beam position.
void dot(int8_t y, int8_t x);
// Draw a list of dots to the screen. Each dot is positioned relative to the previous one.
void dots(uint8_t nr_dots, int8_t* list);
// Set the scale. With this you can zoom in and out objects.
void set_scale(int8_t scale);
// Move the dot to a specific position.
void move(uint8_t y, uint8_t x);
// Draw a line.
void line(int8_t y, int8_t x);
// Draw lines.
// The list of lines can live in ROM.
// You provide the list of lines as follows:
// int8_t list[n] = {
// y1, x1,
// y2, x2,
// ...
// xn, yn
// };
// Make note that these are not absolute, but relative coordinates.
void lines(uint8_t nr_lines, int8_t* list);
// Draw patterned lines, where the pattern is provided as the first parameter, for the rest
// this function behaves the same as the lines fucntion.
void pattern_lines(uint8_t pattern, uint8_t nr_lines, int8_t *list);
// Rotate a list of points. The points array can be in ROM, but the out_points need to be in RAM.
// The list of points is given as follows:
// int8_t points[n] = {
// y1, x1,
// y2, x2,
// ...
// yn, xn
// };
void rotate(int8_t angle, uint8_t nr_points, int8_t* points, int8_t* out_points);
// Set the music flag, which should be set to 1 to start playing music using the BIOS routine.
// The music flag has 3 states: 0, 1 and 0x80.
// State 0 means no music is playing. A 1 means we are about to start the music.
// And 0x80 means the music is currently playing.
void music_set_flag(uint8_t flag);
// Get the music flag, which can have the states documented with the get method.
// If you want to repeat the music, you should check this flag and if it is 0 set to 1 again.
uint8_t music_get_flag();
// Point the BIOS play routine to a piece of music.
// Info about the format: http://www.playvectrex.com/designit/chrissalo/soundplaying.htm
void music_check(unsigned char* music);
// Call this in the main loop to play the music.
void music_play();
// The Vectrex uses three bytes for the random seed.
void random_seed(uint8_t seed1, uint8_t seed2, uint8_t seed3);
// Produce a random value using the BIOS Random function.
int8_t random();
// What follows here are some low level BIOS fucntions that are not really necessary to call from your
// C program, but the are here for completeness.
void cold_start();
void warm_start();
void init_via();
void init_os_ram();
void init_os();
void set_refresh(uint16_t value);
#endif // __vectrex_bios_h__

View File

@ -0,0 +1,345 @@
// cmoc.h - CMOC's standard library functions.
//
// By Pierre Sarrazin <http://sarrazip.com/>.
// 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif /* __GNUC__ */
#endif /* _H_CMOC */

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,22 @@
/* stdarg.h - Support for variable argument functions
By Pierre Sarrazin <http://sarrazip.com/>.
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_ */

View File

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

View File

@ -0,0 +1,27 @@
// This file is in the public domain.
#ifndef __vectrex_h__
#define __vectrex_h__
enum { FALSE, TRUE };
#ifndef _CMOC_BASIC_TYPES_
#define _CMOC_BASIC_TYPES_
typedef unsigned char byte;
typedef signed char sbyte;
typedef unsigned int word;
typedef signed int sword;
typedef unsigned long dword;
typedef signed long sdword;
#endif
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned int uint16_t;
typedef signed int int16_t;
typedef unsigned long uint32_t;
typedef signed long int32_t;
#endif

View File

@ -0,0 +1,17 @@
define basesympat s_%s
define lensympat l_%s
section start load 0
section code
section constructors_start
section constructors
section constructors_end
section destructors_start
section destructors
section destructors_end
section initgl_start
section initgl
section initgl_end
section rodata
section rwdata load c880
section bss,bss
entry program_start

View File

@ -253,7 +253,9 @@ var PLATFORM_PARAMS = {
data_start: 0xc880,
data_size: 0x380,
stack_end: 0xcc00,
extra_compile_files: ['assert.h','cmoc.h','stdarg.h','vectrex.h','stdlib.h','bios.h'],
extra_link_files: ['vectrex.scr', 'libcmoc-crt-vec.a', 'libcmoc-std-vec.a'],
extra_compile_args: ['--vectrex'],
extra_link_args: ['-svectrex.scr', '-lcmoc-crt-vec', '-lcmoc-std-vec'],
},
};
@ -2099,12 +2101,6 @@ function compileCMOC(step:BuildStep) {
//logReadFiles:true,
print:match_fn,
printErr:match_fn,
//arguments:args,
/*
locateFile: (path,prefix) => {
return prefix + 'wasm/' + path;
}
*/
});
// load source file and preprocess
var code = getWorkFileAsString(step.path);
@ -2117,6 +2113,9 @@ function compileCMOC(step:BuildStep) {
populateFiles(step, FS);
FS.writeFile(step.path, code);
fixParamsWithDefines(step.path, params);
if (params.extra_compile_args) {
args.unshift.apply(args, params.extra_compile_args);
}
execMain(step, CMOC, args);
if (errors.length)
return {errors:errors};