mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-22 14:33:51 +00:00
617 lines
20 KiB
C
617 lines
20 KiB
C
|
|
|
|
#define TEST
|
|
|
|
#include <string.h>
|
|
|
|
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
|
|
|
|
#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))
|
|
|
|
/// GRAPHICS FUNCTIONS
|
|
|
|
#define VHEIGHT 89 // 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
|
|
|
|
byte __at (0x0000) vmagic[VHEIGHT][VBWIDTH];
|
|
byte __at (0x4000) vidmem[VHEIGHT][VBWIDTH];
|
|
|
|
// Used by MUSIC PROCESSOR:
|
|
volatile word MUZPC; // $4FCE // MUSic Program Counter
|
|
volatile word MUZSP; // $4FD0 // MUSic Stack Pointer
|
|
volatile byte PVOLAB; // $4FD2 // Preset VOLume for tones A and B
|
|
volatile byte PVOLMC; // $4FD3 // Preset VOLuMe for tone C and Noise Mode
|
|
volatile byte VOICES; // $4FD4 // music VOICES mask
|
|
// COUNTER TIMERS (used by DECCTS,ACTINT,CTIMER):
|
|
volatile byte CT[8];
|
|
// Used by SENTRY to track controls:
|
|
volatile byte CNT; // $4FDD // Counter update & Number Tracking
|
|
volatile byte SEMI4S; // $4FDE // SEMAPHORE flag bitS
|
|
volatile byte OPOT[4]; // $4FDF // Old POT 0 tracking byte
|
|
volatile byte KEYSEX; // $4FE3 // KEYS-EX tracking byte
|
|
volatile byte OSW[4]; // $4FE4 // Old SWitch 0 tracking byte
|
|
volatile word COLLST; // $4FE8 // COLset LaST address for P.B. A
|
|
// Used by STIMER:
|
|
volatile byte DURAT; // $4FEA // note DURATion
|
|
volatile byte TMR60; // $4FEB // TiMeR for SIXTY'ths of sec
|
|
volatile byte TIMOUT; // $4FEC // TIMer for blackOUT
|
|
volatile byte GTSECS; // $4FED // Game Time SECondS
|
|
volatile byte GTMINS; // $4FEE // Game Time MINuteS
|
|
// Used by MENU:
|
|
long RANSHT; // $4FEF // RANdom number SHifT register
|
|
byte NUMPLY; // $4FF3 // NUMber of PLaYers
|
|
byte ENDSCR[3]; // $4FF4 // END SCoRe to 'play to'
|
|
byte MRLOCK; // $4FF7 // Magic Register LOCK out flag
|
|
byte GAMSTB; // $4FF8 // GAMe STatus Byte
|
|
byte PRIOR; // $4FF9 // PRIOR music protect flag
|
|
byte SENFLG; // $4FFA // SENtry control seizure FLaG
|
|
// User UPI Routines, even numbers from $80 to $FE ( + 1 for SUCK):
|
|
byte* UMARGT; // $4FFB // User Mask ARGument Table + (routine / 2)
|
|
word* USERTB; // $4FFD // USER Table Base + routine = JumP address
|
|
|
|
// start routine @ 0x0
|
|
void bios_start() __naked {
|
|
__asm
|
|
DI ; disable interrupts
|
|
LD SP,#0x4fce ; position stack below BIOS vars
|
|
LD HL,#0x2000
|
|
LD A,(HL) ; A <- mem[0x2000]
|
|
CP #0x55 ; found sentinel byte? ($55)
|
|
JP Z,FoundSentinel ; yes, load program
|
|
#ifndef TEST
|
|
JP 0x2000 ; jump to $2000
|
|
#else
|
|
JP _main ; jump to test program
|
|
#endif
|
|
FoundSentinel:
|
|
CALL _bios_init ; misc. bios init routines
|
|
LD HL,#0x2005 ; cartridge start vector
|
|
LD A,(HL)
|
|
INC HL
|
|
LD H,(HL)
|
|
LD L,A
|
|
JP (HL) ; jump to cart start vector
|
|
.ds 0x38 - 0x1b ; eat up space until 0x38
|
|
__endasm;
|
|
}
|
|
|
|
void interrupt_0x38() __naked {
|
|
__asm
|
|
push hl
|
|
push af
|
|
push bc
|
|
push de
|
|
push ix
|
|
push iy
|
|
ld hl,#0
|
|
add hl,sp
|
|
push hl ; HL points to context block
|
|
call _SYSCALL ; syscall handler
|
|
pop hl
|
|
pop iy
|
|
pop ix
|
|
pop de
|
|
pop bc
|
|
pop af
|
|
pop hl
|
|
ret
|
|
__endasm;
|
|
}
|
|
|
|
void _predope() __naked {
|
|
__asm
|
|
.ds 0x200-0x52 ; skip to 0x200
|
|
__endasm;
|
|
}
|
|
|
|
// DOPE vector @ 0x200
|
|
void DOPE() __naked {
|
|
__asm
|
|
JP _STIMER
|
|
JP _CTIMER
|
|
.db 0x20, 8, 8, 1, 7 ; Font descriptor (big font)
|
|
.dw _BIGFONT
|
|
.db 0xa0, 4, 6, 1, 5 ; Font descriptor (small font)
|
|
.dw _SMLFONT
|
|
__endasm;
|
|
}
|
|
|
|
typedef struct {
|
|
byte base_ch;
|
|
byte frame_x;
|
|
byte frame_y;
|
|
byte pattern_x;
|
|
byte pattern_y;
|
|
const byte* chartab;
|
|
} FontDescriptor;
|
|
|
|
#define LOCHAR 32
|
|
#define HICHAR 127
|
|
|
|
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 };
|
|
|
|
void hw_interrupt() __interrupt {
|
|
CT[0]++;
|
|
CT[1]++;
|
|
CT[2]++;
|
|
CT[3]++;
|
|
if (++TMR60 == 60) {
|
|
TMR60 = 0;
|
|
if (++GTSECS == 60) {
|
|
GTMINS++;
|
|
}
|
|
}
|
|
}
|
|
|
|
const void* const actint_vec = &hw_interrupt;
|
|
|
|
void STIMER() {
|
|
}
|
|
|
|
void CTIMER() {
|
|
}
|
|
|
|
void bios_init() {
|
|
memset((void*)0x4fce, 0, 0x5000-0x4fce);
|
|
}
|
|
|
|
///// 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)
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
// never called, hopefully
|
|
void EXIT(ContextBlock *ctx) {
|
|
ctx;
|
|
}
|
|
|
|
// jumps to HL
|
|
void RCALL(ContextBlock *ctx) {
|
|
((Routine*)ctx->regs.w.hl)();
|
|
}
|
|
|
|
// start interpreting at HL
|
|
void MCALL(ContextBlock *ctx) {
|
|
ctx; // TODO
|
|
}
|
|
|
|
// exit MCALL loop
|
|
void MRET(ContextBlock *ctx) {
|
|
ctx; // TODO
|
|
}
|
|
|
|
// jump within MCALL
|
|
void MJUMP(ContextBlock *ctx) {
|
|
ctx->params = (byte*) ctx->regs.w.hl; // TODO?
|
|
}
|
|
|
|
void suckParams(ContextBlock *ctx, byte argmask) {
|
|
byte* dest = (byte*) ctx;
|
|
byte* src = ctx->params;
|
|
if (argmask & REG_IX) {
|
|
ctx->regs.b.ixl = *src++;
|
|
ctx->regs.b.ixh = *src++;
|
|
}
|
|
if (argmask & REG_E)
|
|
ctx->regs.b.e = *src++;
|
|
if (argmask & REG_D)
|
|
ctx->regs.b.d = *src++;
|
|
if (argmask & REG_C)
|
|
ctx->regs.b.c = *src++;
|
|
if (argmask & REG_B)
|
|
ctx->regs.b.b = *src++;
|
|
if (argmask & REG_A)
|
|
ctx->regs.b.a = *src++;
|
|
if (argmask & REG_HL) {
|
|
ctx->regs.b.l = *src++;
|
|
ctx->regs.b.h = *src++;
|
|
}
|
|
ctx->params = src;
|
|
}
|
|
|
|
void SUCK(ContextBlock* ctx) {
|
|
suckParams(ctx, ctx->regs.b.b);
|
|
}
|
|
|
|
void ACTINT(ContextBlock *ctx) {
|
|
ctx;
|
|
hw_inlin = 200;
|
|
hw_infbk = (byte) &actint_vec;
|
|
hw_inmod = 8;
|
|
__asm
|
|
LD A,#0x2 ; I = 0x200
|
|
LD I,A
|
|
IM 2 ; mode 2
|
|
EI ; enable interrupts
|
|
__endasm;
|
|
}
|
|
|
|
// Outputs D to port 0A, B to port 09, A to port 0E.
|
|
void SETOUT(ContextBlock *ctx) {
|
|
hw_verbl = ctx->regs.b.d;
|
|
hw_horcb = ctx->regs.b.b;
|
|
hw_inmod = ctx->regs.b.a;
|
|
}
|
|
|
|
// sets color palettes from (HL)
|
|
void COLSET(ContextBlock *ctx) {
|
|
byte* palette = (byte*) ctx->regs.w.hl;
|
|
hw_col0r = *palette++;
|
|
hw_col1r = *palette++;
|
|
hw_col2r = *palette++;
|
|
hw_col3r = *palette++;
|
|
hw_col0l = *palette++;
|
|
hw_col1l = *palette++;
|
|
hw_col2l = *palette++;
|
|
hw_col3l = *palette++;
|
|
}
|
|
|
|
// Stores A in BC bytes starting at location DE.
|
|
void FILL(ContextBlock *ctx) {
|
|
byte* dest = (byte*) ctx->regs.w.de;
|
|
word count = ctx->regs.w.bc;
|
|
byte val = ctx->regs.b.a;
|
|
memset(dest, val, count);
|
|
}
|
|
|
|
const char BIGFONT[HICHAR-LOCHAR+1][7] = {
|
|
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00 },{ 0x00,0x20,0x20,0x20,0x00,0x20,0x00 },{ 0x50,0x50,0x50,0x00,0x00,0x00,0x00 },{ 0x00,0x50,0xF8,0x50,0xF8,0x50,0x00 },{ 0x00,0xF8,0xA0,0xF8,0x28,0xF8,0x00 },{ 0x00,0xC8,0xD0,0x20,0x58,0x98,0x00 },{ 0x00,0xE0,0xA8,0xF8,0x90,0xF8,0x00 },{ 0x40,0x40,0x40,0x00,0x00,0x00,0x00 },{ 0x30,0x20,0x20,0x20,0x20,0x20,0x30 },{ 0x60,0x20,0x20,0x20,0x20,0x20,0x60 },{ 0x00,0x20,0xA8,0x70,0xA8,0x20,0x00 },{ 0x00,0x20,0x20,0xF8,0x20,0x20,0x00 },{ 0x00,0x00,0x00,0x00,0x60,0x60,0x40 },{ 0x00,0x00,0x00,0xF8,0x00,0x00,0x00 },{ 0x00,0x00,0x00,0x00,0x60,0x60,0x00 },{ 0x00,0x08,0x10,0x20,0x40,0x80,0x00 },{ 0x00,0xF8,0x88,0xE8,0x88,0xF8,0x00 },{ 0x00,0x10,0x30,0x50,0x10,0x10,0x00 },{ 0x00,0xF8,0x08,0xF8,0x80,0xF8,0x00 },{ 0x00,0xF8,0x08,0xF8,0x08,0xF8,0x00 },{ 0x00,0x38,0x48,0x88,0xF8,0x08,0x00 },{ 0x00,0xF8,0x80,0xF8,0x08,0xF8,0x00 },{ 0x00,0xF8,0x80,0xF8,0x88,0xF8,0x00 },{ 0x00,0xF8,0x08,0x10,0x20,0x40,0x00 },{ 0x00,0xF8,0x88,0xF8,0x88,0xF8,0x00 },{ 0x00,0xF8,0x88,0xF8,0x08,0xF8,0x00 },{ 0x00,0x30,0x30,0x00,0x30,0x30,0x00 },{ 0x00,0x30,0x30,0x00,0x30,0x30,0x20 },{ 0x08,0x10,0x20,0x40,0x20,0x10,0x08 },{ 0x00,0x00,0xF8,0x00,0xF8,0x00,0x00 },{ 0x40,0x20,0x10,0x08,0x10,0x20,0x40 },{ 0x00,0xF8,0x08,0x78,0x00,0x60,0x00 },{ 0x00,0xF8,0xA8,0xB8,0x80,0xF8,0x00 },{ 0x00,0xF8,0x88,0xF8,0x88,0x88,0x00 },{ 0x00,0xF0,0x90,0xF8,0x88,0xF8,0x00 },{ 0x00,0xF8,0x80,0x80,0x80,0xF8,0x00 },{ 0x00,0xE0,0x90,0x88,0x88,0xF8,0x00 },{ 0x00,0xF8,0x80,0xF8,0x80,0xF8,0x00 },{ 0x00,0xF8,0x80,0xF8,0x80,0x80,0x00 },{ 0x00,0xF8,0x80,0xB8,0x88,0xF8,0x00 },{ 0x00,0x88,0x88,0xF8,0x88,0x88,0x00 },{ 0x00,0x40,0x40,0x40,0x40,0x40,0x00 },{ 0x00,0x08,0x08,0x88,0x88,0xF8,0x00 },{ 0x00,0x88,0x90,0xA0,0x90,0x88,0x00 },{ 0x00,0x80,0x80,0x80,0x80,0xF8,0x00 },{ 0x00,0xFE,0x92,0x92,0x92,0x92,0x00 },{ 0x00,0x88,0xC8,0xA8,0x98,0x88,0x00 },{ 0x00,0xF8,0x88,0x88,0x88,0xF8,0x00 },{ 0x00,0xF8,0x88,0x88,0xF8,0x80,0x00 },{ 0x00,0xF8,0x88,0xA8,0xA8,0xF8,0x10 },{ 0x00,0xF8,0x88,0xF8,0x90,0x88,0x00 },{ 0x00,0xF8,0x80,0xF8,0x08,0xF8,0x00 },{ 0x00,0xF8,0x20,0x20,0x20,0x20,0x00 },{ 0x00,0x88,0x88,0x88,0x88,0xF8,0x00 },{ 0x00,0x88,0x88,0x90,0xA0,0xC0,0x00 },{ 0x00,0x92,0x92,0x92,0x92,0xFE,0x00 },{ 0x00,0x88,0x50,0x20,0x50,0x88,0x00 },{ 0x00,0x88,0x88,0xF8,0x08,0xF8,0x00 },{ 0x00,0xF8,0x10,0x20,0x40,0xF8,0x00 },{ 0x38,0x20,0x20,0x20,0x20,0x20,0x38 },{ 0x00,0x80,0x40,0x20,0x10,0x08,0x00 },{ 0x70,0x10,0x10,0x10,0x10,0x10,0x70 },{ 0x00,0x20,0x50,0x88,0x00,0x00,0x00 },{ 0x00,0x00,0x00,0x00,0x00,0x00,0xF8 },{ 0x40,0x20,0x10,0x00,0x00,0x00,0x00 },{ 0x00,0xF8,0x88,0xF8,0x88,0x88,0x00 },{ 0x00,0xF0,0x90,0xF8,0x88,0xF8,0x00 },{ 0x00,0xF8,0x80,0x80,0x80,0xF8,0x00 },{ 0x00,0xE0,0x90,0x88,0x88,0xF8,0x00 },{ 0x00,0xF8,0x80,0xF8,0x80,0xF8,0x00 },{ 0x00,0xF8,0x80,0xF8,0x80,0x80,0x00 },{ 0x00,0xF8,0x80,0xB8,0x88,0xF8,0x00 },{ 0x00,0x88,0x88,0xF8,0x88,0x88,0x00 },{ 0x00,0x40,0x40,0x40,0x40,0x40,0x00 },{ 0x00,0x08,0x08,0x88,0x88,0xF8,0x00 },{ 0x00,0x88,0x90,0xA0,0x90,0x88,0x00 },{ 0x00,0x80,0x80,0x80,0x80,0xF8,0x00 },{ 0x00,0xFE,0x92,0x92,0x92,0x92,0x00 },{ 0x00,0x88,0xC8,0xA8,0x98,0x88,0x00 },{ 0x00,0xF8,0x88,0x88,0x88,0xF8,0x00 },{ 0x00,0xF8,0x88,0x88,0xF8,0x80,0x00 },{ 0x00,0xF8,0x88,0xA8,0xA8,0xF8,0x10 },{ 0x00,0xF8,0x88,0xF8,0x90,0x88,0x00 },{ 0x00,0xF8,0x80,0xF8,0x08,0xF8,0x00 },{ 0x00,0xF8,0x20,0x20,0x20,0x20,0x00 },{ 0x00,0x88,0x88,0x88,0x88,0xF8,0x00 },{ 0x00,0x88,0x88,0x90,0xA0,0xC0,0x00 },{ 0x00,0x92,0x92,0x92,0x92,0xFE,0x00 },{ 0x00,0x88,0x50,0x20,0x50,0x88,0x00 },{ 0x00,0x88,0x88,0xF8,0x08,0xF8,0x00 },{ 0x00,0xF8,0x10,0x20,0x40,0xF8,0x00 },{ 0x38,0x20,0x20,0xE0,0x20,0x20,0x38 },{ 0x20,0x20,0x20,0x20,0x20,0x20,0x20 },{ 0xE0,0x20,0x20,0x38,0x20,0x20,0xE0 },{ 0x00,0xE8,0xB8,0x00,0x00,0x00,0x00 },{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00 },};
|
|
|
|
const char SMLFONT[HICHAR-LOCHAR+1][5] = {
|
|
{ 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,0xE0,0x00 },{ 0xC0,0x40,0x40,0xE0,0x00 },{ 0xE0,0x20,0xC0,0xE0,0x00 },{ 0xE0,0x60,0x20,0xE0,0x00 },{ 0xA0,0xA0,0xE0,0x20,0x00 },{ 0xE0,0xC0,0x20,0xE0,0x00 },{ 0xC0,0x80,0xE0,0xE0,0x00 },{ 0xE0,0x20,0x40,0x40,0x00 },{ 0x60,0xE0,0xA0,0xE0,0x00 },{ 0xE0,0xE0,0x20,0x60,0x00 },{ 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 },{ 0x20,0xE0,0xA0,0xE0,0x00 },{ 0x00,0xE0,0xA0,0xC0,0x00 },{ 0x20,0x40,0x60,0x40,0x00 },{ 0x00,0x60,0xA0,0x60,0xC0 },{ 0x80,0xE0,0xA0,0xA0,0x00 },{ 0x40,0x00,0x40,0x40,0x00 },{ 0x40,0x00,0x40,0x40,0xC0 },{ 0x80,0xA0,0xC0,0xA0,0x00 },{ 0xC0,0x40,0x40,0x60,0x00 },{ 0x00,0xE0,0xE0,0xA0,0x00 },{ 0x00,0xE0,0xA0,0xA0,0x00 },{ 0x00,0xE0,0xA0,0xE0,0x00 },{ 0x00,0xE0,0xA0,0xE0,0x80 },{ 0x00,0xE0,0xA0,0xE0,0x20 },{ 0x00,0xE0,0x80,0x80,0x00 },{ 0x00,0x60,0x40,0xC0,0x00 },{ 0x40,0x60,0x40,0x60,0x00 },{ 0x00,0xA0,0xA0,0xE0,0x00 },{ 0x00,0xA0,0xE0,0x40,0x00 },{ 0x00,0xA0,0xE0,0xE0,0x00 },{ 0x00,0xA0,0x40,0xA0,0x00 },{ 0x00,0xA0,0xE0,0x20,0xC0 },{ 0x00,0xC0,0x40,0x60,0x00 },{ 0x60,0xC0,0x40,0x60,0x00 },{ 0x40,0x40,0x40,0x40,0x40 },{ 0xC0,0x60,0x40,0xC0,0x00 },{ 0x20,0xE0,0x80,0x00,0x00 },};
|
|
|
|
// draw a letter
|
|
void 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 xb = x>>2; // divide x by 4
|
|
byte* dest = &vmagic[y][xb]; // destination address
|
|
hw_magic = M_SHIFT(x) | M_XPAND | op;
|
|
for (byte i=0; i<font->pattern_y; i++) {
|
|
char b = *src++;
|
|
EXIT_CLIPDEST(dest);
|
|
*dest++ = b; // expand lower nibble -> 1st byte
|
|
*dest++ = b; // expand upper nibble -> 2nd byte
|
|
*dest++ = 0; // leftover -> 3rd byte
|
|
*dest = 0; // reset upper/lower flag
|
|
dest += VBWIDTH-3; // we incremented 3 bytes for this line
|
|
}
|
|
}
|
|
|
|
#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) {
|
|
ctx->regs.b.e = x;
|
|
break;
|
|
}
|
|
if (ch < 0x20) {
|
|
x += 8 * ch;
|
|
} else if (ch < 0x64) {
|
|
draw_char(&FNTSYS, ch, x, y, op);
|
|
x += 8;
|
|
} else if (ch >= 0x80) {
|
|
draw_char(FONT_IX, ch, x, y, op);
|
|
x += FONT_IX->frame_x;
|
|
} else {
|
|
/*
|
|
if (ch & 0x10) {
|
|
ctx->regs.b.ixl = *str++;
|
|
ctx->regs.b.ixh = *str++;
|
|
}
|
|
if (ch & 0x1)
|
|
ctx->regs.b.e = *str++;
|
|
if (ch & 0x2)
|
|
ctx->regs.b.d = *str++;
|
|
if (ch & 0x4)
|
|
ctx->regs.b.c = *str++;
|
|
*/
|
|
// TODO: only can change font
|
|
}
|
|
} while (1);
|
|
}
|
|
|
|
// String display routine (pass pointer to string)
|
|
void STRDIS2(ContextBlock *ctx, char *str) {
|
|
byte opts = ctx->regs.b.c;
|
|
byte x = ctx->regs.b.e;
|
|
byte y = ctx->regs.b.d;
|
|
void* fontdesc = (void*) ctx->regs.w.ix;
|
|
hw_xpand = opts & 0xf;
|
|
draw_string(ctx, str, x, y, 3&(opts>>4)); // TODO: opts
|
|
}
|
|
|
|
// String display routine
|
|
void STRDIS(ContextBlock *ctx) {
|
|
char* str = (char*) ctx->regs.w.hl;
|
|
STRDIS2(ctx, str);
|
|
}
|
|
|
|
// Character display routine
|
|
void CHRDIS(ContextBlock *ctx) {
|
|
char chstr[2];
|
|
chstr[0] = ctx->regs.b.a;
|
|
chstr[1] = 0;
|
|
STRDIS2(ctx, chstr);
|
|
}
|
|
|
|
// BCD routine
|
|
const char BCDTAB[17] = "0123456789*+,-./";
|
|
|
|
void DISNUM(ContextBlock *ctx) {
|
|
// TODO: options, B
|
|
word oldhl = ctx->regs.w.hl;
|
|
byte val = *(byte*) oldhl;
|
|
char bcdstr[3];
|
|
bcdstr[0] = BCDTAB[val >> 4];
|
|
bcdstr[1] = BCDTAB[val & 15];
|
|
bcdstr[2] = 0;
|
|
STRDIS2(ctx, bcdstr);
|
|
}
|
|
|
|
typedef struct {
|
|
sbyte xofs, yofs;
|
|
byte xsize, ysize;
|
|
byte pattern[0];
|
|
} PatternBlock;
|
|
// TODO
|
|
|
|
void wait_vsync() {
|
|
byte x = TMR60;
|
|
while (x == TMR60) ; // wait until timer/60 changes
|
|
}
|
|
|
|
void PAWS(ContextBlock *ctx) {
|
|
while (ctx->regs.b.b--) {
|
|
wait_vsync();
|
|
}
|
|
}
|
|
|
|
const SysCallEntry SYSCALL_TABLE[64] = {
|
|
/* 0 */
|
|
{ &INTPC, 0 },
|
|
{ &EXIT, 0 },
|
|
{ &RCALL, REG_HL },
|
|
{ &MCALL, REG_HL },
|
|
{ &MRET, 0 },
|
|
/* 10 */
|
|
{ &MJUMP, REG_HL },
|
|
{ &SUCK, REG_B },
|
|
{ &ACTINT, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
/* 20 */
|
|
{ 0, 0 },
|
|
{ &SETOUT, REG_D|REG_B|REG_A },
|
|
{ &COLSET, REG_HL },
|
|
{ &FILL, REG_A|REG_BC|REG_DE },
|
|
{ 0, 0 },
|
|
/* 30 */
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
/* 40 */
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
/* 50 */
|
|
{ &CHRDIS, REG_E|REG_D|REG_C|REG_A },
|
|
{ &STRDIS, REG_E|REG_D|REG_C|REG_HL },
|
|
{ &DISNUM, REG_E|REG_D|REG_C|REG_HL },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
/* 60 */
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
/* 70 */
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
/* 80 */
|
|
{ &PAWS, REG_B },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
/* 90 */
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
/* 100 */
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
/* 110 */
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
/* 120 */
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
};
|
|
|
|
void SYSCALL(ContextBlock *ctx) {
|
|
byte op = *ctx->params++;
|
|
byte argmask;
|
|
SysRoutine* routine;
|
|
// user-defined?
|
|
if (op & 0x80) {
|
|
argmask = UMARGT[op & 0x7f];
|
|
routine = (SysRoutine*) USERTB[op & 0x7f];
|
|
} else {
|
|
const SysCallEntry* entry = &SYSCALL_TABLE[op>>1];
|
|
argmask = entry->argmask;
|
|
routine = entry->routine;
|
|
}
|
|
// suck params into context block?
|
|
if (op & 1) {
|
|
suckParams(ctx, argmask);
|
|
}
|
|
// call the routine
|
|
if (routine) {
|
|
routine(ctx);
|
|
}
|
|
}
|
|
|
|
#ifdef TEST
|
|
void main() {
|
|
__asm
|
|
ld hl,#0x20d
|
|
push hl
|
|
pop ix
|
|
RST 0x38
|
|
.db 0 ; INTPC
|
|
.db 22+1 ; SETOUT
|
|
.db 102*2, 0x1c, 0x08
|
|
.db 14 ; ACTINT
|
|
.db 24+1 ; COLSET
|
|
.dw _main ; palette???
|
|
.db 26+1 ; FILL
|
|
.dw 0x4000
|
|
.dw 90*40
|
|
.db 0xaa
|
|
.db 52+1 ; draw string
|
|
.db 0
|
|
.db 32
|
|
.db 0x0c
|
|
.dw HelloString
|
|
.db 52+1 ; draw string
|
|
.db 0
|
|
.db 48
|
|
.db 0x0c
|
|
.dw HelloString
|
|
.db 50+1 ; draw char
|
|
.db 0
|
|
.db 64
|
|
.db 0x0c
|
|
.db 0x40
|
|
.db 2 ; EXIT
|
|
.loop:
|
|
ld hl,#0x4FED
|
|
ld a,(hl)
|
|
add a,#0x30
|
|
RST 0x38
|
|
.db 50 ; draw char
|
|
jp .loop
|
|
HelloString:
|
|
.ascii "HELLO WORLD! "
|
|
.db 0xc1, 0xc2, 0xc3, 0xc4, 0xc5
|
|
.db 0
|
|
; Critter Pattern
|
|
; Color 0 = White and Color 2 = Black
|
|
;
|
|
PATERN: .DB 0,0 ; (0,0) Position
|
|
.DB 0x02,0x08 ; 2 byte, 8 line pattern size
|
|
|
|
.DB 0x0A,0xA0 ; 0000101010100000 - . . 2 2 2 2 . .
|
|
.DB 0x22,0x88 ; 0010001010001000 - . 2 . 2 2 . 2 .
|
|
.DB 0xAA,0xAA ; 1010101010101010 - 2 2 2 2 2 2 2 2
|
|
.DB 0x2A,0xA8 ; 0010101010101000 - . 2 2 2 2 2 2 .
|
|
.DB 0x08,0x20 ; 0000100000100000 - . . 2 . . 2 . .
|
|
.DB 0x20,0x08 ; 0010000000001000 - . 2 . . . . 2 .
|
|
.DB 0x08,0x20 ; 0000100000100000 - . . 2 . . 2 . .
|
|
.DB 0x00,0x00 ; 0000000000000000 - . . . . . . . .
|
|
__endasm;
|
|
while (1) CT[0]++;
|
|
}
|
|
#endif
|