mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-06-14 00:29:35 +00:00
astrocade: split bios into .c files; check rom_size on sdcc targets (not yet)
This commit is contained in:
parent
50421a69f3
commit
b3861f3361
|
@ -35,7 +35,6 @@ TODO:
|
||||||
- go to error in include files
|
- go to error in include files
|
||||||
- online tools for music etc
|
- online tools for music etc
|
||||||
- text log debugging script
|
- text log debugging script
|
||||||
- NES crt should mark raster pos when debugging
|
|
||||||
- intro/help text for each platform
|
- intro/help text for each platform
|
||||||
- vscode/atom extension?
|
- vscode/atom extension?
|
||||||
- VCS asm library
|
- VCS asm library
|
||||||
|
@ -63,7 +62,10 @@ TODO:
|
||||||
- what if .c and .s names collide?
|
- what if .c and .s names collide?
|
||||||
- maybe put stuff in examples/ dir?
|
- maybe put stuff in examples/ dir?
|
||||||
- error msg when #link doesn't work
|
- 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
|
- live coding URL
|
||||||
- resize memory browser when vertical div resize
|
- resize memory browser when vertical div resize
|
||||||
- preroll the emulator so optimizer does its thing before loading rom
|
- 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
|
- show player controls for each platform, allow touch support, navigator.getGamepads
|
||||||
- better undo/diff for mistakes?
|
- better undo/diff for mistakes?
|
||||||
- ide bug/feature visualizer for sponsors
|
- ide bug/feature visualizer for sponsors
|
||||||
- optimization flags for sdcc (oldralloc)
|
|
||||||
- global undo/redo at checkpoints (when rom changes)
|
- global undo/redo at checkpoints (when rom changes)
|
||||||
- pulldown shows wrong file if preset not present
|
- pulldown shows wrong file if preset not present
|
||||||
- landscape mode for arcade ports
|
- landscape mode for arcade ports
|
||||||
|
@ -104,7 +105,6 @@ TODO:
|
||||||
- parse .incbin directives?
|
- parse .incbin directives?
|
||||||
- can't replace in hex directives
|
- can't replace in hex directives
|
||||||
- should maybe use same single-canvas editor for map + char editor
|
- 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?
|
- crt0.s compiled each time?
|
||||||
- debug highlight doesn't go away when debugging -> running
|
- debug highlight doesn't go away when debugging -> running
|
||||||
- show breakpoint of PC or highest address on stack
|
- show breakpoint of PC or highest address on stack
|
||||||
|
@ -133,6 +133,7 @@ TODO:
|
||||||
- nes debug view toolbar
|
- nes debug view toolbar
|
||||||
- support NES_HEADER_16K?
|
- support NES_HEADER_16K?
|
||||||
- PPU/TIA register write visualization
|
- PPU/TIA register write visualization
|
||||||
|
- NES crt should mark raster pos when debugging
|
||||||
- vcs
|
- vcs
|
||||||
- vcs sound continues when paused
|
- vcs sound continues when paused
|
||||||
- vcs: INPTx needs to be added to control state
|
- vcs: INPTx needs to be added to control state
|
||||||
|
@ -157,6 +158,7 @@ TODO:
|
||||||
- support projects with subdirectories, file list?
|
- support projects with subdirectories, file list?
|
||||||
- emulator needs reset shortcut for nes
|
- emulator needs reset shortcut for nes
|
||||||
- switching platform of a repo?
|
- switching platform of a repo?
|
||||||
|
- make sure to flatten subdirs
|
||||||
- ctrl+alt+l on ubuntu locks screen
|
- ctrl+alt+l on ubuntu locks screen
|
||||||
|
|
||||||
WEB WORKER FORMAT
|
WEB WORKER FORMAT
|
||||||
|
|
|
@ -21,86 +21,18 @@ See: http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
// music processor
|
// music processor
|
||||||
//#link "bmusic.c"
|
//#link "bmusic.c"
|
||||||
|
|
||||||
|
// input
|
||||||
|
//#link "input.c"
|
||||||
|
|
||||||
|
// graphics
|
||||||
|
//#link "gfx.c"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "bios.h"
|
||||||
|
|
||||||
// uncomment to make code better, but slower compile
|
// uncomment to make code better, but slower compile
|
||||||
//#pragma opt_code_speed
|
#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];
|
|
||||||
|
|
||||||
// start @ $4FCE
|
// start @ $4FCE
|
||||||
volatile word MUZPC; // music PC
|
volatile word MUZPC; // music PC
|
||||||
|
@ -136,35 +68,7 @@ byte SENFLG; // sentry control
|
||||||
byte* UMARGT; // user mask table (-64 bytes)
|
byte* UMARGT; // user mask table (-64 bytes)
|
||||||
word* USERTB; // user routine table (-128 bytes)
|
word* USERTB; // user routine table (-128 bytes)
|
||||||
|
|
||||||
typedef enum {
|
// from bmusic.c
|
||||||
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 };
|
|
||||||
|
|
||||||
|
|
||||||
extern void music_update(void);
|
extern void music_update(void);
|
||||||
|
|
||||||
// INTERRUPT HANDLERS
|
// INTERRUPT HANDLERS
|
||||||
|
@ -231,59 +135,6 @@ void TIMEY() {
|
||||||
void TIMEX() {
|
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) {
|
void INTPC(ContextBlock *ctx) {
|
||||||
while (ctx->params[0] != 2) { // 2 = exit
|
while (ctx->params[0] != 2) { // 2 = exit
|
||||||
SYSCALL(ctx);
|
SYSCALL(ctx);
|
||||||
|
@ -302,7 +153,10 @@ void RCALL(ContextBlock *ctx) {
|
||||||
|
|
||||||
// start interpreting at HL
|
// start interpreting at HL
|
||||||
void MCALL(ContextBlock *ctx) {
|
void MCALL(ContextBlock *ctx) {
|
||||||
ctx; // TODO
|
ctx->params = (byte*)_HL;
|
||||||
|
while (ctx->params[0] != 8) { // 8 = MRET
|
||||||
|
SYSCALL(ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// exit MCALL loop
|
// exit MCALL loop
|
||||||
|
@ -369,17 +223,19 @@ void SETOUT(ContextBlock *ctx) {
|
||||||
hw_inmod = _A;
|
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)
|
// sets color palettes from (HL)
|
||||||
void COLSET(ContextBlock *ctx) {
|
void COLSET(ContextBlock *ctx) {
|
||||||
byte* palette = (byte*) _HL;
|
set_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++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stores A in BC bytes starting at location DE.
|
// Stores A in BC bytes starting at location DE.
|
||||||
|
@ -390,248 +246,6 @@ void FILL(ContextBlock *ctx) {
|
||||||
memset(dest, val, count);
|
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() {
|
void wait_vsync() {
|
||||||
byte x = TMR60;
|
byte x = TMR60;
|
||||||
while (x == TMR60) ; // wait until timer/60 changes
|
while (x == TMR60) ; // wait until timer/60 changes
|
||||||
|
@ -694,100 +308,19 @@ void RANGED(ContextBlock *ctx) {
|
||||||
|
|
||||||
// input
|
// input
|
||||||
|
|
||||||
void SENTRY(ContextBlock *ctx) {
|
const byte KCTASC_TABLE[25] = {
|
||||||
byte i;
|
0x00,
|
||||||
byte A = SNUL;
|
0x43, 0x5e, 0x5c, 0x25, 0x52, 0x53, 0x3b, 0x2f,
|
||||||
byte B = 0;
|
0x37, 0x38, 0x39, 0x2a, 0x34, 0x35, 0x36, 0x2d,
|
||||||
byte key = 0;
|
0x31, 0x32, 0x33, 0x2b, 0x26, 0x30, 0x2e, 0x3d
|
||||||
byte val[4];
|
};
|
||||||
// joysticks and switches
|
|
||||||
val[0] = hw_p1ctrl;
|
void KCTASC(ContextBlock *ctx) {
|
||||||
val[1] = hw_p2ctrl;
|
_A = KCTASC_TABLE[_B];
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// music
|
||||||
|
|
||||||
void BMUSIC(ContextBlock *ctx) {
|
void BMUSIC(ContextBlock *ctx) {
|
||||||
VOICES = _A;
|
VOICES = _A;
|
||||||
MUZPC = _HL;
|
MUZPC = _HL;
|
||||||
|
@ -800,6 +333,22 @@ void EMUSIC(ContextBlock *ctx) {
|
||||||
VOICES = 0;
|
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] = {
|
const SysCallEntry SYSCALL_TABLE[64] = {
|
||||||
/* 0 */
|
/* 0 */
|
||||||
{ &INTPC, 0 },
|
{ &INTPC, 0 },
|
||||||
|
@ -840,11 +389,11 @@ const SysCallEntry SYSCALL_TABLE[64] = {
|
||||||
/* 60 */
|
/* 60 */
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
{ 0, 0 },
|
{ &KCTASC, 0 },
|
||||||
{ &SENTRY, REG_DE },
|
{ &SENTRY, REG_DE },
|
||||||
{ 0, 0 },
|
{ &DOIT, REG_HL },
|
||||||
/* 70 */
|
/* 70 */
|
||||||
{ 0, 0 },
|
{ &DOITB, REG_HL },
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
|
|
158
presets/astrocade-bios/bios.h
Normal file
158
presets/astrocade-bios/bios.h
Normal 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);
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
|
|
||||||
#pragma opt_code_speed
|
#pragma opt_code_speed
|
||||||
|
|
||||||
typedef unsigned char byte;
|
#include "bios.h"
|
||||||
typedef signed char sbyte;
|
|
||||||
typedef unsigned short word;
|
|
||||||
typedef signed short sword;
|
|
||||||
|
|
||||||
extern byte* MUZPC; // music PC
|
extern byte* MUZPC; // music PC
|
||||||
extern byte* MUZSP; // music SP
|
extern byte* MUZSP; // music SP
|
||||||
|
@ -68,8 +65,9 @@ void music_update(void) {
|
||||||
} else if (op < 0x88) {
|
} else if (op < 0x88) {
|
||||||
portOut( NEXT() | ((op-0x70)<<8) );
|
portOut( NEXT() | ((op-0x70)<<8) );
|
||||||
} else if (op == 0x88) {
|
} else if (op == 0x88) {
|
||||||
for (byte i=0; i<8; i++)
|
for (byte i=0; i<8; i++) {
|
||||||
portOut( NEXT() | (0x17-i) );
|
portOut( NEXT() | (0x17-i) );
|
||||||
|
}
|
||||||
} else switch (op & 0xf0) {
|
} else switch (op & 0xf0) {
|
||||||
case 0x90:
|
case 0x90:
|
||||||
VOICES = NEXT();
|
VOICES = NEXT();
|
||||||
|
|
244
presets/astrocade-bios/gfx.c
Normal file
244
presets/astrocade-bios/gfx.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
144
presets/astrocade-bios/input.c
Normal file
144
presets/astrocade-bios/input.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ void set_palette(byte palette[8]) __z88dk_fastcall {
|
||||||
__asm
|
__asm
|
||||||
ld bc,#0x80b ; B -> 8, C -> 0xb
|
ld bc,#0x80b ; B -> 8, C -> 0xb
|
||||||
otir ; write C bytes from HL to port[B]
|
otir ; write C bytes from HL to port[B]
|
||||||
ret ; return
|
|
||||||
__endasm;
|
__endasm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +21,6 @@ void set_sound_registers(byte regs[8]) __z88dk_fastcall {
|
||||||
__asm
|
__asm
|
||||||
ld bc,#0x818 ; B -> 8, C -> 0x18
|
ld bc,#0x818 ; B -> 8, C -> 0x18
|
||||||
otir ; write C bytes from HL to port[B]
|
otir ; write C bytes from HL to port[B]
|
||||||
ret ; return
|
|
||||||
__endasm;
|
__endasm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ Start:
|
||||||
ldir ; clear RAM
|
ldir ; clear RAM
|
||||||
; initialize INITIALIZED segment
|
; initialize INITIALIZED segment
|
||||||
ld BC, #l__INITIALIZER
|
ld BC, #l__INITIALIZER
|
||||||
|
ld a,c
|
||||||
|
or b
|
||||||
jp z,.nomeminit
|
jp z,.nomeminit
|
||||||
ld A, B
|
ld A, B
|
||||||
ld DE, #s__INITIALIZED
|
ld DE, #s__INITIALIZED
|
||||||
|
|
|
@ -27,8 +27,26 @@ const byte BALL[] = {
|
||||||
0b01111000,
|
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
|
// BCD number
|
||||||
static byte bcdnum[3] = {0x56,0x34,0x12};
|
byte bcdnum[3] = {0x56,0x34,0x12};
|
||||||
const byte bcdinc[3] = {0x01,0x00,0x00};
|
const byte bcdinc[3] = {0x01,0x00,0x00};
|
||||||
const byte keypadMask[4] = { 0x3f,0x3f,0x3f,0x3f };
|
const byte keypadMask[4] = { 0x3f,0x3f,0x3f,0x3f };
|
||||||
|
|
||||||
|
|
|
@ -967,11 +967,11 @@ class PixEditor extends Viewer {
|
||||||
this.setPixel(pos.x, pos.y, this.currgba);
|
this.setPixel(pos.x, pos.y, this.currgba);
|
||||||
dragging = true;
|
dragging = true;
|
||||||
$(document).mouseup( (e) => {
|
$(document).mouseup( (e) => {
|
||||||
|
$(document).off('mouseup');
|
||||||
var pos = this.getPositionFromEvent(e);
|
var pos = this.getPositionFromEvent(e);
|
||||||
this.setPixel(pos.x, pos.y, dragcol);
|
this.setPixel(pos.x, pos.y, dragcol);
|
||||||
dragging = false;
|
dragging = false;
|
||||||
this.commit();
|
this.commit();
|
||||||
$(document).off('mouseup');
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.mousemove( (e) => {
|
.mousemove( (e) => {
|
||||||
|
|
|
@ -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 {
|
class AstrocadeAudio extends AY38910_Audio {
|
||||||
setACRegister(addr : number, val : number) {
|
setACRegister(addr : number, val : number) {
|
||||||
addr &= 0x7;
|
addr &= 0x7;
|
||||||
|
|
|
@ -242,6 +242,7 @@ var PLATFORM_PARAMS = {
|
||||||
//{name:'Cart ROM',start:0x2000,size:0x2000,type:'rom'},
|
//{name:'Cart ROM',start:0x2000,size:0x2000,type:'rom'},
|
||||||
//{name:'Magic RAM',start:0x0,size:0x4000,type:'ram'},
|
//{name:'Magic RAM',start:0x0,size:0x4000,type:'ram'},
|
||||||
{name:'Screen RAM',start:0x4000,size:0x1000,type:'ram'},
|
{name:'Screen RAM',start:0x4000,size:0x1000,type:'ram'},
|
||||||
|
{name:'BIOS Variables',start:0x4fce,size:0x5000-0x4fce,type:'ram'},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'astrocade-arcade': {
|
'astrocade-arcade': {
|
||||||
|
@ -1133,26 +1134,33 @@ function hexToArray(s, ofs) {
|
||||||
return arr;
|
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 output = new Uint8Array(new ArrayBuffer(rom_size));
|
||||||
|
var high_size = 0;
|
||||||
for (var s of ihx.split("\n")) {
|
for (var s of ihx.split("\n")) {
|
||||||
if (s[0] == ':') {
|
if (s[0] == ':') {
|
||||||
var arr = hexToArray(s, 1);
|
var arr = hexToArray(s, 1);
|
||||||
var count = arr[0];
|
var count = arr[0];
|
||||||
var address = (arr[1]<<8) + arr[2] - rom_start;
|
var address = (arr[1]<<8) + arr[2] - rom_start;
|
||||||
var rectype = arr[3];
|
var rectype = arr[3];
|
||||||
|
//console.log(rectype,address.toString(16),count,arr);
|
||||||
if (rectype == 0) {
|
if (rectype == 0) {
|
||||||
for (var i=0; i<count; i++) {
|
for (var i=0; i<count; i++) {
|
||||||
var b = arr[4+i];
|
var b = arr[4+i];
|
||||||
output[i+address] = b;
|
output[i+address] = b;
|
||||||
}
|
}
|
||||||
|
if (i+address > high_size) high_size = i+address;
|
||||||
} else if (rectype == 1) {
|
} else if (rectype == 1) {
|
||||||
return output;
|
break;
|
||||||
} else {
|
} else {
|
||||||
console.log(s); // unknown record type
|
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;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1268,6 +1276,10 @@ function linkSDLDZ80(step:BuildStep)
|
||||||
if (!anyTargetChanged(step, ["main.ihx", "main.noi"]))
|
if (!anyTargetChanged(step, ["main.ihx", "main.noi"]))
|
||||||
return;
|
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 = {};
|
var listings = {};
|
||||||
for (var fn of step.files) {
|
for (var fn of step.files) {
|
||||||
if (fn.endsWith('.lst')) {
|
if (fn.endsWith('.lst')) {
|
||||||
|
@ -1304,7 +1316,8 @@ function linkSDLDZ80(step:BuildStep)
|
||||||
let segsize = symbolmap['l__'+seg]; // l__SEG
|
let segsize = symbolmap['l__'+seg]; // l__SEG
|
||||||
if (segstart >= 0 && segsize > 0) {
|
if (segstart >= 0 && segsize > 0) {
|
||||||
var type = null;
|
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';
|
else if (['DATA','INITIALIZED'].includes(seg)) type = 'ram';
|
||||||
if (type == 'rom' || segstart > 0) // ignore HEADER0, CABS0, etc (TODO?)
|
if (type == 'rom' || segstart > 0) // ignore HEADER0, CABS0, etc (TODO?)
|
||||||
segments.push({name:seg, start:segstart, size:segsize, type:type});
|
segments.push({name:seg, start:segstart, size:segsize, type:type});
|
||||||
|
@ -1312,7 +1325,7 @@ function linkSDLDZ80(step:BuildStep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
output:parseIHX(hexout, params.rom_start!==undefined?params.rom_start:params.code_start, params.rom_size),
|
output:binout,
|
||||||
listings:listings,
|
listings:listings,
|
||||||
errors:errors,
|
errors:errors,
|
||||||
symbolmap:symbolmap,
|
symbolmap:symbolmap,
|
||||||
|
|
|
@ -301,7 +301,7 @@ describe('Worker', function() {
|
||||||
});
|
});
|
||||||
it('should compile vicdual skeleton', function(done) {
|
it('should compile vicdual skeleton', function(done) {
|
||||||
var files = ['skeleton.sdcc', 'cp437.c'];
|
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) {
|
it('should compile apple2 skeleton with CC65', function(done) {
|
||||||
var csource = ab2str(fs.readFileSync('presets/apple2/skeleton.cc65'));
|
var csource = ab2str(fs.readFileSync('presets/apple2/skeleton.cc65'));
|
||||||
|
|
Loading…
Reference in New Issue
Block a user