From 50421a69f355ad7a9f8df51563d9e451a18de812 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Sat, 1 Jun 2019 22:09:45 -0400 Subject: [PATCH] astrocade: added bmusic, updated aclib --- doc/notes.txt | 2 + presets/astrocade-bios/bios.c | 49 +++++++++---- presets/astrocade-bios/biosasm.s | 7 ++ presets/astrocade-bios/bmusic.c | 110 ++++++++++++++++++++++++++++++ presets/astrocade-bios/test1.s | 22 ++++++ presets/astrocade/acbios.h | 16 +++-- presets/astrocade/acbios.s | 36 +++++++++- presets/astrocade/acextra.c | 1 + presets/astrocade/acextra.h | 6 ++ presets/astrocade/aclib.c | 2 + presets/astrocade/aclib.h | 6 -- presets/astrocade/acmenu.s | 2 +- presets/astrocade/cosmic.c | 3 + presets/astrocade/hdr_autostart.s | 21 ++++-- presets/astrocade/hello.c | 13 ++-- presets/astrocade/lines.c | 2 +- presets/astrocade/skeleton.sdcc | 7 +- presets/astrocade/sprites.c | 2 +- presets/astrocade/vsync.c | 6 +- src/platform/astrocade.ts | 7 +- 20 files changed, 277 insertions(+), 43 deletions(-) create mode 100644 presets/astrocade-bios/bmusic.c diff --git a/doc/notes.txt b/doc/notes.txt index 48ef3833..7a4ada6d 100644 --- a/doc/notes.txt +++ b/doc/notes.txt @@ -144,6 +144,8 @@ TODO: - target ES6 - don't have to include bootstrap-tourist each time? - don't have to include firebase always? + - squelch error msgs? + - test offline? - Github - gh-pages branch with embedded - handle overwrite logic diff --git a/presets/astrocade-bios/bios.c b/presets/astrocade-bios/bios.c index 1b1d45ed..3bbc8acb 100644 --- a/presets/astrocade-bios/bios.c +++ b/presets/astrocade-bios/bios.c @@ -18,6 +18,9 @@ See: http://creativecommons.org/publicdomain/zero/1.0/ // demo code //#link "test1.s" +// music processor +//#link "bmusic.c" + #include // uncomment to make code better, but slower compile @@ -162,6 +165,7 @@ 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); // INTERRUPT HANDLERS // must be in 0x200 page @@ -176,31 +180,38 @@ void hw_interrupt() __naked { if (++TMR60 == 60) { TMR60 = 0; ++TIMOUT; - KEYSEX |= 0x80; + KEYSEX |= 0x80; // notify SENTRY if (++GTSECS == 60) { GTMINS++; } } + // TODO? + if (VOICES) { + if (DURAT) { + DURAT--; + } else { + music_update(); + } + } __asm__("exx"); __asm__("ex af,af'"); __asm__("reti"); } -// TODO -byte add_counters(byte mask, byte delta) { +void add_counters(byte mask, byte delta) { byte i = 0; - byte any0 = 0; while (mask) { if (mask & 1) { if (CT[i]) { - if (!(CT[i] += delta)) - any0 = 1; + // notify SENTRY if counters go to 0 + if (!(CT[i] += delta)) { + SENFLG |= 1<>= 1; i++; } - return any0; } void STIMER() { @@ -214,10 +225,7 @@ void TIMEZ() { } void TIMEY() { - CT[0]--; - CT[1]--; - CT[2]--; - CT[3]--; + add_counters(0x0f, -1); } void TIMEX() { @@ -780,6 +788,18 @@ void SENTRY(ContextBlock *ctx) { _B = B; } +void BMUSIC(ContextBlock *ctx) { + VOICES = _A; + MUZPC = _HL; + MUZSP = _IX; + DURAT = 0; +} + +void EMUSIC(ContextBlock *ctx) { + ctx; + VOICES = 0; +} + const SysCallEntry SYSCALL_TABLE[64] = { /* 0 */ { &INTPC, 0 }, @@ -792,9 +812,9 @@ const SysCallEntry SYSCALL_TABLE[64] = { { &SUCK, REG_B }, { &ACTINT, 0 }, { 0, 0 }, - { 0, 0 }, + { &BMUSIC, REG_HL|REG_IX|REG_A }, /* 20 */ - { 0, 0 }, + { &EMUSIC, }, { &SETOUT, REG_D|REG_B|REG_A }, { &COLSET, REG_HL }, { &FILL, REG_A|REG_BC|REG_DE }, @@ -893,4 +913,7 @@ void bios_init() { hw_magic = 0; *((byte*)0x4fce) = 0; hw_magic = 0; + // call SENTRY once to set current values + // (context block doesn't matter) + SENTRY((ContextBlock*)0x4fce); } diff --git a/presets/astrocade-bios/biosasm.s b/presets/astrocade-bios/biosasm.s index d270a2b1..b35358bc 100644 --- a/presets/astrocade-bios/biosasm.s +++ b/presets/astrocade-bios/biosasm.s @@ -55,6 +55,13 @@ SYSCALL38: pop hl ret +; out to port + .globl _portOut +_portOut: + ld c,h + out (c),l + ret + ; TODO? ReloadRegs: ld c,(hl) diff --git a/presets/astrocade-bios/bmusic.c b/presets/astrocade-bios/bmusic.c new file mode 100644 index 00000000..c89a086d --- /dev/null +++ b/presets/astrocade-bios/bmusic.c @@ -0,0 +1,110 @@ + +#pragma opt_code_speed + +typedef unsigned char byte; +typedef signed char sbyte; +typedef unsigned short word; +typedef signed short sword; + +extern byte* MUZPC; // music PC +extern byte* MUZSP; // music SP +extern byte PVOLAB; // channels A and B volume +extern byte PVOLMC; // channel C volume and noise mask +extern byte VOICES; // voices mmask +extern byte DURAT; // note duration + +__sfr __at(0x10) hw_tonmo; +__sfr __at(0x11) hw_tonea; +__sfr __at(0x12) hw_toneb; +__sfr __at(0x13) hw_tonec; +__sfr __at(0x14) hw_vibra; +__sfr __at(0x15) hw_volc; +__sfr __at(0x16) hw_volab; +__sfr __at(0x17) hw_voln; +__sfr __at(0x18) hw_sndbx; + +extern void portOut(word portVal) __z88dk_fastcall; + +static byte NEXT(void) { + return *MUZPC++; +} + +static void PUSH(byte b) { + *++MUZSP = b; +} + +static byte POP() { + return *MUZSP--; +} + +static byte DECTOP() { + return --(*MUZSP); +} + +void music_update(void) { + byte op = NEXT(); + if (op < 0x80) { + DURAT = op; + op = VOICES; + if (op & 0x01) hw_voln = NEXT(); + if (op & 0x02) hw_vibra = NEXT(); + if (op & 0x04 && (hw_tonec = *MUZPC)) { + hw_volc = PVOLMC; + } + if (op & 0x08) MUZPC++; + if (op & 0x10) { + if (!(hw_toneb = *MUZPC)) + op ^= 0x10; + } + if (op & 0x20) MUZPC++; + if (op & 0x40) { + if (!(hw_tonea = *MUZPC)) + op ^= 0x40; + } + if (op & 0x80) MUZPC++; + hw_volab = + ((op & 0x40) ? (PVOLAB & 0x0f) : 0) | + ((op & 0x10) ? (PVOLAB & 0xf0) : 0); + } else if (op < 0x88) { + portOut( NEXT() | ((op-0x70)<<8) ); + } else if (op == 0x88) { + for (byte i=0; i<8; i++) + portOut( NEXT() | (0x17-i) ); + } else switch (op & 0xf0) { + case 0x90: + VOICES = NEXT(); + break; + case 0xa0: + PUSH(op - 0x9f); + break; + case 0xb0: + PVOLAB = NEXT(); + PVOLMC = NEXT(); + break; + case 0xc0: + if (DECTOP()) { + MUZPC = (byte*)*(word*)MUZPC; + } else { + MUZPC += 2; + POP(); + } + break; + case 0xd0: + MUZPC += op & 0xf; + break; + case 0xe0: + // REST + if (op == 0xe1) { + hw_volab = hw_volc = 0; + DURAT = *MUZPC++; + } else { + // TODO: legatto/stacatto + } + break; + case 0xf0: + hw_volab = hw_volc = 0; + VOICES = 0; + break; + } +} + diff --git a/presets/astrocade-bios/test1.s b/presets/astrocade-bios/test1.s index 467a39b6..a19d32f4 100644 --- a/presets/astrocade-bios/test1.s +++ b/presets/astrocade-bios/test1.s @@ -20,6 +20,7 @@ _main: SYSTEM INTPC DO SETOUT .db 89*2, 23, 0x00 + DONT EMUSIC DONT ACTINT DO COLSET .dw palette @@ -87,6 +88,10 @@ _main: .dw BCDNUM .dw 3 .dw _BCDNUM + DO BMUSIC + .dw 0x4000 + .db 0b11111100 + .dw ANTHEM ; exit interpreter EXIT .loop: @@ -173,3 +178,20 @@ BALL: .db 0,0 RINGING: .db 0x80,0x23,0xB0,0x80,0x00,0x3C,0x17,0x3C,0x11,0xE1,0x50,0x3C,0x17,0x3C,0x11,0xE1,0xA0,0xC3,0x5B,0x23,0x00 + +ANTHEM: + .db 0x80 + .db 0x20,0xB0,0xCC,0x0F,0x0C,0x7E,0x00,0x00 + .db 0x0C,0x7E,0x00,0x00,0x24,0x5E,0x7E,0x96 + .db 0x0C,0x54,0x64,0x7E,0x0E,0x4A,0x5E,0x7E + .db 0x10,0x46,0x54,0x7E,0x48,0x3E,0x4A,0x5E + .db 0x0E,0x5E,0x8D,0x70,0x10,0x54,0x8D,0x70 + .db 0x36,0x4A,0x5E,0x70,0x12,0x46,0x54,0x7E + .db 0x24,0x54,0x64,0x7E,0x48,0x5E,0x96,0x7E +CHEERS: + .db 0xE0,0x80,0x18,0x90,0xFD,0xB0,0xFF,0x1F + .db 0xA4 +CHEERLOOP: + .db 0x1E,0x19,0x03,0x3C,0x50,0xC0 + .dw CHEERLOOP + .db 0xE0,0xF0 diff --git a/presets/astrocade/acbios.h b/presets/astrocade/acbios.h index b8555568..59b833a9 100644 --- a/presets/astrocade/acbios.h +++ b/presets/astrocade/acbios.h @@ -2,6 +2,8 @@ #ifndef _ACBIOS_H #define _ACBIOS_H +#include "aclib.h" + // FONT DESCRIPTORS typedef struct { @@ -16,10 +18,6 @@ typedef struct { const FontDescriptor __at(0x206) FNTSYS; const FontDescriptor __at(0x20d) FNTSML; -// BIOS COMMANDS - -#define STRDIS 0x34 - // FUNCTIONS #define OPT_1x1 0x00 @@ -36,6 +34,7 @@ const FontDescriptor __at(0x20d) FNTSML; void activate_interrupts(void); void sleep(byte frames) __z88dk_fastcall; +void fast_vsync(void); void display_string(byte x, byte y, byte options, const char* str); void paint_rectangle(byte x, byte y, byte w, byte h, byte colormask); @@ -49,6 +48,11 @@ void bcdn_add(byte* dest, byte size, const byte* n); void bcdn_sub(byte* dest, byte size, const byte* n); byte ranged_random(byte n) __z88dk_fastcall; +word sense_transition(const byte* keypad_mask) __z88dk_fastcall; + +void begin_music(const byte* stack, byte voices, const byte* musicdata); +void end_music(void); + // QUICK MACROS #define SYS_SETOUT(verbl,horcb,inmod)\ @@ -65,4 +69,8 @@ byte ranged_random(byte n) __z88dk_fastcall; __asm__(".dw "#count);\ __asm__(".db "#val);\ +#define RESET_TIMEOUT() \ + __asm__("ld a,#0xff");\ + __asm__("ld (0x4FEC),a"); + #endif diff --git a/presets/astrocade/acbios.s b/presets/astrocade/acbios.s index 14a0ab12..57b0ef24 100644 --- a/presets/astrocade/acbios.s +++ b/presets/astrocade/acbios.s @@ -3,7 +3,7 @@ ;;; C functions - .area CODE + .area _LIB ; activate interrupts .globl _activate_interrupts @@ -21,6 +21,16 @@ _sleep: SYSTEM PAWS ret + .globl _fast_vsync +_fast_vsync: + ld hl,#TMR60 + ld c,(hl) +.lvsync: + ld a,(hl) + sub c + jp z,.lvsync + ret + ; load 5 bytes from stack into registers load5_edca_hl: ld ix,#4 @@ -96,3 +106,27 @@ _blank_area: SYSTEM BLANK ret +; SENTRY mask-addr + .globl _sense_transition +_sense_transition: + ld l,e + ld h,d + SYSTEM SENTRY + ld l,a + ld h,b + ret + +; BMUSIC stack-addr voices score-addr + .globl _begin_music +_begin_music: + call load5_edca_hl + push de + pop ix + SYSTEM BMUSIC + ret + +; EMUSIC + .globl _end_music +_end_music: + SYSTEM EMUSIC + ret diff --git a/presets/astrocade/acextra.c b/presets/astrocade/acextra.c index 6c11989c..fb1caf7b 100644 --- a/presets/astrocade/acextra.c +++ b/presets/astrocade/acextra.c @@ -2,6 +2,7 @@ #include #include "aclib.h" +#include "acextra.h" #define EXIT_CLIPDEST(addr) if ((((word)addr)&0xfff) >= 0xe10) return diff --git a/presets/astrocade/acextra.h b/presets/astrocade/acextra.h index 8b6df575..61524515 100644 --- a/presets/astrocade/acextra.h +++ b/presets/astrocade/acextra.h @@ -4,6 +4,12 @@ #include "aclib.h" +// font constants +#define LOCHAR 32 +#define HICHAR 127 +#define FONT_BWIDTH 1 +#define FONT_HEIGHT 8 + void clrscr(); void vline(byte x, byte y1, byte y2, byte col, byte op); void pixel(byte x, byte y, byte col, byte op); diff --git a/presets/astrocade/aclib.c b/presets/astrocade/aclib.c index b0554607..5fb2ddbf 100644 --- a/presets/astrocade/aclib.c +++ b/presets/astrocade/aclib.c @@ -2,6 +2,8 @@ #include #include "aclib.h" +#pragma opt_code_speed + // 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 { diff --git a/presets/astrocade/aclib.h b/presets/astrocade/aclib.h index 0ba1b5f8..e1c5ff21 100644 --- a/presets/astrocade/aclib.h +++ b/presets/astrocade/aclib.h @@ -71,12 +71,6 @@ byte __at (0x0000) vmagic[VTOTAL][VBWIDTH]; // regular frame buffer RAM byte __at (0x4000) vidmem[VTOTAL][VBWIDTH]; -// font constants -#define LOCHAR 32 -#define HICHAR 127 -#define FONT_BWIDTH 1 -#define FONT_HEIGHT 8 - /// GRAPHICS FUNCTIONS void set_palette(byte palette[8]) __z88dk_fastcall; // palette in reverse order diff --git a/presets/astrocade/acmenu.s b/presets/astrocade/acmenu.s index b32e8faf..982a3192 100644 --- a/presets/astrocade/acmenu.s +++ b/presets/astrocade/acmenu.s @@ -1,7 +1,7 @@ ; Minimal header file for use with Astrocade C programs - .area _CODE + .area _CODE .byte 0x55 ; ... with the code for a normal menued cartridge .word 0x0218 ; Initialize menu diff --git a/presets/astrocade/cosmic.c b/presets/astrocade/cosmic.c index 41065464..95a64dff 100644 --- a/presets/astrocade/cosmic.c +++ b/presets/astrocade/cosmic.c @@ -7,6 +7,9 @@ #include +//#resource "astrocade.inc" +#include "acbios.h" +//#link "acbios.s" #include "aclib.h" //#link "aclib.c" #include "acextra.h" diff --git a/presets/astrocade/hdr_autostart.s b/presets/astrocade/hdr_autostart.s index 8de35957..788b22ed 100644 --- a/presets/astrocade/hdr_autostart.s +++ b/presets/astrocade/hdr_autostart.s @@ -1,14 +1,27 @@ ; Minimal header file for use with Astrocade C programs - .area _CODE + .area _CODE - jp start ; jump to main() -start: - ld sp,#0x4fce + jp Start ; jump to main() +Start: + ld hl,#0x4fce ; stack start + ld sp,hl ; setup stack pointer +; clear BIOS RAM + ld bc,#0x4fff-0x4fce + xor a ; A = 0 + ld (hl),a ; set initial zero + push hl + pop de + inc de ; DE = HL + 1 + ldir ; clear RAM +; initialize INITIALIZED segment ld BC, #l__INITIALIZER + jp z,.nomeminit ld A, B ld DE, #s__INITIALIZED ld HL, #s__INITIALIZER ldir +.nomeminit: +; jump to main C function jp _main diff --git a/presets/astrocade/hello.c b/presets/astrocade/hello.c index cce70b05..b2efc7ae 100644 --- a/presets/astrocade/hello.c +++ b/presets/astrocade/hello.c @@ -27,10 +27,10 @@ const byte BALL[] = { 0b01111000, }; - // BCD number -byte bcdnum[3] = {0x56,0x34,0x12}; -byte bcdinc[3] = {0x01,0x00,0x00}; +static byte bcdnum[3] = {0x56,0x34,0x12}; +const byte bcdinc[3] = {0x01,0x00,0x00}; +const byte keypadMask[4] = { 0x3f,0x3f,0x3f,0x3f }; void main(void) { // setup palette @@ -61,11 +61,16 @@ void main(void) { write_relative(60, 80, M_XPAND, BALL); // write_pattern() doesn't use the x/y offset write_pattern(70, 80, M_XPAND, BALL+2); + write_pattern(0, 80, M_XPAND|M_FLOP, BALL+2); + write_pattern(1, 70, M_XPAND|M_FLOP, BALL+2); + write_pattern(2, 60, M_XPAND|M_FLOP, BALL+2); // infinite loop activate_interrupts(); + // make sure screen doesn't black out + RESET_TIMEOUT(); while (1) { display_bcd_number(80, 80, OPT_ON(2), bcdnum, 6|DISBCD_SML|DISBCD_NOZERO); bcdn_add(bcdnum, 3, bcdinc); - sleep(60); + while (sense_transition(keypadMask) == 0); } } diff --git a/presets/astrocade/lines.c b/presets/astrocade/lines.c index 9b2281ce..3d6ec020 100644 --- a/presets/astrocade/lines.c +++ b/presets/astrocade/lines.c @@ -34,7 +34,7 @@ const byte palette[8] = { void main() { set_palette(palette); SYS_SETOUT(89*2, 20, 0); - SYS_FILL(0x4000, 89*2, 0); + SYS_FILL(0x4000, 89*40, 0); hw_xpand = XPAND_COLORS(0, 2); draw_string(2, 80, 0, "Hello, Lines!"); draw_line(0, 0, 159, 95, 1); diff --git a/presets/astrocade/skeleton.sdcc b/presets/astrocade/skeleton.sdcc index e88849c5..aeea7431 100644 --- a/presets/astrocade/skeleton.sdcc +++ b/presets/astrocade/skeleton.sdcc @@ -1,9 +1,10 @@ +//#resource "astrocade.inc" #include "aclib.h" //#link "aclib.c" -//#link "hdr_autostart.s" #include "acbios.h" //#link "acbios.s" +//#link "hdr_autostart.s" #include #include @@ -15,14 +16,14 @@ const byte palette[8] = { }; void main(void) { - // clear screen - clrscr(); // setup palette set_palette(palette); // set screen height // set horizontal color split (position / 4) // set interrupt status SYS_SETOUT(89*2, 23, 0); + // clear screen + SYS_FILL(0x4000, 89*40, 0); // display standard characters display_string(2, 2, OPT_ON(1), "HELLO, WORLD!!"); // infinite loop diff --git a/presets/astrocade/sprites.c b/presets/astrocade/sprites.c index b280dda7..a08d13d9 100644 --- a/presets/astrocade/sprites.c +++ b/presets/astrocade/sprites.c @@ -24,7 +24,7 @@ void main() { y=10; set_palette(palette); SYS_SETOUT(102*2, 0, 0); - SYS_FILL(0x4000, 89*2, 0); + SYS_FILL(0x4000, 89*40, 0); while (1) { render_sprite(player_bitmap, x, y, M_MOVE); erase_sprite(player_bitmap, x, y); diff --git a/presets/astrocade/vsync.c b/presets/astrocade/vsync.c index 015305b1..f7bac6d3 100644 --- a/presets/astrocade/vsync.c +++ b/presets/astrocade/vsync.c @@ -24,13 +24,17 @@ void main() { byte x,y; x=20; y=20; + memset((void*)0x4FCE, 0, 0x5000-0x4FCE); set_palette(palette); SYS_SETOUT(98*2, 0, 0x0); SYS_FILL(0x4000, 98*40, 0); // clear screen activate_interrupts(); while (1) { write_relative(x, y, M_MOVE, player_bitmap); - sleep(1); + write_relative(x, y+20, M_MOVE, player_bitmap); + write_relative(x, y+40, M_MOVE, player_bitmap); +// write_relative(x, y+60, M_MOVE, player_bitmap); + fast_vsync(); x++; } } diff --git a/src/platform/astrocade.ts b/src/platform/astrocade.ts index 0a7e66b8..05e2018e 100644 --- a/src/platform/astrocade.ts +++ b/src/platform/astrocade.ts @@ -452,16 +452,16 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) { } toLongString(st) { var s = ""; - s += " Scanline: " + st.sl; + s += " Scan Y: " + st.sl; + s += "\n INLIN: " + st.inlin; + s += "\n VERBL: " + st.verbl; s += "\nMAGICOP: $" + hex(st.magicop); s += "\n XPAND: $" + hex(st.xpand); s += "\nXPLOWER: " + st.xplower; s += "\n SHIFT2: $" + hex(st.shift2); s += "\n HORCB: $" + hex(st.horcb); s += "\n INMOD: $" + hex(st.inmod); - s += "\n INLIN: " + st.inlin; s += "\n INFBK: $" + hex(st.infbk); - s += "\n VERBL: " + st.verbl; /* s += "\nPalette: "; for (var i=0; i<8; i++) @@ -481,7 +481,6 @@ class AstrocadeAudio extends AY38910_Audio { setACRegister(addr : number, val : number) { addr &= 0x7; val &= 0xff; - //console.log(addr,val); switch (addr) { case 0: this.psg.setClock(1789000 * 16 / (val + 1));