astrocade: added bmusic, updated aclib

This commit is contained in:
Steven Hugg 2019-06-01 22:09:45 -04:00
parent fcc358a1ab
commit 50421a69f3
20 changed files with 277 additions and 43 deletions

View File

@ -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

View File

@ -18,6 +18,9 @@ See: http://creativecommons.org/publicdomain/zero/1.0/
// demo code
//#link "test1.s"
// music processor
//#link "bmusic.c"
#include <string.h>
// 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<<i;
}
}
}
mask >>= 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);
}

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -2,6 +2,7 @@
#include <string.h>
#include "aclib.h"
#include "acextra.h"
#define EXIT_CLIPDEST(addr) if ((((word)addr)&0xfff) >= 0xe10) return

View File

@ -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);

View File

@ -2,6 +2,8 @@
#include <string.h>
#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 {

View File

@ -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

View File

@ -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

View File

@ -7,6 +7,9 @@
#include <string.h>
//#resource "astrocade.inc"
#include "acbios.h"
//#link "acbios.s"
#include "aclib.h"
//#link "aclib.c"
#include "acextra.h"

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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 <stdlib.h>
#include <string.h>
@ -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

View File

@ -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);

View File

@ -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++;
}
}

View File

@ -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));