astrocade: split bios into .s file, fixed interrupt page, added music

This commit is contained in:
Steven Hugg 2019-05-31 15:05:33 -04:00
parent 53d6dce4de
commit 700877e310
13 changed files with 388 additions and 125 deletions

View File

@ -381,3 +381,12 @@ URINAL = 0x4FFF ; WASTER flushes here!
.macro DO CID
.db CID + 1
.endm
;
; EXIT interpreter with context restore:
.macro EXIT
.db XINTC
;INTPCC = 0
.endm
;
ENDx = 0xC0 ; END of DOIT Table
;

View File

@ -1,6 +1,22 @@
/**
AstroLibre
An open source Bally Astrocade BIOS implementation in C
by Steven Hugg (@sehugg) for 8bitworkshop.com
#define TEST
To the extent possible under law, the author(s) have
dedicated all copyright and related and neighboring
rights to this software to the public domain worldwide.
This software is distributed without any warranty.
See: http://creativecommons.org/publicdomain/zero/1.0/
**/
//#resource "astrocade.inc"
//#link "biosasm.s"
// comment out to build BIOS without demo
//#link "test1.s"
#include <string.h>
@ -62,7 +78,7 @@ __sfr __at(0x13) hw_p4ctrl; // player controls
/// GRAPHICS FUNCTIONS
#define VHEIGHT 89 // number of scanlines
#define VHEIGHT 102 // number of scanlines
#define VBWIDTH 40 // number of bytes per scanline
#define PIXWIDTH 160 // 4 pixels per byte
@ -105,82 +121,13 @@ byte SENFLG; // sentry control
byte* UMARGT; // user mask table (-64 bytes)
word* USERTB; // user routine table (-128 bytes)
#ifdef TEST
#define MAIN _main
#else
#define MAIN 0x2000
#endif
// start routine @ 0x0
void bios_start() __naked {
__asm
DI ; disable interrupts
LD HL,#MAIN
LD A,(HL) ; A <- mem[0x2000]
CP #0x55 ; found sentinel byte? ($55)
JP Z,FoundSentinel ; yes, load program
JP MAIN
FoundSentinel:
LD SP,#0x4fce ; position stack below BIOS vars
CALL _bios_init ; misc. bios init routines
LD HL,#(MAIN+5) ; 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;
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
@ -192,6 +139,10 @@ 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 };
// INTERRUPT HANDLERS
// must be in 0x200 page
void hw_interrupt() __interrupt {
CT[0]++;
CT[1]++;
@ -205,7 +156,22 @@ void hw_interrupt() __interrupt {
}
}
const void* const actint_vec = &hw_interrupt;
// TODO
byte 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;
}
}
mask >>= 1;
i++;
}
return any0;
}
void STIMER() {
}
@ -213,6 +179,20 @@ void STIMER() {
void CTIMER() {
}
void TIMEZ() {
// updates game timer, blackout timer, and music processor
}
void TIMEY() {
CT[0]--;
CT[1]--;
CT[2]--;
CT[3]--;
}
void TIMEX() {
}
///// INTERPRETER
typedef struct {
@ -325,17 +305,23 @@ void SUCK(ContextBlock* ctx) {
suckParams(ctx, _B);
}
const void* const actint_vec = &hw_interrupt;
void ACTINT(ContextBlock *ctx) {
ctx;
hw_inlin = 200;
hw_infbk = (byte) &actint_vec;
hw_inmod = 8;
__asm
LD A,#0x2 ; I = 0x200
LD BC,#(_actint_vec) ; upper 8 bits of address
LD A,B
LD I,A
IM 2 ; mode 2
EI ; enable interrupts
__endasm;
hw_inlin = 200;
hw_infbk = (byte) &actint_vec;
hw_inmod = 0x8;
TIMEZ();
TIMEY();
}
// Outputs D to port 0A, B to port 09, A to port 0E.
@ -766,23 +752,3 @@ void bios_init() {
*((byte*)0x4fce) = 0;
hw_magic = 0;
}
#ifdef TEST
void _main() {
__asm
#include "astrocade.inc"
#include "test3.s"
__endasm;
}
#else
void _biosend() __naked {
__asm
; eat up rest of space
.ds 0x2000 - (. - __biosend)
__endasm;
}
#endif

View File

@ -1,34 +1,38 @@
;#link "bioslib.c"
TEST = 1
.module biosasm
.globl _STIMER,_CTIMER,_BIGFONT,_SMLFONT
.area BIOSSTART (ABS)
.org 0x0
BIOSStart:
di ; disable interrupts
ld HL,#0x2000
ld A,(HL) ; A <- mem[0x2000]
cp #0x55 ; found sentinel byte? ($55)
jp Z,FoundSentinel ; yes, load program
.if 1
jp 0x2000 ; jump to $2000
.else
.if TEST
jp _main ; jump to test program
.else
jp 0x2000 ; jump to $2000
.endif
FoundSentinel:
ld SP,#0x4fce ; position stack below BIOS vars
call _bios_init ; misc. bios init routines
.if TEST
ld HL,#(_main+5)
.else
ld HL,#0x2005 ; cartridge start vector
.endif
ld A,(HL)
inc HL
ld H,(HL)
ld L,A
jp (HL) ; jump to cart start vector
.ds 0x38 - (. - BIOSStart) ; eat up space until 0x38
.globl SYSCALL38
SYSCALL38:
.org 0x38
push hl
push af
push bc
@ -47,16 +51,7 @@ SYSCALL38:
pop af
pop hl
ret
DOPEVector:
.org 0x200
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
; TODO?
ReloadRegs:
ld c,(hl)
inc hl
@ -95,4 +90,14 @@ ReloadRegs:
pop hl
pop bc
ret
.ds 0x200 - (. - BIOSStart) ; eat up space until 0x200
DOPEVector:
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

View File

@ -1,5 +1,16 @@
; need these in 1st file sdcc linker sees
.area _HOME
.area _INITIALIZER
.area _DATA
.area _INITIALIZED
.area _BSEG
.area _BSS
.area _HEAP
.area _CODE
.include "astrocade.inc"
.globl _main
_main:
LD SP,#0x4fce ; position stack below BIOS vars
@ -62,7 +73,7 @@ _main:
.dw 3
.dw _BCDNUM
; exit interpreter
DONT XINTC
EXIT
.loop:
SYSSUK DISNUM
.db 80
@ -123,3 +134,5 @@ BALL: .db 0,0
.db 0b11111101
.db 0b01111010
RINGING:
.db 0x80,0x23,0xB0,0x80,0x00,0x3C,0x17,0x3C,0x11,0xE1,0x50,0x3C,0x17,0x3C,0x11,0xE1,0xA0,0xC3,0x5B,0x23,0x00

View File

@ -0,0 +1,49 @@
; Demo 1: HELLO, WORLDS! / 2018 hxlnt
; Inspired by Adam Trionfo Hello World
; http://www.ballyalley.com/ml/ml_homebrew/helloworld/hello.asm
; From: https://github.com/hxlnt/astrocade
; need these in 1st file sdcc linker sees
.area _HOME
.area _INITIALIZER
.area _DATA
.area _INITIALIZED
.area _BSEG
.area _BSS
.area _HEAP
.area _CODE
.include "astrocade.inc"
.globl _main
_main:
.db 0x55 ; ... with the code for a normal menued cartridge
.dw MENUST ; Initialize menu
.dw PrgName ; ... with string at PrgName
.dw PrgStart ; ... such that selecting the program enters PrgStart
PrgName: .ascii "HELLO, WORLDS!"; String
.db 0 ; ... which must be followed by 0
PrgStart: DI ; Disable interrupts
LD SP,#0x4fce ; position stack below BIOS vars
ld hl,#0x20d ; small font -> IX
push hl
pop ix
SYSTEM INTPC ; Begin interpreter mode
DO SETOUT ; Set output ports
.db 100*2 ; ... with VBLANK line set to line 100
.db 112/4 ; ... with color boundary 112 pixels from the left of the screen
.db 0b00001000 ; ... with screen interrupts reenabled
DO COLSET ; Set color palettes
.dw Palettes ; ... with the values at Palettes
DO FILL ; Set background fill
.dw NORMEM ; ... starting at the beginning of screen RAM
.dw 99*BYTEPL ; ... and going for 100 lines
.db 0b00010010 ; ... with a fill pattern of three different colored pixels
DO STRDIS ; Set string display
.db 0 ; ... starting 0 pixels from the left of the screen
.db 32 ; ... and 32 pixels from the top of the screen
.db 0b00001100 ; ... with no enlargement, foreground color = 11, background color = 00
.dw PrgName ; ... to show string at PrgName
DONT XINTC
Loop: JP Loop ; Play infinite loop
Palettes: .db 0xBF,0x00,0x00,0x00 ; Left color palette (11b, 10b, 01b, 00b)
.db 0xE7,0x9A,0x39,0x19 ; Right color palette (11b, 10b, 01b, 00b)

View File

@ -0,0 +1,103 @@
; "HORCB Pal" demo 2018 hxlnt
; Inspired by Michael Garber Color Picker
; http://ballyalley.com/ml/ml_homebrew/colorpicker.asm
; From: https://github.com/hxlnt/astrocade
; need these in 1st file sdcc linker sees
.area _HOME
.area _INITIALIZER
.area _DATA
.area _INITIALIZED
.area _BSEG
.area _BSS
.area _HEAP
.area _CODE
.include "astrocade.inc"
.globl _main
_main:
FrameCount = 0x4F00 ; Reserve a space for a frame counter
.db 0x55 ; ... with the code for a normal menued cartridge
.dw MENUST ; Initialize menu
.dw PrgName ; ... with string at PrgName
.dw PrgStart ; ... such that selecting the program enters PrgStart
PrgName: .ascii "HORCB PAL" ; String
.db 0 ; ... which must be followed by 0
PrgStart: DI ; Disable interrupts
LD SP,#0x4fce ; position stack below BIOS vars
ld hl,#0x20d ; small font -> IX
push hl
pop ix
SYSTEM INTPC ; Begin interpreter mode
DO SETOUT ; Set output ports
.db 96*2 ; ... with VBLANK line set to line 96
.db 0/4 ; ... with color boundary 0 pixels from the left of the screen
.db 0b00001000 ; ... with screen interrupts enabled
DO COLSET ; Set color palettes
.dw Palettes ; ... with the values at Palettes
DO FILL ; Set background fill
.dw NORMEM ; ... starting at the beginning of screen RAM
.dw 24*BYTEPL ; ... and going for 24 lines
.db 0b00011011 ; ... with a fill pattern of four different colored pixels
DO FILL ; Set background fill
.dw NORMEM+(24*BYTEPL)
.dw 24*BYTEPL ; ... and going for 24 lines
.db 0b00000000 ; ... with a solid fill of color 00
DO FILL ; Set background fill
.dw NORMEM+(48*BYTEPL)
.dw 24*BYTEPL ; ... and going for 24 lines
.db 0b11111111 ; ... with a solid fill of color 11
DO STRDIS ; Set string display
.db 28 ; ... starting 28 pixels from the left of the screen
.db 40 ; ... and 40 pixels from the top of the screen
.db 0b00001100 ; ... with no enlargement, foreground color = 11, background color = 00
.dw PrgName ; ... with string at PrgName
DONT XINTC ; Exit interpreter mode
Loop: IN A,(POT0) ; Let A = controller 1 knob value
OUT (HORCB),A ; Let horizontal color boundary = A
CALL UpdateDisp ; Call UpdateDisp subroutine
JP Loop ; Go back to beginning of infinite loop
Palettes: .db 0xF4,0x1C,0x1F,0x5F ; Left color palette (11b, 10b, 01b, 00b)
.db 0xED,0xCD,0xD5,0x8E ; Right color palette (11b, 10b, 01b, 00b)
UpdateDisp:
DI ; Disable interrupts
PUSH AF ; Push AF to SP
LD C,A ; Get first hex digit from knob value
SRL C ; ...
SRL C ; ...
SRL C ; ...
SRL C ; ...
LD B,#0 ; Display first hex digit from knob value
LD HL,#Hex ; ... Load HL with address Hex
ADD HL,BC ; ... Offset Hex by BC to get first hex digit
LD A,(HL) ; ... Load A with first hex digit
LD C,#0b00000100 ; ... Load C with string options
LD D,#40 ; ... Load D with string Y-coordinate
LD E,#120 ; ... Load E with X-coordinate
SYSTEM (CHRDIS) ; ... Display first digit
POP AF ; Pop AF off SP
AND A,#0x0F ; Get second hex digit from knob value
LD C,A ; ...
LD B,#0 ; Display second hex digit from knob value
LD HL,#Hex ; ... Load HL with address Hex
ADD HL,BC ; ... Offset Hex by BC to get second hex digit
LD A,(HL) ; ... Load A with second hex digit
LD C,#0b00000100 ; ... Load C with string options
LD D,#40 ; ... Load D with Y-coordinate
LD E,#128 ; ... Load E with X-coordinate
SYSTEM (CHRDIS) ; ... Display second digit
LD A,(FrameCount) ; Increment frame counter
INC A ; ...
LD (FrameCount),A ; ...
AND #0b00000111 ; Every fourth frame, run AnimBars
CP #0b00000100 ; ...
JR Z, AnimBars ; ...
JP AnimDone ; Otherwise, skip AnimBars
AnimBars: SYSSUK RANGED ; Load a random 8-bit number in A
.db 0 ; ...
LD BC,#24*BYTEPL ; Load BC with one scanline length
LD DE,#NORMEM+(72*BYTEPL)
SYSTEM FILL ; Fill remainder of screen with repeating random tile
AnimDone: EI ; Enable interrupts
RET ; Return from subroutine
Hex: .ascii "0123456789ABCDEF"

View File

@ -20,6 +20,17 @@ __asm
__endasm;
}
// set entire sound registers at once (8 bytes to port 0x18)
// bytes in array should be in reverse
void set_sound_registers(byte regs[8]) __z88dk_fastcall {
regs;
__asm
ld bc,#0x818 ; B -> 8, C -> 0x18
otir ; write C bytes from HL to port[B]
ret ; return
__endasm;
}
// draw vertical line
void vline(byte x, byte y1, byte y2, byte col, byte op) {
byte* dest = &vmagic[y1][x>>2];// destination address

View File

@ -81,6 +81,7 @@ byte __at (0x4000) vidmem[VTOTAL][VBWIDTH];
void clrscr();
void set_palette(byte palette[8]) __z88dk_fastcall; // palette in reverse order
void set_sound_registers(byte regs[8]) __z88dk_fastcall; // in reverse too
void vline(byte x, byte y1, byte y2, byte col, byte op);
void pixel(byte x, byte y, byte col, byte op);
void render_sprite(const byte* src, byte x, byte y, byte op);

98
presets/astrocade/music.c Normal file

File diff suppressed because one or more lines are too long

View File

@ -15,6 +15,7 @@ const ASTROCADE_PRESETS = [
{id:'lines.c', name:'Lines'},
{id:'sprites.c', name:'Sprites'},
{id:'vsync.c', name:'Sprites w/ VSYNC'},
{id:'music.c', name:'Music'},
{id:'cosmic.c', name:'Cosmic Impalas Game'},
];
@ -339,6 +340,7 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
}
// interrupt
if (sl == inlin && (inmod & 0x8)) {
// TODO: interrupt mode bit 0x4
cpu.requestInterrupt(infbk);
}
// refresh this line in frame buffer?
@ -458,7 +460,7 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
s += "\n HORCB: $" + hex(st.horcb);
s += "\n INMOD: $" + hex(st.inmod);
s += "\n INLIN: " + st.inlin;
s += "\n INFBK: " + st.infbk;
s += "\n INFBK: $" + hex(st.infbk);
s += "\n VERBL: " + st.verbl;
/*
s += "\nPalette: ";

View File

@ -120,7 +120,7 @@ export class CodeProject {
}
return files;
}
loadFileDependencies(text:string) : Promise<Dependency[]> {
let includes = this.parseIncludeDependencies(text);
let linkfiles = this.parseLinkDependencies(text);

View File

@ -1182,7 +1182,7 @@ function getDebugExprExamples() : string {
if (cpu.SP) s += "c.SP < 0x" + hex(cpu.SP) + "\n";
if (platform.readAddress) s += "this.readAddress(0x1234) == 0x0\n";
if (platform.readVRAMAddress) s += "this.readVRAMAddress(0x1234) != 0x80\n";
if (platform['getRasterPosition']) s += "this.getRasterPosition().y > 222\n";
if (platform['getRasterScanline']) s += "this.getRasterScanline() > 222\n";
return s;
}

View File

@ -2020,8 +2020,14 @@ function executeBuildSteps() {
for (var i=0; i<buildsteps.length; i++) {
var ls = buildsteps[i];
if (ls.tool == linkstep.tool && ls.platform == linkstep.platform && ls.files && ls.args) {
ls.files = ls.files.concat(linkstep.files);
ls.args = ls.args.concat(linkstep.args);
if (step.result.order === 'last') { // TODO: not used
ls.files = linkstep.files.concat(ls.files);
ls.args = linkstep.args.concat(ls.args);
} else {
ls.files = ls.files.concat(linkstep.files);
ls.args = ls.args.concat(linkstep.args);
}
console.log(ls);
linkstep = null;
break;
}