#define TEST #include 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]; // start @ $4FCE volatile word MUZPC; // music PC volatile word MUZSP; // music SP volatile byte PVOLAB; // channels A and B volume volatile byte PVOLMC; // channel C volume and noise mask volatile byte VOICES; // voice smask volatile byte CT[8]; // counter timers volatile byte CNT; volatile byte SEMI4S; volatile byte OPOT[4]; volatile byte KEYSEX; volatile byte OSW[4]; volatile word COLLST; volatile byte DURAT; // note duration volatile byte TMR60; // 1/60 sec timer volatile byte TIMOUT; // blackout timer volatile byte GTSECS; // seconds timer volatile byte GTMINS; // minutes timer unsigned long RANSHT; // RNG byte NUMPLY; // # players byte ENDSCR[3]; // end score byte MRLOCK; // magic register lock out byte GAMSTB; // game status byte PRIOR; // music protect byte SENFLG; // sentry control byte* UMARGT; // user mask table (-64 bytes) word* USERTB; // user routine table (-128 bytes) // start routine @ 0x0 void bios_start() __naked { __asm DI ; disable interrupts 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: LD SP,#0x4fce ; position stack below BIOS vars 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 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 }; 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] = {/*{count:68,w:8,h:7,brev:1}*/ { 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,0x70,0xA8,0x20,0x20,0x00 },{ 0x00,0x20,0x40,0xF8,0x40,0x20,0x00 },{ 0x00,0x20,0x20,0xA8,0x70,0x20,0x00 },{ 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,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 }}; // 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; ipattern_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(); } } // MATH void RANGED(ContextBlock *ctx) { /* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */ RANSHT ^= RANSHT << 13; RANSHT ^= RANSHT >> 17; RANSHT ^= RANSHT << 5; if (ctx->regs.b.a == 0) { ctx->regs.b.a = (byte)RANSHT; } else { ctx->regs.b.a = (byte)(RANSHT % ctx->regs.b.a); } } 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 }, { &RANGED, REG_A }, /* 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>>1]; routine = (SysRoutine*) USERTB[op>>1]; } 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 SP,#0x4fce ; position stack below BIOS vars 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) ; } #endif