astrocade: split bios into .c files; check rom_size on sdcc targets (not yet)

This commit is contained in:
Steven Hugg 2019-06-02 10:53:39 -04:00
parent 50421a69f3
commit b3861f3361
13 changed files with 651 additions and 524 deletions

View File

@ -35,7 +35,6 @@ TODO:
- go to error in include files
- online tools for music etc
- text log debugging script
- NES crt should mark raster pos when debugging
- intro/help text for each platform
- vscode/atom extension?
- VCS asm library
@ -63,7 +62,10 @@ TODO:
- what if .c and .s names collide?
- maybe put stuff in examples/ dir?
- error msg when #link doesn't work
- sdcc: can't link asm files before c files (e.g. acheader.s must be last)
- warning when ROM too big
- sdcc:
- can't link asm files before c files (e.g. acheader.s must be last)
- figure out area names ordering
- live coding URL
- resize memory browser when vertical div resize
- preroll the emulator so optimizer does its thing before loading rom
@ -87,7 +89,6 @@ TODO:
- show player controls for each platform, allow touch support, navigator.getGamepads
- better undo/diff for mistakes?
- ide bug/feature visualizer for sponsors
- optimization flags for sdcc (oldralloc)
- global undo/redo at checkpoints (when rom changes)
- pulldown shows wrong file if preset not present
- landscape mode for arcade ports
@ -104,7 +105,6 @@ TODO:
- parse .incbin directives?
- can't replace in hex directives
- should maybe use same single-canvas editor for map + char editor
- Uncaught Expected 12 bytes; image has 6 (380:13): Expected 12 bytes; image has 6 ... over and over ... editing BALL
- crt0.s compiled each time?
- debug highlight doesn't go away when debugging -> running
- show breakpoint of PC or highest address on stack
@ -133,6 +133,7 @@ TODO:
- nes debug view toolbar
- support NES_HEADER_16K?
- PPU/TIA register write visualization
- NES crt should mark raster pos when debugging
- vcs
- vcs sound continues when paused
- vcs: INPTx needs to be added to control state
@ -157,6 +158,7 @@ TODO:
- support projects with subdirectories, file list?
- emulator needs reset shortcut for nes
- switching platform of a repo?
- make sure to flatten subdirs
- ctrl+alt+l on ubuntu locks screen
WEB WORKER FORMAT

View File

@ -21,86 +21,18 @@ See: http://creativecommons.org/publicdomain/zero/1.0/
// music processor
//#link "bmusic.c"
// input
//#link "input.c"
// graphics
//#link "gfx.c"
#include <string.h>
#include "bios.h"
// uncomment to make code better, but slower compile
//#pragma opt_code_speed
typedef unsigned char byte;
typedef signed char sbyte;
typedef unsigned short word;
typedef signed short sword;
/// HARDWARE
__sfr __at(0x00) hw_col0r; // palette 0
__sfr __at(0x01) hw_col1r;
__sfr __at(0x02) hw_col2r;
__sfr __at(0x03) hw_col3r;
__sfr __at(0x04) hw_col0l;
__sfr __at(0x05) hw_col1l;
__sfr __at(0x06) hw_col2l;
__sfr __at(0x07) hw_col3l; // palette 7
__sfr __at(0x08) hw_intst; // intercept test feedback
__sfr __at(0x09) hw_horcb; // horiz color boundary
__sfr __at(0x0a) hw_verbl; // vertical blanking line * 2
__sfr __at(0x0c) hw_magic; // magic register
__sfr __at(0x0d) hw_infbk; // interrupt feedback
__sfr __at(0x0e) hw_inmod; // interrupt enable
__sfr __at(0x0f) hw_inlin; // interrupt line
__sfr __at(0x19) hw_xpand; // expander register
__sfr __at(0x10) hw_p1ctrl; // player controls
__sfr __at(0x11) hw_p2ctrl; // player controls
__sfr __at(0x12) hw_p3ctrl; // player controls
__sfr __at(0x13) hw_p4ctrl; // player controls
__sfr __at(0x14) hw_keypad0;
__sfr __at(0x15) hw_keypad1;
__sfr __at(0x16) hw_keypad2;
__sfr __at(0x17) hw_keypad3;
__sfr __at(0x1c) hw_p1pot; // player pot
__sfr __at(0x1d) hw_p2pot; // player pot
__sfr __at(0x1e) hw_p3pot; // player pot
__sfr __at(0x1f) hw_p4pot; // player pot
#define M_SHIFT0 0x00
#define M_SHIFT1 0x01
#define M_SHIFT2 0x02
#define M_SHIFT3 0x03
#define M_XPAND 0x08
#define M_MOVE 0x00
#define M_OR 0x10
#define M_XOR 0x20
#define M_FLOP 0x40
#define M_SHIFT(x) ((x)&3)
#define XPAND_COLORS(off,on) (((off)&3) | (((on)&3)<<2))
// font options
#define OPT_1x1 0x00
#define OPT_2x2 0x40
#define OPT_4x4 0x80
#define OPT_8x8 0xc0
#define OPT_XOR 0x20
#define OPT_OR 0x10
#define OPT_ON(n) ((n)<<2)
#define OPT_OFF(n) ((n))
// bcd options
#define DISBCD_SML 0x40
#define DISBCD_NOZERO 0x80
/// GRAPHICS FUNCTIONS
#define VHEIGHT 102 // number of scanlines
#define VBWIDTH 40 // number of bytes per scanline
#define PIXWIDTH 160 // 4 pixels per byte
//#define EXIT_CLIPDEST(addr) if ((((word)addr)&0xfff) >= 0xe10) return
#define EXIT_CLIPDEST(addr)
byte __at (0x0000) vmagic[VHEIGHT][VBWIDTH];
byte __at (0x4000) vidmem[VHEIGHT][VBWIDTH];
#pragma opt_code_speed
// start @ $4FCE
volatile word MUZPC; // music PC
@ -136,35 +68,7 @@ byte SENFLG; // sentry control
byte* UMARGT; // user mask table (-64 bytes)
word* USERTB; // user routine table (-128 bytes)
typedef enum {
SNUL,
SCT0,SCT1,SCT2,SCT3,SCT4,SCT5,SCT6,SCT7,
SF0,SF1,SF2,SF3,SF4,SF5,SF6,SF7,
SSEC,
SKYU,SKYD,
ST0,SJ0,ST1,SJ1,ST2,SJ2,ST3,SJ3,
SP0,SP1,SP2,SP3
} SENTRYCode;
typedef struct {
byte base_ch; // first char
byte frame_x; // frame width
byte frame_y; // frame height
byte pattern_x; // pattern width
byte pattern_y; // pattern height
const byte* chartab; // pointer to char data
} FontDescriptor;
#define LOCHAR 0x20
#define HICHAR 0x63
extern const char BIGFONT[HICHAR-LOCHAR+1][7];
extern const char SMLFONT[HICHAR-LOCHAR+1][5];
const FontDescriptor __at(0x206) FNTSYS; // = { 0x20, 8, 8, 1, 7, (byte*)BIGFONT };
const FontDescriptor __at(0x20d) FNTSML; // = { 0xa0, 4, 6, 1, 5, (byte*)SMLFONT };
// from bmusic.c
extern void music_update(void);
// INTERRUPT HANDLERS
@ -231,59 +135,6 @@ void TIMEY() {
void TIMEX() {
}
///// INTERPRETER
typedef struct {
union {
struct {
word iy,ix,de,bc,af,hl;
} w;
struct {
byte iyl,iyh,ixl,ixh,e,d,c,b,f,a,l,h;
} b;
} regs;
byte* params;
} ContextBlock;
#define REG_IY 0x1
#define REG_E 0x2
#define REG_D 0x4
#define REG_C 0x8
#define REG_B 0x10
#define REG_IX 0x20
#define REG_A 0x40
#define REG_HL 0x80
#define REG_DE (REG_D|REG_E)
#define REG_BC (REG_B|REG_C)
#define _IY (ctx->regs.w.iy)
#define _IX (ctx->regs.w.ix)
#define _DE (ctx->regs.w.de)
#define _BC (ctx->regs.w.bc)
#define _AF (ctx->regs.w.af)
#define _HL (ctx->regs.w.hl)
#define _IXL (ctx->regs.b.ixl)
#define _IXH (ctx->regs.b.ixh)
#define _IYL (ctx->regs.b.iyl)
#define _IYH (ctx->regs.b.iyh)
#define _E (ctx->regs.b.e)
#define _D (ctx->regs.b.d)
#define _C (ctx->regs.b.c)
#define _B (ctx->regs.b.b)
#define _A (ctx->regs.b.a)
#define _L (ctx->regs.b.l)
#define _H (ctx->regs.b.h)
typedef void (Routine)();
typedef void (SysRoutine)(ContextBlock *ctx);
typedef struct {
SysRoutine* routine;
byte argmask;
} SysCallEntry;
void SYSCALL(ContextBlock *ctx);
void INTPC(ContextBlock *ctx) {
while (ctx->params[0] != 2) { // 2 = exit
SYSCALL(ctx);
@ -302,7 +153,10 @@ void RCALL(ContextBlock *ctx) {
// start interpreting at HL
void MCALL(ContextBlock *ctx) {
ctx; // TODO
ctx->params = (byte*)_HL;
while (ctx->params[0] != 8) { // 8 = MRET
SYSCALL(ctx);
}
}
// exit MCALL loop
@ -369,17 +223,19 @@ void SETOUT(ContextBlock *ctx) {
hw_inmod = _A;
}
// set entire palette at once (8 bytes to port 0xb)
// bytes in array should be in reverse
void set_palette(byte palette[8]) __z88dk_fastcall {
palette;
__asm
ld bc,#0x80b ; B -> 8, C -> 0xb
otir ; write C bytes from HL to port[B]
__endasm;
}
// sets color palettes from (HL)
void COLSET(ContextBlock *ctx) {
byte* palette = (byte*) _HL;
hw_col3l = *palette++;
hw_col2l = *palette++;
hw_col1l = *palette++;
hw_col0l = *palette++;
hw_col3r = *palette++;
hw_col2r = *palette++;
hw_col1r = *palette++;
hw_col0r = *palette++;
set_palette((byte*)_HL);
}
// Stores A in BC bytes starting at location DE.
@ -390,248 +246,6 @@ void FILL(ContextBlock *ctx) {
memset(dest, val, count);
}
void hline(byte x1, byte x2, byte y, byte pattern) {
byte xb1 = x1/4;
byte xb2 = x2/4;
byte* dest = &vmagic[y][xb1];
signed char nbytes = xb2 - xb1;
hw_magic = M_SHIFT(x1) | M_XOR;
while (--nbytes > 0) {
*dest++ = pattern;
}
if (x2&3) *dest = 0;
// TODO
}
// Fill rect (E,D,C,B) color A
void RECTAN(const ContextBlock *ctx) {
for (byte y=_D; y<_D+_B; y++) {
hline(_E, _E+_C, y, _A);
}
}
const char BIGFONT[HICHAR-LOCHAR+1][7] = {/*{count:68,w:8,h:7,brev:1}*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x20,0x20,0x20,0x20,0x00,0x00,0x20},{0x50,0x50,0x00,0x00,0x00,0x00,0x00},{0x48,0xFC,0x48,0x48,0x48,0xFC,0x48},{0x20,0x78,0x80,0x70,0x08,0xF0,0x20},{0x00,0x48,0x10,0x20,0x40,0x90,0x00},{0x60,0x90,0x60,0xA0,0xA8,0x90,0x68},{0x60,0x60,0x20,0x00,0x00,0x00,0x00},{0x20,0x40,0x40,0x40,0x40,0x40,0x20},{0x40,0x20,0x20,0x20,0x20,0x20,0x40},{0x00,0xA8,0x70,0xF8,0x70,0xA8,0x00},{0x00,0x20,0x20,0xF8,0x20,0x20,0x00},{0x00,0x00,0x00,0x00,0x60,0x20,0x40},{0x00,0x00,0x00,0xF0,0x00,0x00,0x00},{0x00,0x00,0x00,0x00,0x00,0x60,0x60},{0x00,0x08,0x10,0x20,0x40,0x80,0x00},{0x70,0x88,0x88,0xA8,0x88,0x88,0x70},{0x20,0x60,0x20,0x20,0x20,0x20,0x70},{0x70,0x88,0x08,0x30,0x40,0x80,0xF8},{0x70,0x88,0x08,0x70,0x08,0x88,0x70},{0x10,0x30,0x50,0x90,0xF8,0x10,0x10},{0xF8,0x80,0x80,0x70,0x08,0x88,0x70},{0x70,0x88,0x80,0xF0,0x88,0x88,0x70},{0xF8,0x88,0x10,0x20,0x20,0x20,0x20},{0x70,0x88,0x88,0x70,0x88,0x88,0x70},{0x70,0x88,0x88,0x78,0x08,0x88,0x70},{0x00,0x00,0x60,0x00,0x60,0x00,0x00},{0x00,0x00,0x60,0x00,0x60,0x20,0x40},{0x10,0x20,0x40,0x80,0x40,0x20,0x10},{0x00,0x00,0xF8,0x00,0xF8,0x00,0x00},{0x40,0x20,0x10,0x08,0x10,0x20,0x40},{0x70,0x08,0x08,0x30,0x20,0x00,0x20},{0x70,0x88,0xB8,0xA8,0x90,0x80,0x70},{0x70,0x88,0x88,0xF8,0x88,0x88,0x88},{0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0},{0x70,0x88,0x80,0x80,0x80,0x88,0x70},{0xF0,0x88,0x88,0x88,0x88,0x88,0xF0},{0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8},{0xF8,0x80,0x80,0xF0,0x80,0x80,0x80},{0x70,0x88,0x80,0xB0,0x88,0x88,0x70},{0x88,0x88,0x88,0xF8,0x88,0x88,0x88},{0x70,0x20,0x20,0x20,0x20,0x20,0x70},{0x08,0x08,0x08,0x08,0x88,0x88,0x70},{0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88},{0x80,0x80,0x80,0x80,0x80,0x80,0xF8},{0x88,0xD8,0xA8,0x88,0x88,0x88,0x88},{0x88,0xC8,0xA8,0xA8,0x98,0x88,0x88},{0xF8,0x88,0x88,0x88,0x88,0x88,0xF8},{0xF0,0x88,0x88,0xF0,0x80,0x80,0x80},{0x70,0x88,0x88,0xA8,0xA8,0x90,0x68},{0xF0,0x88,0x88,0xF0,0x90,0x90,0x88},{0x70,0x88,0x80,0x70,0x08,0x88,0x70},{0xF8,0x20,0x20,0x20,0x20,0x20,0x20},{0x88,0x88,0x88,0x88,0x88,0x88,0x70},{0x88,0x88,0x88,0x88,0x88,0x50,0x20},{0x88,0x88,0x88,0x88,0xA8,0xD8,0x88},{0x88,0x88,0x50,0x20,0x50,0x88,0x88},{0x88,0x88,0x50,0x20,0x20,0x20,0x20},{0xF8,0x08,0x10,0x20,0x40,0x80,0xF8},{0x70,0x40,0x40,0x40,0x40,0x40,0x70},{0x00,0x80,0x40,0x20,0x10,0x08,0x00},{0x70,0x10,0x10,0x10,0x10,0x10,0x70},{0x20,0x70,0xA8,0x20,0x20,0x20,0x00},{0x00,0x20,0x40,0xF8,0x40,0x20,0x00},{0x00,0x20,0x20,0x20,0xA8,0x70,0x20},{0x00,0x20,0x10,0xF8,0x10,0x20,0x00},{0x00,0x88,0x50,0x20,0x50,0x88,0x00},{0x00,0x20,0x00,0xF8,0x00,0x20,0x00}};
const char SMLFONT[HICHAR-LOCHAR+1][5] = {/*{count:68,w:5,h:5,brev:1}*/
{ 0x00,0x00,0x00,0x00,0x00 },{ 0x40,0x40,0x00,0x40,0x00 },{ 0xA0,0xA0,0x00,0x00,0x00 },{ 0x60,0xF0,0xF0,0x60,0x00 },{ 0x40,0xE0,0xE0,0x40,0x00 },{ 0x90,0x20,0x40,0x90,0x00 },{ 0xC0,0xB0,0xE0,0xD0,0x00 },{ 0x20,0x40,0x00,0x00,0x00 },{ 0x20,0x40,0x40,0x20,0x00 },{ 0x40,0x20,0x20,0x40,0x00 },{ 0x40,0xE0,0x40,0xA0,0x00 },{ 0x00,0x40,0xE0,0x40,0x00 },{ 0x00,0x00,0x00,0x60,0x20 },{ 0x00,0x00,0xE0,0x00,0x00 },{ 0x00,0x00,0x00,0x40,0x00 },{ 0x20,0x20,0x40,0x40,0x00 },{ 0xE0,0xA0,0xA0,0xA0,0xE0 },{ 0xC0,0x40,0x40,0x40,0xE0 },{ 0xE0,0x20,0xE0,0x80,0xE0 },{ 0xE0,0x20,0x60,0x20,0xE0 },{ 0xA0,0xA0,0xE0,0x20,0x20 },{ 0xE0,0x80,0xE0,0x20,0xE0 },{ 0xE0,0x80,0xE0,0xA0,0xE0 },{ 0xE0,0x20,0x40,0x40,0x40 },{ 0xE0,0xA0,0xE0,0xA0,0xE0 },{ 0xE0,0xA0,0xE0,0x20,0xE0 },{ 0x00,0x40,0x00,0x40,0x00 },{ 0x00,0x40,0x00,0x60,0x20 },{ 0x00,0x20,0x40,0x20,0x00 },{ 0x00,0xE0,0x00,0xE0,0x00 },{ 0x00,0x40,0x20,0x40,0x00 },{ 0xE0,0x20,0x60,0x00,0x40 },{ 0xF0,0x90,0x10,0xD0,0xF0 },{ 0x60,0xA0,0xE0,0xA0,0x00 },{ 0xC0,0xE0,0xA0,0xE0,0x00 },{ 0x60,0x80,0x80,0xE0,0x00 },{ 0xC0,0xA0,0xA0,0xC0,0x00 },{ 0xE0,0xC0,0x80,0xE0,0x00 },{ 0xE0,0xC0,0x80,0x80,0x00 },{ 0x60,0x80,0xA0,0xE0,0x00 },{ 0xA0,0xA0,0xE0,0xA0,0x00 },{ 0xE0,0x40,0x40,0xE0,0x00 },{ 0x60,0x20,0xA0,0xE0,0x00 },{ 0xA0,0xC0,0xC0,0xA0,0x00 },{ 0x80,0x80,0x80,0xE0,0x00 },{ 0xE0,0xE0,0xE0,0xA0,0x00 },{ 0xE0,0xA0,0xA0,0xA0,0x00 },{ 0xE0,0xA0,0xA0,0xE0,0x00 },{ 0xE0,0xA0,0xE0,0x80,0x00 },{ 0xE0,0xA0,0xE0,0xF0,0x00 },{ 0xE0,0xA0,0xC0,0xA0,0x00 },{ 0xE0,0x80,0x60,0xE0,0x00 },{ 0xE0,0x40,0x40,0x40,0x00 },{ 0xA0,0xA0,0xA0,0xE0,0x00 },{ 0xA0,0xA0,0xC0,0x80,0x00 },{ 0xA0,0xE0,0xE0,0xE0,0x00 },{ 0xA0,0x40,0xA0,0xA0,0x00 },{ 0xA0,0xE0,0x40,0x40,0x00 },{ 0xE0,0x20,0x40,0xE0,0x00 },{ 0x60,0x40,0x40,0x60,0x00 },{ 0x40,0x40,0x20,0x20,0x00 },{ 0x60,0x20,0x20,0x60,0x00 },{ 0x40,0xA0,0x00,0x00,0x00 },{ 0x00,0x00,0x00,0x00,0xF0 },{ 0x80,0x40,0x00,0x00,0x00 },{ 0x00,0x60,0xA0,0xE0,0x00 },{ 0x80,0xE0,0xA0,0xE0,0x00 },{ 0x00,0x60,0x80,0xE0,0x00 }};
// draw a letter
byte draw_char(const FontDescriptor* font, byte ch, byte x, byte y, byte op) {
const byte* src = font->chartab + (ch-font->base_ch)*font->pattern_y;
byte* dest = &vmagic[y][x>>2];// destination address
byte magic = M_SHIFT(x) | M_XPAND | (op & 0x30);
// big sizes?
if (op & 0xc0) {
char buf[8]; // expansion buffer
char* mbuf = (buf - 0x4000);// make it magic
byte sc = 1 << (op >> 6); // 2x2 = 2, 4x4 = 4, 8x8 = 8
for (byte i=0; i<font->pattern_y; i++) {
// expand into magic buffer onto stack
hw_magic = M_XPAND;
hw_xpand = 0b1100; // on = 11, off = 00
// 2x2 size
mbuf[1] = mbuf[0] = *src++;
// 4x4 size
if (op & 0x80) {
byte b = buf[0];
mbuf[3] = mbuf[2] = buf[1];
mbuf[1] = mbuf[0] = b;
}
// 8x8 size
if ((op & 0xc0) == 0xc0) {
byte b = buf[0];
mbuf[7] = mbuf[6] = buf[3];
mbuf[5] = mbuf[4] = buf[2];
mbuf[3] = mbuf[2] = buf[1];
mbuf[1] = mbuf[0] = b;
}
// draw to screen (magic, again)
hw_xpand = op & 0xf;
for (byte j=0; j<sc; j++) {
hw_magic = magic; // reset flip flop
EXIT_CLIPDEST(dest);
for (byte k=0; k<sc; k++) {
byte b = buf[k];
*dest++ = b;
*dest++ = b;
}
dest += VBWIDTH-sc*2;
}
}
} else {
hw_xpand = op & 0xf;
for (byte i=0; i<font->pattern_y; i++) {
char b = *src++;
EXIT_CLIPDEST(dest);
hw_magic = magic; // reset flip flop
*dest++ = b; // expand lower nibble -> 1st byte
*dest++ = b; // expand upper nibble -> 2nd byte
*dest++ = 0; // leftover -> 3rd byte
dest += VBWIDTH-3; // we incremented 3 bytes for this line
}
}
return font->frame_x << (op >> 6);
}
#define FONT_IX ((const FontDescriptor*)ctx->regs.w.ix)
void draw_string(ContextBlock *ctx, const char* str, byte x, byte y, byte op) {
do {
byte ch = *str++;
if (!ch) {
_E = x;
break;
}
if (ch < 0x20) {
x += draw_char(&FNTSYS, ' ', x, y, op); // TODO
} else if (ch < 0x64) {
x += draw_char(&FNTSYS, ch, x, y, op);
} else if (ch >= 0x80) {
x += draw_char(FONT_IX, ch, x, y, op);
} else {
/*
if (ch & 0x10) {
ctx->regs.b.ixl = *str++;
ctx->regs.b.ixh = *str++;
}
if (ch & 0x1)
_E = *str++;
if (ch & 0x2)
_D = *str++;
if (ch & 0x4)
_C = *str++;
*/
// TODO: only can change font
}
} while (1);
}
// String display routine (pass pointer to string)
void STRDIS2(ContextBlock *ctx, char *str) {
byte opts = _C;
byte x = _E;
byte y = _D;
void* fontdesc = (void*) ctx->regs.w.ix;
draw_string(ctx, str, x, y, opts); // TODO: opts
}
// String display routine
void STRDIS(ContextBlock *ctx) {
char* str = (char*) _HL;
STRDIS2(ctx, str);
}
// Character display routine
void CHRDIS(ContextBlock *ctx) {
char chstr[2];
chstr[0] = _A;
chstr[1] = 0;
STRDIS2(ctx, chstr);
}
// BCD routine
const char BCDTAB[17] = "0123456789*+,-./";
// DISNUM - (E.D) x/y (C) options (B) ext (HL) BCD-addr
void DISNUM(ContextBlock *ctx) {
// TODO: options, B
byte x = _E;
byte y = _D;
byte opt = _C;
byte ext = _B;
byte ndigits = ext & 63;
const FontDescriptor* font = (ext&64) ? &FNTSML : &FNTSYS;
byte add = (ext&64) ? 128 : 0;
byte noleadingzero = ext & 128;
byte* pbcd = (byte*) _HL;
pbcd += (ndigits-1)/2;
while (ndigits--) {
byte val = *pbcd;
if (ndigits & 1) {
val >>= 4;
} else {
val &= 15;
pbcd--;
}
x += draw_char(font, BCDTAB[val]+add, x, y, opt);
}
}
typedef struct {
sbyte xofs, yofs;
byte xsize, ysize;
byte pattern[0];
} PatternBlock;
// write pattern (E,D,C,B) magic A @ HL
void WRIT(ContextBlock *ctx) {
byte magic = _A;
byte w = _C;
byte h = _B;
byte x = _E;
byte y = _D;
byte* src = (byte*) _HL;
byte* dest = &vmagic[y][0]; // destination address
byte xb = (magic & M_FLOP) ? (39-(x>>2)) : (x>>2);
byte i,j,b;
// iterate through all lines
for (j=0; j<h; j++) {
EXIT_CLIPDEST(dest);
hw_magic = magic;
if (magic & M_XPAND) {
// when XPAND set, write twice as many bytes
for (i=0; i<w*2; i+=2) {
b = *src++;
// when FLOP set, sprite position is also mirrored
if (magic & M_FLOP) {
dest[xb-i] = b;
dest[xb-i-1] = b;
} else {
dest[xb+i] = b;
dest[xb+i+1] = b;
}
}
} else {
for (i=0; i<w; i++) {
// when FLOP set, sprite position is also mirrored
if (magic & M_FLOP) {
dest[xb-i] = *src++;
} else {
dest[xb+i] = *src++;
}
}
}
if (magic & M_FLOP)
dest[xb-i] = 0;
else
dest[xb+i] = 0;
dest += VBWIDTH;
}
}
// write sized pattern (E,D) magic A @ HL
void WRITP(ContextBlock *ctx) {
byte* src = (byte*) _HL;
// get size
_C = *src++;
_B = *src++;
// update src
_HL = (word) src;
WRIT(ctx);
}
// write relative pattern (E,D) magic A @ HL
void WRITR(ContextBlock *ctx) {
byte* src = (byte*) _HL;
// sub offset
_E -= *src++;
_D -= *src++;
// update src
_HL = (word) src;
WRITP(ctx);
}
void wait_vsync() {
byte x = TMR60;
while (x == TMR60) ; // wait until timer/60 changes
@ -694,100 +308,19 @@ void RANGED(ContextBlock *ctx) {
// input
void SENTRY(ContextBlock *ctx) {
byte i;
byte A = SNUL;
byte B = 0;
byte key = 0;
byte val[4];
// joysticks and switches
val[0] = hw_p1ctrl;
val[1] = hw_p2ctrl;
val[2] = hw_p3ctrl;
val[3] = hw_p4ctrl;
for (i=0; i<4; i++) {
if (val[i] != OSW[i]) {
A = SJ0+i*2;
if ((val[i] ^ OSW[i]) & 0x10) {
A++;
}
B = val[i];
}
}
memcpy(OSW, val, 4); // update previous state
// keypad
val[0] = hw_keypad0;
val[1] = hw_keypad1;
val[2] = hw_keypad2;
val[3] = hw_keypad3;
for (i=0; i<4; i++) {
// key down? and with mask
if (val[i] && (val[i] &= ((byte*)_DE)[i])) {
key = i+1;
while (val[i]) {
key += 4;
val[i] >>= 1;
}
}
}
// key up?
if (key && key != KEYSEX) {
B = KEYSEX = key;
A = SKYD;
}
else if (!key && KEYSEX) {
if (KEYSEX & 0x80) {
A = SSEC; // second timer
} else {
A = SKYU;
}
B = 0;
KEYSEX = 0;
}
// pots
val[0] = hw_p1pot;
val[1] = hw_p2pot;
val[2] = hw_p3pot;
val[3] = hw_p4pot;
for (i=0; i<4; i++) {
if (val[i] != OPOT[i]) {
A = SP0+i;
B = val[i];
}
}
memcpy(OPOT, val, 4); // update previous state
// semiphores
if (SEMI4S) {
B = SEMI4S;
for (i=7; i>=0; i--) {
if (B & 0x80) {
A = SF0+i;
SEMI4S ^= 1 << i;
break;
}
B <<= 1;
}
}
// counters
if (SENFLG) {
B = SENFLG;
for (i=7; i>=0; i--) {
if (B & 0x80) {
A = SF0+i;
SENFLG ^= 1 << i;
break;
}
B <<= 1;
}
}
// clear timeout counter (TODO)
if (A >= SKYU) {
TIMOUT = 0xff;
}
_A = A;
_B = B;
const byte KCTASC_TABLE[25] = {
0x00,
0x43, 0x5e, 0x5c, 0x25, 0x52, 0x53, 0x3b, 0x2f,
0x37, 0x38, 0x39, 0x2a, 0x34, 0x35, 0x36, 0x2d,
0x31, 0x32, 0x33, 0x2b, 0x26, 0x30, 0x2e, 0x3d
};
void KCTASC(ContextBlock *ctx) {
_A = KCTASC_TABLE[_B];
}
// music
void BMUSIC(ContextBlock *ctx) {
VOICES = _A;
MUZPC = _HL;
@ -800,6 +333,22 @@ void EMUSIC(ContextBlock *ctx) {
VOICES = 0;
}
// externals
extern void SENTRY(ContextBlock *ctx);
extern void DOIT(ContextBlock *ctx);
extern void DOITB(ContextBlock *ctx);
extern void RECTAN(const ContextBlock *ctx);
extern void WRITR(const ContextBlock *ctx);
extern void WRITP(const ContextBlock *ctx);
extern void WRIT(const ContextBlock *ctx);
extern void CHRDIS(const ContextBlock *ctx);
extern void STRDIS(const ContextBlock *ctx);
extern void DISNUM(const ContextBlock *ctx);
// table
const SysCallEntry SYSCALL_TABLE[64] = {
/* 0 */
{ &INTPC, 0 },
@ -840,11 +389,11 @@ const SysCallEntry SYSCALL_TABLE[64] = {
/* 60 */
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ &KCTASC, 0 },
{ &SENTRY, REG_DE },
{ 0, 0 },
{ &DOIT, REG_HL },
/* 70 */
{ 0, 0 },
{ &DOITB, REG_HL },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },

View File

@ -0,0 +1,158 @@
typedef unsigned char byte;
typedef signed char sbyte;
typedef unsigned short word;
typedef signed short sword;
/// HARDWARE
__sfr __at(0x00) hw_col0r; // palette 0
__sfr __at(0x01) hw_col1r;
__sfr __at(0x02) hw_col2r;
__sfr __at(0x03) hw_col3r;
__sfr __at(0x04) hw_col0l;
__sfr __at(0x05) hw_col1l;
__sfr __at(0x06) hw_col2l;
__sfr __at(0x07) hw_col3l; // palette 7
__sfr __at(0x08) hw_intst; // intercept test feedback
__sfr __at(0x09) hw_horcb; // horiz color boundary
__sfr __at(0x0a) hw_verbl; // vertical blanking line * 2
__sfr __at(0x0c) hw_magic; // magic register
__sfr __at(0x0d) hw_infbk; // interrupt feedback
__sfr __at(0x0e) hw_inmod; // interrupt enable
__sfr __at(0x0f) hw_inlin; // interrupt line
__sfr __at(0x19) hw_xpand; // expander register
__sfr __at(0x10) hw_p1ctrl; // player controls
__sfr __at(0x11) hw_p2ctrl; // player controls
__sfr __at(0x12) hw_p3ctrl; // player controls
__sfr __at(0x13) hw_p4ctrl; // player controls
__sfr __at(0x14) hw_keypad0;
__sfr __at(0x15) hw_keypad1;
__sfr __at(0x16) hw_keypad2;
__sfr __at(0x17) hw_keypad3;
__sfr __at(0x1c) hw_p1pot; // player pot
__sfr __at(0x1d) hw_p2pot; // player pot
__sfr __at(0x1e) hw_p3pot; // player pot
__sfr __at(0x1f) hw_p4pot; // player pot
#define M_SHIFT0 0x00
#define M_SHIFT1 0x01
#define M_SHIFT2 0x02
#define M_SHIFT3 0x03
#define M_XPAND 0x08
#define M_MOVE 0x00
#define M_OR 0x10
#define M_XOR 0x20
#define M_FLOP 0x40
#define M_SHIFT(x) ((x)&3)
#define XPAND_COLORS(off,on) (((off)&3) | (((on)&3)<<2))
// font options
#define OPT_1x1 0x00
#define OPT_2x2 0x40
#define OPT_4x4 0x80
#define OPT_8x8 0xc0
#define OPT_XOR 0x20
#define OPT_OR 0x10
#define OPT_ON(n) ((n)<<2)
#define OPT_OFF(n) ((n))
// bcd options
#define DISBCD_SML 0x40
#define DISBCD_NOZERO 0x80
/// GRAPHICS FUNCTIONS
#define VHEIGHT 102 // number of scanlines
#define VBWIDTH 40 // number of bytes per scanline
#define PIXWIDTH 160 // 4 pixels per byte
//#define EXIT_CLIPDEST(addr) if ((((word)addr)&0xfff) >= 0xe10) return
#define EXIT_CLIPDEST(addr)
byte __at (0x0000) vmagic[VHEIGHT][VBWIDTH];
byte __at (0x4000) vidmem[VHEIGHT][VBWIDTH];
typedef enum {
SNUL,
SCT0,SCT1,SCT2,SCT3,SCT4,SCT5,SCT6,SCT7,
SF0,SF1,SF2,SF3,SF4,SF5,SF6,SF7,
SSEC,
SKYU,SKYD,
ST0,SJ0,ST1,SJ1,ST2,SJ2,ST3,SJ3,
SP0,SP1,SP2,SP3
} SENTRYCode;
typedef struct {
byte base_ch; // first char
byte frame_x; // frame width
byte frame_y; // frame height
byte pattern_x; // pattern width
byte pattern_y; // pattern height
const byte* chartab; // pointer to char data
} FontDescriptor;
typedef struct {
sbyte xofs, yofs;
byte xsize, ysize;
byte pattern[0];
} PatternBlock;
const FontDescriptor __at(0x206) FNTSYS; // = { 0x20, 8, 8, 1, 7, (byte*)BIGFONT };
const FontDescriptor __at(0x20d) FNTSML; // = { 0xa0, 4, 6, 1, 5, (byte*)SMLFONT };
///// INTERPRETER
typedef struct {
union {
struct {
word iy,ix,de,bc,af,hl;
} w;
struct {
byte iyl,iyh,ixl,ixh,e,d,c,b,f,a,l,h;
} b;
} regs;
byte* params;
} ContextBlock;
#define REG_IY 0x1
#define REG_E 0x2
#define REG_D 0x4
#define REG_C 0x8
#define REG_B 0x10
#define REG_IX 0x20
#define REG_A 0x40
#define REG_HL 0x80
#define REG_DE (REG_D|REG_E)
#define REG_BC (REG_B|REG_C)
#define _IY (ctx->regs.w.iy)
#define _IX (ctx->regs.w.ix)
#define _DE (ctx->regs.w.de)
#define _BC (ctx->regs.w.bc)
#define _AF (ctx->regs.w.af)
#define _HL (ctx->regs.w.hl)
#define _IXL (ctx->regs.b.ixl)
#define _IXH (ctx->regs.b.ixh)
#define _IYL (ctx->regs.b.iyl)
#define _IYH (ctx->regs.b.iyh)
#define _E (ctx->regs.b.e)
#define _D (ctx->regs.b.d)
#define _C (ctx->regs.b.c)
#define _B (ctx->regs.b.b)
#define _A (ctx->regs.b.a)
#define _L (ctx->regs.b.l)
#define _H (ctx->regs.b.h)
typedef void (Routine)();
typedef void (SysRoutine)(ContextBlock *ctx);
typedef struct {
SysRoutine* routine;
byte argmask;
} SysCallEntry;
void SYSCALL(ContextBlock *ctx);

View File

@ -1,10 +1,7 @@
#pragma opt_code_speed
typedef unsigned char byte;
typedef signed char sbyte;
typedef unsigned short word;
typedef signed short sword;
#include "bios.h"
extern byte* MUZPC; // music PC
extern byte* MUZSP; // music SP
@ -68,8 +65,9 @@ void music_update(void) {
} else if (op < 0x88) {
portOut( NEXT() | ((op-0x70)<<8) );
} else if (op == 0x88) {
for (byte i=0; i<8; i++)
for (byte i=0; i<8; i++) {
portOut( NEXT() | (0x17-i) );
}
} else switch (op & 0xf0) {
case 0x90:
VOICES = NEXT();

View File

@ -0,0 +1,244 @@
#include "bios.h"
#pragma opt_code_speed
#define LOCHAR 0x20
#define HICHAR 0x63
static void hline(byte x1, byte x2, byte y, byte pattern) {
byte xb1 = x1/4;
byte xb2 = x2/4;
byte* dest = &vmagic[y][xb1];
signed char nbytes = xb2 - xb1;
hw_magic = M_SHIFT(x1) | M_XOR;
while (--nbytes > 0) {
*dest++ = pattern;
}
if (x2&3) *dest = 0;
// TODO
}
// Fill rect (E,D,C,B) color A
void RECTAN(const ContextBlock *ctx) {
for (byte y=_D; y<_D+_B; y++) {
hline(_E, _E+_C, y, _A);
}
}
const char BIGFONT[HICHAR-LOCHAR+1][7] = {/*{count:68,w:8,h:7,brev:1}*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x20,0x20,0x20,0x20,0x00,0x00,0x20},{0x50,0x50,0x00,0x00,0x00,0x00,0x00},{0x48,0xFC,0x48,0x48,0x48,0xFC,0x48},{0x20,0x78,0x80,0x70,0x08,0xF0,0x20},{0x00,0x48,0x10,0x20,0x40,0x90,0x00},{0x60,0x90,0x60,0xA0,0xA8,0x90,0x68},{0x60,0x60,0x20,0x00,0x00,0x00,0x00},{0x20,0x40,0x40,0x40,0x40,0x40,0x20},{0x40,0x20,0x20,0x20,0x20,0x20,0x40},{0x00,0xA8,0x70,0xF8,0x70,0xA8,0x00},{0x00,0x20,0x20,0xF8,0x20,0x20,0x00},{0x00,0x00,0x00,0x00,0x60,0x20,0x40},{0x00,0x00,0x00,0xF0,0x00,0x00,0x00},{0x00,0x00,0x00,0x00,0x00,0x60,0x60},{0x00,0x08,0x10,0x20,0x40,0x80,0x00},{0x70,0x88,0x88,0xA8,0x88,0x88,0x70},{0x20,0x60,0x20,0x20,0x20,0x20,0x70},{0x70,0x88,0x08,0x30,0x40,0x80,0xF8},{0x70,0x88,0x08,0x70,0x08,0x88,0x70},{0x10,0x30,0x50,0x90,0xF8,0x10,0x10},{0xF8,0x80,0x80,0x70,0x08,0x88,0x70},{0x70,0x88,0x80,0xF0,0x88,0x88,0x70},{0xF8,0x88,0x10,0x20,0x20,0x20,0x20},{0x70,0x88,0x88,0x70,0x88,0x88,0x70},{0x70,0x88,0x88,0x78,0x08,0x88,0x70},{0x00,0x00,0x60,0x00,0x60,0x00,0x00},{0x00,0x00,0x60,0x00,0x60,0x20,0x40},{0x10,0x20,0x40,0x80,0x40,0x20,0x10},{0x00,0x00,0xF8,0x00,0xF8,0x00,0x00},{0x40,0x20,0x10,0x08,0x10,0x20,0x40},{0x70,0x08,0x08,0x30,0x20,0x00,0x20},{0x70,0x88,0xB8,0xA8,0x90,0x80,0x70},{0x70,0x88,0x88,0xF8,0x88,0x88,0x88},{0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0},{0x70,0x88,0x80,0x80,0x80,0x88,0x70},{0xF0,0x88,0x88,0x88,0x88,0x88,0xF0},{0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8},{0xF8,0x80,0x80,0xF0,0x80,0x80,0x80},{0x70,0x88,0x80,0xB0,0x88,0x88,0x70},{0x88,0x88,0x88,0xF8,0x88,0x88,0x88},{0x70,0x20,0x20,0x20,0x20,0x20,0x70},{0x08,0x08,0x08,0x08,0x88,0x88,0x70},{0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88},{0x80,0x80,0x80,0x80,0x80,0x80,0xF8},{0x88,0xD8,0xA8,0x88,0x88,0x88,0x88},{0x88,0xC8,0xA8,0xA8,0x98,0x88,0x88},{0xF8,0x88,0x88,0x88,0x88,0x88,0xF8},{0xF0,0x88,0x88,0xF0,0x80,0x80,0x80},{0x70,0x88,0x88,0xA8,0xA8,0x90,0x68},{0xF0,0x88,0x88,0xF0,0x90,0x90,0x88},{0x70,0x88,0x80,0x70,0x08,0x88,0x70},{0xF8,0x20,0x20,0x20,0x20,0x20,0x20},{0x88,0x88,0x88,0x88,0x88,0x88,0x70},{0x88,0x88,0x88,0x88,0x88,0x50,0x20},{0x88,0x88,0x88,0x88,0xA8,0xD8,0x88},{0x88,0x88,0x50,0x20,0x50,0x88,0x88},{0x88,0x88,0x50,0x20,0x20,0x20,0x20},{0xF8,0x08,0x10,0x20,0x40,0x80,0xF8},{0x70,0x40,0x40,0x40,0x40,0x40,0x70},{0x00,0x80,0x40,0x20,0x10,0x08,0x00},{0x70,0x10,0x10,0x10,0x10,0x10,0x70},{0x20,0x70,0xA8,0x20,0x20,0x20,0x00},{0x00,0x20,0x40,0xF8,0x40,0x20,0x00},{0x00,0x20,0x20,0x20,0xA8,0x70,0x20},{0x00,0x20,0x10,0xF8,0x10,0x20,0x00},{0x00,0x88,0x50,0x20,0x50,0x88,0x00},{0x00,0x20,0x00,0xF8,0x00,0x20,0x00}};
const char SMLFONT[HICHAR-LOCHAR+1][5] = {/*{count:68,w:5,h:5,brev:1}*/
{ 0x00,0x00,0x00,0x00,0x00 },{ 0x40,0x40,0x00,0x40,0x00 },{ 0xA0,0xA0,0x00,0x00,0x00 },{ 0x60,0xF0,0xF0,0x60,0x00 },{ 0x40,0xE0,0xE0,0x40,0x00 },{ 0x90,0x20,0x40,0x90,0x00 },{ 0xC0,0xB0,0xE0,0xD0,0x00 },{ 0x20,0x40,0x00,0x00,0x00 },{ 0x20,0x40,0x40,0x20,0x00 },{ 0x40,0x20,0x20,0x40,0x00 },{ 0x40,0xE0,0x40,0xA0,0x00 },{ 0x00,0x40,0xE0,0x40,0x00 },{ 0x00,0x00,0x00,0x60,0x20 },{ 0x00,0x00,0xE0,0x00,0x00 },{ 0x00,0x00,0x00,0x40,0x00 },{ 0x20,0x20,0x40,0x40,0x00 },{ 0xE0,0xA0,0xA0,0xA0,0xE0 },{ 0xC0,0x40,0x40,0x40,0xE0 },{ 0xE0,0x20,0xE0,0x80,0xE0 },{ 0xE0,0x20,0x60,0x20,0xE0 },{ 0xA0,0xA0,0xE0,0x20,0x20 },{ 0xE0,0x80,0xE0,0x20,0xE0 },{ 0xE0,0x80,0xE0,0xA0,0xE0 },{ 0xE0,0x20,0x40,0x40,0x40 },{ 0xE0,0xA0,0xE0,0xA0,0xE0 },{ 0xE0,0xA0,0xE0,0x20,0xE0 },{ 0x00,0x40,0x00,0x40,0x00 },{ 0x00,0x40,0x00,0x60,0x20 },{ 0x00,0x20,0x40,0x20,0x00 },{ 0x00,0xE0,0x00,0xE0,0x00 },{ 0x00,0x40,0x20,0x40,0x00 },{ 0xE0,0x20,0x60,0x00,0x40 },{ 0xF0,0x90,0x10,0xD0,0xF0 },{ 0x60,0xA0,0xE0,0xA0,0x00 },{ 0xC0,0xE0,0xA0,0xE0,0x00 },{ 0x60,0x80,0x80,0xE0,0x00 },{ 0xC0,0xA0,0xA0,0xC0,0x00 },{ 0xE0,0xC0,0x80,0xE0,0x00 },{ 0xE0,0xC0,0x80,0x80,0x00 },{ 0x60,0x80,0xA0,0xE0,0x00 },{ 0xA0,0xA0,0xE0,0xA0,0x00 },{ 0xE0,0x40,0x40,0xE0,0x00 },{ 0x60,0x20,0xA0,0xE0,0x00 },{ 0xA0,0xC0,0xC0,0xA0,0x00 },{ 0x80,0x80,0x80,0xE0,0x00 },{ 0xE0,0xE0,0xE0,0xA0,0x00 },{ 0xE0,0xA0,0xA0,0xA0,0x00 },{ 0xE0,0xA0,0xA0,0xE0,0x00 },{ 0xE0,0xA0,0xE0,0x80,0x00 },{ 0xE0,0xA0,0xE0,0xF0,0x00 },{ 0xE0,0xA0,0xC0,0xA0,0x00 },{ 0xE0,0x80,0x60,0xE0,0x00 },{ 0xE0,0x40,0x40,0x40,0x00 },{ 0xA0,0xA0,0xA0,0xE0,0x00 },{ 0xA0,0xA0,0xC0,0x80,0x00 },{ 0xA0,0xE0,0xE0,0xE0,0x00 },{ 0xA0,0x40,0xA0,0xA0,0x00 },{ 0xA0,0xE0,0x40,0x40,0x00 },{ 0xE0,0x20,0x40,0xE0,0x00 },{ 0x60,0x40,0x40,0x60,0x00 },{ 0x40,0x40,0x20,0x20,0x00 },{ 0x60,0x20,0x20,0x60,0x00 },{ 0x40,0xA0,0x00,0x00,0x00 },{ 0x00,0x00,0x00,0x00,0xF0 },{ 0x80,0x40,0x00,0x00,0x00 },{ 0x00,0x60,0xA0,0xE0,0x00 },{ 0x80,0xE0,0xA0,0xE0,0x00 },{ 0x00,0x60,0x80,0xE0,0x00 }};
// draw a letter
static byte draw_char(const FontDescriptor* font, byte ch, byte x, byte y, byte op) {
const byte* src = font->chartab + (ch-font->base_ch)*font->pattern_y;
byte* dest = &vmagic[y][x>>2];// destination address
byte magic = M_SHIFT(x) | M_XPAND | (op & 0x30);
// big sizes?
if (op & 0xc0) {
char buf[8]; // expansion buffer
char* mbuf = (buf - 0x4000);// make it magic
byte sc = 1 << (op >> 6); // 2x2 = 2, 4x4 = 4, 8x8 = 8
for (byte i=0; i<font->pattern_y; i++) {
// expand into magic buffer onto stack
hw_magic = M_XPAND;
hw_xpand = 0b1100; // on = 11, off = 00
// 2x2 size
mbuf[1] = mbuf[0] = *src++;
// 4x4 size
if (op & 0x80) {
byte b = buf[0];
mbuf[3] = mbuf[2] = buf[1];
mbuf[1] = mbuf[0] = b;
}
// 8x8 size
if ((op & 0xc0) == 0xc0) {
byte b = buf[0];
mbuf[7] = mbuf[6] = buf[3];
mbuf[5] = mbuf[4] = buf[2];
mbuf[3] = mbuf[2] = buf[1];
mbuf[1] = mbuf[0] = b;
}
// draw to screen (magic, again)
hw_xpand = op & 0xf;
for (byte j=0; j<sc; j++) {
hw_magic = magic; // reset flip flop
EXIT_CLIPDEST(dest);
for (byte k=0; k<sc; k++) {
byte b = buf[k];
*dest++ = b;
*dest++ = b;
}
dest += VBWIDTH-sc*2;
}
}
} else {
hw_xpand = op & 0xf;
for (byte i=0; i<font->pattern_y; i++) {
char b = *src++;
EXIT_CLIPDEST(dest);
hw_magic = magic; // reset flip flop
*dest++ = b; // expand lower nibble -> 1st byte
*dest++ = b; // expand upper nibble -> 2nd byte
*dest++ = 0; // leftover -> 3rd byte
dest += VBWIDTH-3; // we incremented 3 bytes for this line
}
}
return font->frame_x << (op >> 6);
}
#define FONT_IX ((const FontDescriptor*)ctx->regs.w.ix)
static void draw_string(ContextBlock *ctx, const char* str, byte x, byte y, byte op) {
do {
byte ch = *str++;
if (!ch) {
_E = x;
break;
}
if (ch < 0x20) {
x += draw_char(&FNTSYS, ' ', x, y, op); // TODO
} else if (ch < 0x64) {
x += draw_char(&FNTSYS, ch, x, y, op);
} else if (ch >= 0x80) {
x += draw_char(FONT_IX, ch, x, y, op);
} else {
/*
if (ch & 0x10) {
ctx->regs.b.ixl = *str++;
ctx->regs.b.ixh = *str++;
}
if (ch & 0x1)
_E = *str++;
if (ch & 0x2)
_D = *str++;
if (ch & 0x4)
_C = *str++;
*/
// TODO: only can change font
}
} while (1);
}
// String display routine (pass pointer to string)
void STRDIS2(ContextBlock *ctx, char *str) {
byte opts = _C;
byte x = _E;
byte y = _D;
void* fontdesc = (void*) ctx->regs.w.ix;
draw_string(ctx, str, x, y, opts); // TODO: opts
}
// String display routine
void STRDIS(ContextBlock *ctx) {
char* str = (char*) _HL;
STRDIS2(ctx, str);
}
// Character display routine
void CHRDIS(ContextBlock *ctx) {
char chstr[2];
chstr[0] = _A;
chstr[1] = 0;
STRDIS2(ctx, chstr);
}
// BCD routine
const char BCDTAB[17] = "0123456789*+,-./";
// DISNUM - (E.D) x/y (C) options (B) ext (HL) BCD-addr
void DISNUM(ContextBlock *ctx) {
// TODO: options, B
byte x = _E;
byte y = _D;
byte opt = _C;
byte ext = _B;
byte ndigits = ext & 63;
const FontDescriptor* font = (ext&64) ? &FNTSML : &FNTSYS;
byte add = (ext&64) ? 128 : 0;
byte noleadingzero = ext & 128;
byte* pbcd = (byte*) _HL;
pbcd += (ndigits-1)/2;
while (ndigits--) {
byte val = *pbcd;
if (ndigits & 1) {
val >>= 4;
} else {
val &= 15;
pbcd--;
}
x += draw_char(font, BCDTAB[val]+add, x, y, opt);
}
}
// write pattern (E,D,C,B) magic A @ HL
void WRIT(ContextBlock *ctx) {
byte magic = _A;
byte w = _C;
byte h = _B;
byte x = _E;
byte y = _D;
byte* src = (byte*) _HL;
byte* dest = &vmagic[y][0]; // destination address
byte xb = (magic & M_FLOP) ? (39-(x>>2)) : (x>>2);
byte i,j,b;
// iterate through all lines
for (j=0; j<h; j++) {
EXIT_CLIPDEST(dest);
hw_magic = magic;
if (magic & M_XPAND) {
// when XPAND set, write twice as many bytes
for (i=0; i<w*2; i+=2) {
b = *src++;
// when FLOP set, sprite position is also mirrored
if (magic & M_FLOP) {
dest[xb-i] = b;
dest[xb-i-1] = b;
} else {
dest[xb+i] = b;
dest[xb+i+1] = b;
}
}
} else {
for (i=0; i<w; i++) {
// when FLOP set, sprite position is also mirrored
if (magic & M_FLOP) {
dest[xb-i] = *src++;
} else {
dest[xb+i] = *src++;
}
}
}
if (magic & M_FLOP)
dest[xb-i] = 0;
else
dest[xb+i] = 0;
dest += VBWIDTH;
}
}
// write sized pattern (E,D) magic A @ HL
void WRITP(ContextBlock *ctx) {
byte* src = (byte*) _HL;
// get size
_C = *src++;
_B = *src++;
// update src
_HL = (word) src;
WRIT(ctx);
}
// write relative pattern (E,D) magic A @ HL
void WRITR(ContextBlock *ctx) {
byte* src = (byte*) _HL;
// sub offset
_E -= *src++;
_D -= *src++;
// update src
_HL = (word) src;
WRITP(ctx);
}

View File

@ -0,0 +1,144 @@
#include "bios.h"
#include <string.h>
#pragma opt_code_speed
// for SENTRY
extern volatile byte CNT;
extern volatile byte SEMI4S;
extern volatile byte OPOT[4];
extern volatile byte KEYSEX;
extern volatile byte OSW[4];
extern volatile word COLLST;
extern volatile byte SENFLG;
extern volatile byte TIMOUT;
void RCALL(ContextBlock *ctx);
void MCALL(ContextBlock *ctx);
void SENTRY(ContextBlock *ctx) {
byte i;
byte A = SNUL;
byte B = 0;
byte key = 0;
byte val[4];
// joysticks and switches
val[0] = hw_p1ctrl;
val[1] = hw_p2ctrl;
val[2] = hw_p3ctrl;
val[3] = hw_p4ctrl;
for (i=0; i<4; i++) {
if (val[i] != OSW[i]) {
A = SJ0+i*2;
if ((val[i] ^ OSW[i]) & 0x10) {
A++;
}
B = val[i];
}
}
memcpy(OSW, val, 4); // update previous state
// keypad
val[0] = hw_keypad0;
val[1] = hw_keypad1;
val[2] = hw_keypad2;
val[3] = hw_keypad3;
for (i=0; i<4; i++) {
// key down? and with mask
if (val[i] && (val[i] &= ((byte*)_DE)[i])) {
key = i+1;
while (val[i]) {
key += 4;
val[i] >>= 1;
}
}
}
// key up?
if (key && key != KEYSEX) {
B = KEYSEX = key;
A = SKYD;
}
else if (!key && KEYSEX) {
if (KEYSEX & 0x80) {
A = SSEC; // second timer
} else {
A = SKYU;
}
B = 0;
KEYSEX = 0;
}
// pots
val[0] = hw_p1pot;
val[1] = hw_p2pot;
val[2] = hw_p3pot;
val[3] = hw_p4pot;
for (i=0; i<4; i++) {
if (val[i] != OPOT[i]) {
A = SP0+i;
B = val[i];
}
}
memcpy(OPOT, val, 4); // update previous state
// semiphores
if (SEMI4S) {
B = SEMI4S;
for (i=7; i>=0; i--) {
if (B & 0x80) {
A = SF0+i;
SEMI4S ^= 1 << i;
break;
}
B <<= 1;
}
}
// counters
if (SENFLG) {
B = SENFLG;
for (i=7; i>=0; i--) {
if (B & 0x80) {
A = SF0+i;
SENFLG ^= 1 << i;
break;
}
B <<= 1;
}
}
// clear timeout counter (TODO)
if (A >= SKYU) {
TIMOUT = 0xff;
}
_A = A;
_B = B;
}
void DOIT(ContextBlock *ctx) {
byte* list = (byte*) _HL;
byte code = _A;
byte op;
while ((op = *list) < 0xc0) {
if ((op & 0x3f) == code) {
_HL = *(word*)(list+1);
switch (op & 0xc0) {
// TODO: JMP
case 0x00:
// RCALL
case 0x40:
RCALL(ctx);
break;
// MCALL
case 0x80:
MCALL(ctx);
break;
}
return;
}
list += 3;
}
}
void DOITB(ContextBlock *ctx) {
_A = _B;
DOIT(ctx);
}

View File

@ -11,7 +11,6 @@ void set_palette(byte palette[8]) __z88dk_fastcall {
__asm
ld bc,#0x80b ; B -> 8, C -> 0xb
otir ; write C bytes from HL to port[B]
ret ; return
__endasm;
}
@ -22,7 +21,6 @@ void set_sound_registers(byte regs[8]) __z88dk_fastcall {
__asm
ld bc,#0x818 ; B -> 8, C -> 0x18
otir ; write C bytes from HL to port[B]
ret ; return
__endasm;
}

View File

@ -17,6 +17,8 @@ Start:
ldir ; clear RAM
; initialize INITIALIZED segment
ld BC, #l__INITIALIZER
ld a,c
or b
jp z,.nomeminit
ld A, B
ld DE, #s__INITIALIZED

View File

@ -27,8 +27,26 @@ const byte BALL[] = {
0b01111000,
};
const byte BALL2[] = {
0, 0, // x and y offset
1, 6, // width (bytes) and height (lines)
/*{w:16,h:6,brev:1}*/
0b1111000,
0b11011100,
0b10111000,
0b110100,
0b11100000,
0b1111000,
0b1000000,
0b11010100,
0b10111100,
0b10110100,
0b11111000,
0b1111000,
};
// BCD number
static byte bcdnum[3] = {0x56,0x34,0x12};
byte bcdnum[3] = {0x56,0x34,0x12};
const byte bcdinc[3] = {0x01,0x00,0x00};
const byte keypadMask[4] = { 0x3f,0x3f,0x3f,0x3f };

View File

@ -967,11 +967,11 @@ class PixEditor extends Viewer {
this.setPixel(pos.x, pos.y, this.currgba);
dragging = true;
$(document).mouseup( (e) => {
$(document).off('mouseup');
var pos = this.getPositionFromEvent(e);
this.setPixel(pos.x, pos.y, dragcol);
dragging = false;
this.commit();
$(document).off('mouseup');
});
})
.mousemove( (e) => {

View File

@ -477,6 +477,7 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
/////
// TODO: https://github.com/mamedev/mame/blob/master/src/devices/sound/astrocde.cpp
class AstrocadeAudio extends AY38910_Audio {
setACRegister(addr : number, val : number) {
addr &= 0x7;

View File

@ -242,6 +242,7 @@ var PLATFORM_PARAMS = {
//{name:'Cart ROM',start:0x2000,size:0x2000,type:'rom'},
//{name:'Magic RAM',start:0x0,size:0x4000,type:'ram'},
{name:'Screen RAM',start:0x4000,size:0x1000,type:'ram'},
{name:'BIOS Variables',start:0x4fce,size:0x5000-0x4fce,type:'ram'},
],
},
'astrocade-arcade': {
@ -1133,26 +1134,33 @@ function hexToArray(s, ofs) {
return arr;
}
function parseIHX(ihx, rom_start, rom_size) {
function parseIHX(ihx, rom_start, rom_size, errors) {
var output = new Uint8Array(new ArrayBuffer(rom_size));
var high_size = 0;
for (var s of ihx.split("\n")) {
if (s[0] == ':') {
var arr = hexToArray(s, 1);
var count = arr[0];
var address = (arr[1]<<8) + arr[2] - rom_start;
var rectype = arr[3];
//console.log(rectype,address.toString(16),count,arr);
if (rectype == 0) {
for (var i=0; i<count; i++) {
var b = arr[4+i];
output[i+address] = b;
}
if (i+address > high_size) high_size = i+address;
} else if (rectype == 1) {
return output;
break;
} else {
console.log(s); // unknown record type
}
}
}
// TODO: return ROM anyway?
if (high_size > rom_size) {
//errors.push({line:0, msg:"ROM size too large: 0x" + high_size.toString(16) + " > 0x" + rom_size.toString(16)});
}
return output;
}
@ -1268,6 +1276,10 @@ function linkSDLDZ80(step:BuildStep)
if (!anyTargetChanged(step, ["main.ihx", "main.noi"]))
return;
var binout = parseIHX(hexout, params.rom_start!==undefined?params.rom_start:params.code_start, params.rom_size, errors);
if (errors.length) {
return {errors:errors};
}
var listings = {};
for (var fn of step.files) {
if (fn.endsWith('.lst')) {
@ -1304,7 +1316,8 @@ function linkSDLDZ80(step:BuildStep)
let segsize = symbolmap['l__'+seg]; // l__SEG
if (segstart >= 0 && segsize > 0) {
var type = null;
if (['CODE','INITIALIZER','GSINIT','GSFINAL'].includes(seg)) type = 'rom';
if (['INITIALIZER','GSINIT','GSFINAL'].includes(seg)) type = 'rom';
else if (seg.startsWith('CODE')) type = 'rom';
else if (['DATA','INITIALIZED'].includes(seg)) type = 'ram';
if (type == 'rom' || segstart > 0) // ignore HEADER0, CABS0, etc (TODO?)
segments.push({name:seg, start:segstart, size:segsize, type:type});
@ -1312,7 +1325,7 @@ function linkSDLDZ80(step:BuildStep)
}
}
return {
output:parseIHX(hexout, params.rom_start!==undefined?params.rom_start:params.code_start, params.rom_size),
output:binout,
listings:listings,
errors:errors,
symbolmap:symbolmap,

View File

@ -301,7 +301,7 @@ describe('Worker', function() {
});
it('should compile vicdual skeleton', function(done) {
var files = ['skeleton.sdcc', 'cp437.c'];
compileFiles('sdcc', files, 'vicdual', done, 16416, [0,45], 0); // TODO?
compileFiles('sdcc', files, 'vicdual', done, 16416, [2048,45], 0); // TODO?
});
it('should compile apple2 skeleton with CC65', function(done) {
var csource = ab2str(fs.readFileSync('presets/apple2/skeleton.cc65'));