From 9e900a5a26a0da5616b40fe7c463eec0977aa509 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Tue, 28 Aug 2018 18:11:22 -0400 Subject: [PATCH] started on the cade that is astro --- doc/notes.txt | 1 + index.html | 2 + presets/astrocade/01-helloworlds.asm | 35 ++ presets/astrocade/02-telephone.asm | 52 ++ presets/astrocade/02-telephone.gfx | 26 + presets/astrocade/03-horcbpal.asm | 88 ++++ presets/astrocade/hvglib.h | 683 +++++++++++++++++++++++++++ src/audio.ts | 37 +- src/baseplatform.ts | 7 + src/cpu/z80fast.js | 2 +- src/platform/astrocade.ts | 369 +++++++++++++++ src/platform/vector.ts | 4 +- src/project.ts | 4 +- 13 files changed, 1289 insertions(+), 21 deletions(-) create mode 100644 presets/astrocade/01-helloworlds.asm create mode 100644 presets/astrocade/02-telephone.asm create mode 100644 presets/astrocade/02-telephone.gfx create mode 100644 presets/astrocade/03-horcbpal.asm create mode 100644 presets/astrocade/hvglib.h create mode 100644 src/platform/astrocade.ts diff --git a/doc/notes.txt b/doc/notes.txt index 6d8cd962..75f44270 100644 --- a/doc/notes.txt +++ b/doc/notes.txt @@ -57,6 +57,7 @@ TODO: - stop debugging where mouse clicked - bring back the profiler! - vcs disasm is broken +- links to external tools in ide On the website the additional grey spacing next to the program line numbers is not dynamically resized when the web browser window size is changed. Intentional? diff --git a/index.html b/index.html index dbf30529..1de33d4a 100644 --- a/index.html +++ b/index.html @@ -318,6 +318,8 @@ function require(modname) { + + diff --git a/presets/astrocade/01-helloworlds.asm b/presets/astrocade/01-helloworlds.asm new file mode 100644 index 00000000..e05df2b9 --- /dev/null +++ b/presets/astrocade/01-helloworlds.asm @@ -0,0 +1,35 @@ +; Demo 1: HELLO, WORLDS! / 2018 hxlnt +; Inspired by Adam Trionfo's Hello World +; http://www.ballyalley.com/ml/ml_homebrew/helloworld/hello.asm +; Assemble with Zmac 1.3 +; From: https://github.com/hxlnt/astrocade + + INCLUDE "hvglib.h" ; Include HVGLIB library + ORG FIRSTC ; Initialize at beginning of cartridge ROM area + DB $55 ; ... 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: DB "HELLO, WORLDS!"; String + DB 0 ; ... which must be followed by 0 +PrgStart: DI ; Disable interrupts + 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 00001000b ; ... 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 100*BYTEPL ; ... and going for 100 lines + DB 00010010b ; ... 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 00001100b ; ... with no enlargement, foreground color = 11, background color = 00 + DW PrgName ; ... to show string at PrgName +; EXIT ; Exit interpreter mode +Loop: JP Loop ; Play infinite loop +Palettes: DB $BF,$00,$00,$00 ; Left color palette (11b, 10b, 01b, 00b) + DB $E7,$9A,$39,$19 ; Right color palette (11b, 10b, 01b, 00b) diff --git a/presets/astrocade/02-telephone.asm b/presets/astrocade/02-telephone.asm new file mode 100644 index 00000000..3484d016 --- /dev/null +++ b/presets/astrocade/02-telephone.asm @@ -0,0 +1,52 @@ +; Telephone +; Inspired by Adam Trionfo's Happy Birthday Music +; http://ballyalley.com/ml/ml_homebrew/birthday.asm +; Assemble with Zmac 1.3 +; From: https://github.com/hxlnt/astrocade + + INCLUDE "hvglib.h" ; Include HVGLIB library +MUSICSP = $4FD2 ; Music stack pointer + ORG FIRSTC ; Initialize at beginning of cartridge ROM area + DB $55 ; ... 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: DB "TELEPHONE" ; String to be displayed on menu + DB 0 ; ... which must be followed by 0 +PrgStart: DI ; Disable interrupts + SYSTEM INTPC ; Begin interpreter mode + DO SETOUT ; Set output ports + DB 80*2 ; ... with VBLANK line set to line 80 + DB 44/4 ; ... with color boundary 44 pixels from the left of the screen + DB 00001000b ; ... with screen interrupts reenabled + DO COLSET ; Set color palettes + DW Palettes ; ... with the values at Palettes + DO FILL ; Fill screen + DW NORMEM ; ... starting at the beginning of screen RAM + DW 81*BYTEPL ; ... and going for 81 lines + DB 00000000b ; ... with a solid black (color 0) fill pattern + DO MOVE ; Display graphic + DW NORMEM+(38*BYTEPL) + DW 20*BYTEPL ; ... copy 20 lines + DW Telephone ; ... from data at location Telephone + DO ACTINT ; Activate subtimer interrupts + DO BMUSIC ; Play music + DW MUSICSP ; ... using predefined music stack address + DB 00110011B ; ... setting tone B, vibrato, noise bits + DW Ringing ; ... with music score defined at Ringing + EXIT ; Exit interpreter mode +Loop: JP Loop ; Play infinite loop +Palettes: DB $07,$FE,$FB,$00 ; Left color palette (11b, 10b, 01b, 00b) + DB $07,$4F,$CB,$00 ; Right color palette (11b, 10b, 01b, 00b) +Telephone: ; Telephone graphic + INCLUDE "02-telephone.gfx" +Ringing: ; Music score + MASTER OA3 ; + VOLUME $80, $00 ; + NOTE1 60, C4 ; ... in which notes oscillate between C4 + NOTE1 60, F4 ; ... and F4 + REST 80 ; ... followed by a short rest + NOTE1 60, C4 ; ... then another ring + NOTE1 60, F4 ; + REST 160 ; ... and a long rest + JP Ringing ; ... ending in replay \ No newline at end of file diff --git a/presets/astrocade/02-telephone.gfx b/presets/astrocade/02-telephone.gfx new file mode 100644 index 00000000..e1ab5f7f --- /dev/null +++ b/presets/astrocade/02-telephone.gfx @@ -0,0 +1,26 @@ + DB $0, $0, $0, $0, $0, $0, $0, $33, $0, $FF, $0, $EE, $0, $EE, $0, $AA, $0, $AA, $0, $AA, $0, $AA, $0, $AA, $0, $BB, $0, $BB, $0, $FF, $0, $CC, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0, $33, $0, $FF, $0, $EE, $0, $AA, $0, $AA, $0, $AA, $0, $AA, $0, $AA, $0, $AA, $0, $BB, $0, $FF, $0, $CC, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0, $FF, $D0, $0, $03, $FF, $FD, $3F, $FD, $0F, $0, $03, $FF, $D0, $FF, $40, $3C, $0F, $0F, $FD, $03, $FF, $40, $FF, $F4, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0F, $55, $55, $0, $03, $55, $54, $D5, $55, $35, $0, $0D, $55, $53, $55, $50, $D4, $35, $35, $55, $4D, $55, $53, $55, $54, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $1D, $55, $55, $40, $0, $05, $40, $D4, $0, $35, $0, $0D, $40, $03, $50, $54, $D4, $35, $35, $05, $4D, $41, $53, $50, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $55, $20, $85, $54, $0, $05, $40, $54, $0, $15, $0, $05, $40, $01, $50, $14, $54, $15, $15, $05, $45, $41, $51, $50, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $55, $AA, $A5, $5C, $0, $05, $40, $54, $0, $15, $0, $05, $40, $01, $50, $54, $54, $15, $15, $05, $45, $41, $51, $50, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $16, $AA, $A9, $45, $0, $05, $40, $57, $FD, $15, $0, $05, $7F, $D1, $5F, $50, $57, $D5, $15, $05, $45, $41, $51, $5F, $F4, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0A, $77, $6A, $02, $C0, $05, $40, $55, $55, $15, $0, $05, $55, $51, $55, $40, $55, $55, $15, $05, $45, $41, $51, $55, $54, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0A, $EE, $EA, $01, $0, $05, $40, $54, $0, $15, $0, $05, $40, $01, $50, $0, $54, $15, $15, $05, $45, $41, $51, $50, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $2A, $77, $6A, $8B, $0, $05, $40, $54, $0, $15, $0, $05, $40, $01, $50, $0, $54, $15, $15, $05, $45, $41, $51, $50, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $2A, $EE, $EA, $85, $0, $05, $40, $54, $0, $15, $0, $05, $40, $01, $50, $0, $54, $15, $15, $05, $45, $41, $51, $50, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $2A, $AA, $AA, $8B, $0, $05, $40, $57, $FD, $15, $FF, $45, $7F + DB $D1, $50, $0, $54, $15, $15, $F5, $45, $41, $51, $5F, $F4, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $05, $55, $55, $14, $0, $01, $40, $15, $55, $05, $55, $41, $55 + DB $51, $50, $0, $14, $05, $05, $55, $01, $40, $50, $55, $54, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $0, $33, $0, $FF, $0, $EE, $0, $AA, $0, $AA, $0, $AA, $0, $AA, $0, $AA, $0, $AA, $0, $BB, $0, $FF, $0, $CC, $0, $0, $0, $0, $0, $0, $0, $0, $0 + DB $0, $0, $0, $0, $0, $0, $0, $33, $0, $FF, $0, $EE, $0, $EE, $0, $AA, $0, $AA, $0, $AA, $0, $AA, $0, $AA, $0, $BB, $0, $BB, $0, $FF, $0, $CC, $0, $0, $0, $0, $0, $0, $0, $0 diff --git a/presets/astrocade/03-horcbpal.asm b/presets/astrocade/03-horcbpal.asm new file mode 100644 index 00000000..97d68e2e --- /dev/null +++ b/presets/astrocade/03-horcbpal.asm @@ -0,0 +1,88 @@ +; "HORCB Pal" demo 2018 hxlnt +; Inspired by Michael Garber's Color Picker +; http://ballyalley.com/ml/ml_homebrew/colorpicker.asm +; Assemble with Zmac 1.3 +; From: https://github.com/hxlnt/astrocade + + INCLUDE "hvglib.h" ; Include HVGLIB library +FrameCount EQU $4F00 ; Reserve a space for a frame counter + ORG FIRSTC ; Initialize at beginning of cartridge ROM area + DB $55 ; ... 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: DB "HORCB PAL" ; String + DB 0 ; ... which must be followed by 0 +PrgStart: DI ; Disable interrupts + 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 00001000b ; ... 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 00011011b ; ... 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 00000000b ; ... 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 11111111b ; ... 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 00001100b ; ... with no enlargement, foreground color = 11, background color = 00 + DW PrgName ; ... with string at PrgName + EXIT ; 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 $F4,$1C,$1F,$5F ; Left color palette (11b, 10b, 01b, 00b) + DB $ED,$CD,$D5,$8E ; 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,00000100b ; ... 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 $0F ; 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,00000100b ; ... 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 00000111b ; Every fourth frame, run AnimBars + CP 00000100b ; ... + JR Z, AnimBars ; ... + JP AnimDone ; Otherwise, skip AnimBars +AnimBars: SYSSUK RANGED ; Load a random 8-bit number in A + DEFB 0 ; ... + LD BC,24*BYTEPL ; Load BC with one scanline's 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: DB "0123456789ABCDEF" diff --git a/presets/astrocade/hvglib.h b/presets/astrocade/hvglib.h new file mode 100644 index 00000000..368005e7 --- /dev/null +++ b/presets/astrocade/hvglib.h @@ -0,0 +1,683 @@ +; ****** HVGLIB.H (formally called ballyequ.h) (C)1977,78 +; *** Bally Astrocade Equates and Macros Header File *** +; From the nutting_manual and reformatted using Mixed Case +; Version 3.01 - thru December 29, 2010 +; by Richard C Degler, from scratch +; +; > Retyped and proofread by Adam Trionfo and Lance F. Squire +; > Version 1.0 (as ballyequ.h) - January 17, 2002 +; > Version 2.52 (Version 1.0 of HVGLIB.H) - March 28, 2003 +; > Version 2.6 - March 2, 2004 - as seen on BallyAlley.com +; > Version 3.0 - 2009 +; > Version 3.01 - Changed "FonT BASE character" comment +; > (also patched for latest zmac with default args) +; > +; > This file contains the equates and macros that Bally +; > programs require for assembly. This file has been +; > written to assemble with ZMAC 1.3 (a freely distribut- +; > able Z-80 assembler (with C source), that has a 25-year +; > history. ZMAC can be compiled under just about any O.S. +; > in existence, so try it out. This file will probably +; > require changes to be assembled under other assemblers. +; > +; > To assemble your Z-80 source code using ZMAC: +; > +; > zmac -d -o -x +; > +; > For example, assemble this Astrocade Z-80 ROM file: +; > +; > zmac -d -o BallyROM.bin -x BallyROM.lst BallyROM.asm +; > +; > Currently the Listing file is full of 'Undeclared' +; > errors. When all of the source is typed-in, these will +; > vanish. I'm leaving the others until all the source is +; > re-typed. +; > +; +; *************************** +; * Home Video Game EQUates * +; *************************** +; +; ASSEMBLY CONTROL +; +XPNDON EQU 1 ; ** SET TO 1 WHEN HARDWARE EXP +NWHDWR EQU 1 ; ** SET TO 1 WHEN NEW HARDWARE +; +; General goodies (HEX and Decimal values): +NORMEM EQU $4000 ; 8192 ; NORmal MEMory start +FIRSTC EQU $2000 ; 4096 ; FIRST address in Cartridge +SCREEN EQU $0000 ; 0 ; magic SCREEN start +BYTEPL EQU $28 ; 40 ; BYTEs Per Line +BITSPL EQU $A0 ; 160 ; BITS Per Line +; +; Stuff in SYSTEM DOPE VECTOR (valid for ALL system ROMs): +STIMER EQU $0200 ; Seconds and game TIMER, music +CTIMER EQU $0203 ; Custom TIMERs +FNTSYS EQU $0206 ; FoNT descriptor for SYStem font +FNTSML EQU $020D ; FoNT descriptor for SMaLl font +ALKEYS EQU $0214 ; ALl KEYS keypad mask +MENUST EQU $0218 ; head of onboard MENU STart +MXSCR EQU $021E ; address of 'MaX SCoRe' text string +NOPLAY EQU $0228 ; address of 'Number Of PLAYers' string +NOGAME EQU $0235 ; address of 'Number Of GAMEs' string +; +; BITS in PROCESSOR FLAG byte: +PSWCY EQU 0 ; Processor Status Word, CarrY bit +PSWPV EQU 2 ; Processor Status Word, Parity or oVerflow bit +PSWZRO EQU 6 ; Processor Status Word, ZeRO bit +PSWSGN EQU 7 ; Processor Status Word, SiGN bit +; +; BITS in GAME STATUS Byte: +GSBTIM EQU 0 ; Game Status Byte, if TIMe is up set end bit +GSBSCR EQU 1 ; Game Status Byte, if SCoRe reached set end bit +GSBEND EQU 7 ; Game Status Byte, END flag bit +; +; Standard VECTOR DISPLACEMENTS and bits: +VBMR EQU $00 ; +0 ; Vector Block, Magic Register +VBSTAT EQU $01 ; +1 ; Vector Block, STATus byte +VBTIMB EQU $02 ; +2 ; Vector Block, TIMe Base +VBDXL EQU $03 ; +3 ; Vector Block, Delta for X Low +VBDXH EQU $04 ; +4 ; Vector Block, Delta for X Hi +VBXL EQU $05 ; +5 ; Vector Block, X coord Low +VBXH EQU $06 ; +6 ; Vector Block, X coord Hi +VBXCHK EQU $07 ; +7 ; Vector Block, X CHecK flags +VBDYL EQU $08 ; +8 ; Vector Block, Delta for Y Low +VBDYH EQU $09 ; +9 ; Vector Block, Delta for Y Hi +VBYL EQU $0A ; +10 ; Vector Block, Y coord Low +VBYH EQU $0B ; +11 ; Vector Block, Y coord Hi +VBYCHK EQU $0C ; +12 ; Vector Block, Y CHecK flags +VBOAL EQU $0D ; +13 ; Vector Block, Old Address Low +VBOAH EQU $0E ; +14 ; Vector Block, Old Address Hi +; +; DISPLACEMENTS from start of COORDINATE AREA (X or Y): +VBDCL EQU $00 ; +0 ; Vector Block, Delta for Coord Low +VBDCH EQU $01 ; +1 ; Vector Block, Delta for Coord Hi +VBCL EQU $02 ; +2 ; Vector Block, Coord Low +VBCH EQU $03 ; +3 ; Vector Block, Coord Hi +VBCCHK EQU $04 ; +4 ; Vector Block, Coord CHecK flags +; +; BITS in STATUS byte: +VBBLNK EQU 6 ; Vector Block status, BLaNK bit +VBSACT EQU 7 ; Vector Block Status, ACTive bit +; +; BITS in (X or Y) VB CHECK FLAG bit mask: +VBCLMT EQU 0 ; Vector Block Check, LiMiT bit +VBCREV EQU 1 ; Vector Block Check, REVerse delta on limit attain +VBCLAT EQU 3 ; Vector Block Check, coordinate Limit ATtained +; +; FONT TABLE DISPLACEMENTS for CHARACTER DESCRIPTOR BLOCK: +FTBASE EQU $00 ; +0 ; FonT BASE character (normally $A0) +FTFSX EQU $01 ; +1 ; FonT Frame X Size width +FTFSY EQU $02 ; +2 ; FonT Frame Y Size height +FTBYTE EQU $03 ; +3 ; FonT X size for char in BYTEs +FTYSIZ EQU $04 ; +4 ; FonT Y SIZe height in rows +FTPTL EQU $05 ; +5 ; FonT Pattern Table address Low +FTPTH EQU $06 ; +6 ; FonT Pattern Table address Hi +; +; BITS for MAGIC REGISTER (write option) byte: +MRSHFT EQU $03 ; Magic Register, mask of SHiFT amount 0-3 +MRROT EQU 2 ; Magic Register, write with ROTata bit +MRXPND EQU 3 ; Magic Register, write with eXPaND bit +MROR EQU 4 ; Magic Register, write with OR bit +MRXOR EQU 5 ; Magic Register, write with eXclusive-OR bit +MRFLOP EQU 6 ; Magic Register, write with FLOP bit +; +; BITS of CONTROL HANDLE Input port: +CHUP EQU 0 ; Control Handle, UP bit +CHDOWN EQU 1 ; Control Handle, DOWN bit +CHLEFT EQU 2 ; Control Handle, joystick LEFT bit +CHRIGH EQU 3 ; Control Handle, joystick RIGHT bit +CHTRIG EQU 4 ; Control Handle, TRIGger bit +; +; CONTEXT BLOCK Register DISPLACEMENTS: +CBIYL EQU $00 ; +0 ; Context Block, IY register Low +CBIYH EQU $01 ; +1 ; Context Block, IY register Hi +CBIXL EQU $02 ; +2 ; Context Block, IX register Low +CBIXH EQU $03 ; +3 ; Context Block, IX register Hi +CBE EQU $04 ; +4 ; Context Block, E register +CBD EQU $05 ; +5 ; Context Block, D register +CBC EQU $06 ; +6 ; Context Block, C register +CBB EQU $07 ; +7 ; Context Block, B register +CBFLAG EQU $08 ; +8 ; Context Block, FLAGs register +CBA EQU $09 ; +9 ; Context Block, A register +CBL EQU $0A ; +10 ; Context Block, L register +CBH EQU $0B ; +11 ; Context Block, H register +; +; SENTRY RETURN Codes EQUates: +SNUL EQU $00 ; Sentry return NULl, nothing happened +SCT0 EQU $01 ; Sentry, Counter-Timer 0 has counted down +SCT1 EQU $02 ; Sentry, Counter-Timer 1 has counted down +SCT2 EQU $03 ; Sentry, Counter-Timer 2 has counted down +SCT3 EQU $04 ; Sentry, Counter-Timer 3 has counted down +SCT4 EQU $05 ; Sentry, Counter-Timer 4 has counted down +SCT5 EQU $06 ; Sentry, Counter-Timer 5 has counted down +SCT6 EQU $07 ; Sentry, Counter-Timer 6 has counted down +SCT7 EQU $08 ; Sentry, Counter-Timer 7 has counted down +SF0 EQU $09 ; Sentry, Flag bit 0 has changed +SF1 EQU $0A ; Sentry, Flag bit 1 has changed +SF2 EQU $0B ; Sentry, Flag bit 2 has changed +SF3 EQU $0C ; Sentry, Flag bit 3 has changed +SF4 EQU $0D ; Sentry, Flag bit 4 has changed +SF5 EQU $0E ; Sentry, Flag bit 5 has changed +SF6 EQU $0F ; Sentry, Flag bit 6 has changed +SF7 EQU $10 ; Sentry, Flag bit 7 has changed +SSEC EQU $11 ; Sentry, SEConds timer has counted down +SKYU EQU $12 ; Sentry, KeY is now Up +SKYD EQU $13 ; Sentry, KeY is now Down +ST0 EQU $14 ; Sentry, Trigger 0 for player 1 has changed +SJ0 EQU $15 ; Sentry, Joystick 0 for player 1 has changed +ST1 EQU $16 ; Sentry, Trigger 1 for player 2 has changed +SJ1 EQU $17 ; Sentry, Joystick 1 for player 2 has changed +ST2 EQU $18 ; Sentry, Trigger 2 for player 3 has changed +SJ2 EQU $19 ; Sentry, Joystick 2 for player 3 has changed +ST3 EQU $1A ; Sentry, Trigger 3 for player 4 has changed +SJ3 EQU $1B ; Sentry, Joystick 3 for player 4 has changed +SP0 EQU $1C ; Sentry, POTentiometer 0 has changed +SP1 EQU $1D ; Sentry, POTentiometer 1 has changed +SP2 EQU $1E ; Sentry, POTentiometer 2 has changed +SP3 EQU $1F ; Sentry, POTentiometer 3 has changed +; +; +; ******************************** +; * Home Video Game PORT EQUates * +; ******************************** +; +; OUTPUT Ports for VIRTUAL COLOR: +COL0R EQU $00 ; &(0)= ; write COLor 0 Right +COL1R EQU $01 ; &(1)= ; write COLor 1 Right +COL2R EQU $02 ; &(2)= ; write COLor 2 Right +COL3R EQU $03 ; &(3)= ; write COLor 3 Right +COL0L EQU $04 ; &(4)= ; write COLor 0 Left +COL1L EQU $05 ; &(5)= ; write COLor 1 Left +COL2L EQU $06 ; &(6)= ; write COLor 2 Left +COL3L EQU $07 ; &(7)= ; write COLor 3 Left +HORCB EQU $09 ; &(9)= ; write HORizontal Color Boundary +VERBL EQU $0A ;&(10)= ; write VERtical Blanking Line +COLBX EQU $0B ;&(11)= ; write COLor BloCK multi-port +; +; OUTPUT Ports for MUSIC and SOUNDS: +TONMO EQU $10 ;&(16)= ; write TONe Master Oscillator +TONEA EQU $11 ;&(17)= ; write TONe A oscillator +TONEB EQU $12 ;&(18)= ; write TONe B oscillator +TONEC EQU $13 ;&(19)= ; write TONe C oscillator +VIBRA EQU $14 ;&(20)= ; write VIBRAto frequency & range +VOLC EQU $15 ;&(21)= ; write VOLume of tone C +VOLAB EQU $16 ;&(22)= ; write VOLumes of tones A & B +VOLN EQU $17 ;&(23)= ; write VOLume of Noise +SNDBX EQU $18 ;&(24)= ; write SouND BloCK multi-port +; +; INTERRUPT and CONTROL OUTPUT Ports: +CONCM EQU $08 ; &(8)= ; write 0 for CONsumer, 1 for CoMmercial mode +MAGIC EQU $0C ;&(12)= ; write MAGIC register +INFBK EQU $0D ;&(13)= ; write INterrupt FeedBacK +INMOD EQU $0E ;&(14)= ; write INterrupt MODe +INLIN EQU $0F ;&(15)= ; write INterrupt LINe +XPAND EQU $19 ;&(25)= ; eXPANDer pixel definition port +; +; INTERRUPT and INTERCEPT INPUT Ports: +INTST EQU $08 ; =&(8) ; read INTercept STatus +VERAF EQU $0E ;=&(14) ; read VERtical Address Feedback +HORAF EQU $0F ;=&(15) ; read HORizontal Address Feedback +; +; HAND CONTROL INPUT Ports: +SW0 EQU $10 ;=&(16) ; read SWitch bank 0 for player 1 hand control +SW1 EQU $11 ;=&(17) ; read SWitch bank 1 for player 2 hand control +SW2 EQU $12 ;=&(18) ; read SWitch bank 2 for player 3 hand control +SW3 EQU $13 ;=&(19) ; read SWitch bank 3 for player 4 hand control +POT0 EQU $1C ;=&(28) ; read POTentiometer 0 for player 1 knob +POT1 EQU $1D ;=&(29) ; read POTentiometer 1 for player 2 knob +POT2 EQU $1E ;=&(30) ; read POTentiometer 2 for player 3 knob +POT3 EQU $1F ;=&(31) ; read POTentiometer 3 for player 4 knob +; +; KEYBOARD INPUT Ports: +KEY0 EQU $14 ;=&(20) ; KEYboard column 0 (right side) +KEY1 EQU $15 ;=&(21) ; KEYboard column 1 (center right) +KEY2 EQU $16 ;=&(22) ; KEYboard column 2 (center left) +KEY3 EQU $17 ;=&(23) ; KEYboard column 3 (left side) +; +; +; *************************************** +; * Home Video Game SYSTEM CALL Indexes * +; *************************************** +; +; USER PROGRAM Interface: +INTPC EQU $00 ; # 0 ; INTerPret with Context create +XINTC EQU $02 ; # 2 ; eXit INTerpreter with Context +RCALL EQU $04 ; # 4 ; Real CALL asm language subroutine +MCALL EQU $06 ; # 6 ; Macro CALL interpreter subroutine +MRET EQU $08 ; # 8 ; Macro RETurn from interpreter subroutine +MJUMP EQU $0A ; # 10 ; Macro JUMP to interpreter subroutine +SUCK EQU $0C ; # 12 ; SUCK inline args into context block +; +; SCHEDULER Routines: +ACTINT EQU $0E ; # 14 ; ACTivate sub timer INTerrupts +DECCTS EQU $10 ; # 16 ; DECrement CT'S under mask +; +; MUSIC and SOUNDS: +BMUSIC EQU $12 ; # 18 ; Begin playing MUSIC +EMUSIC EQU $14 ; # 20 ; End playing MUSIC +; +; SCREEN HANDLER Routines: +SETOUT EQU $16 ; # 22 ; SET some OUTput ports +COLSET EQU $18 ; # 24 ; COLors SET +FILL EQU $1A ; # 26 ; FILL memory with data +RECTAN EQU $1C ; # 28 ; paint a RECTANgle +VWRITR EQU $1E ; # 30 ; Vector WRITe Relative +WRITR EQU $20 ; # 32 ; WRITe Relative +WRITP EQU $22 ; # 34 ; WRITe with Pattern size lookup +WRIT EQU $24 ; # 36 ; WRITe with sizes provided +WRITA EQU $26 ; # 38 ; WRITe Absolute +VBLANK EQU $28 ; # 40 ; Vector BLANK area +BLANK EQU $2A ; # 42 ; BLANK area +SAVE EQU $2C ; # 44 ; SAVE area +RESTOR EQU $2E ; # 46 ; RESTORe area +SCROLL EQU $30 ; # 48 ; SCROLL area of screen +; +CHRDIS EQU $32 ; # 50 ; CHaRacter DISplay +STRDIS EQU $34 ; # 52 ; STRing DISplay +DISNUM EQU $36 ; # 54 ; DISplay NUMber +; +RELABS EQU $38 ; # 56 ; RELative to ABSolute conversion +RELAB1 EQU $3A ; # 58 ; RELative to non-magic ABSolute +VECTC EQU $3C ; # 60 ; VECTor move single Coordinate +VECT EQU $3E ; # 62 ; VECTor move coordinate pair +; +; HUMAN INTERFACE Routines: +KCTASC EQU $40 ; # 64 ; Key Code in B To ASCii +SENTRY EQU $42 ; # 66 ; SENse TRansition Y +DOIT EQU $44 ; # 68 ; DOIT table, branch to translation handler +DOITB EQU $46 ; # 70 ; DOIT table, use B instead of A +PIZBRK EQU $48 ; # 72 ; take a PIZza BReaK +MENU EQU $4A ; # 74 ; display a MENU +GETPAR EQU $4C ; # 76 ; GET game PARameter from user +GETNUM EQU $4E ; # 78 ; GET NUMber from user +PAWS EQU $50 ; # 80 ; PAUSE +DISTIM EQU $52 ; # 82 ; DISplay TIMe +INCSCR EQU $54 ; # 84 ; INCrement SCoRe +; +; MATH Routines: +INDEXN EQU $56 ; # 86 ; INDEX Nibble by C +STOREN EQU $58 ; # 88 ; STORE Nibble in A by C +INDEXW EQU $5A ; # 90 ; INDEX Word by A +INDEXB EQU $5C ; # 92 ; INDEX Byte by A +MOVE EQU $5E ; # 94 ; MOVE block transfer +SHIFTU EQU $60 ; # 96 ; SHIFT Up digit in A +BCDADD EQU $62 ; # 98 ; BCD ADDition +BCDSUB EQU $64 ;# 100 ; BCD SUBtraction +BCDMUL EQU $66 ;# 102 ; BCD MULtiplication +BCDDIV EQU $68 ;# 104 ; BCD DIVision +BCDCHS EQU $6A ;# 106 ; BCD CHange Sign +BCDNEG EQU $6C ;# 108 ; BCD NEGate to decimal +DADD EQU $6E ;# 110 ; Decimal ADDition +DSMG EQU $70 ;# 112 ; Decimal convert to Sign MaGnitude +DABS EQU $72 ;# 114 ; Decimal ABSolute value +NEGT EQU $74 ;# 116 ; decimal NEGaTe +RANGED EQU $76 ;# 118 ; RANGED random number +QUIT EQU $78 ;# 120 ; QUIT cassette execution +SETB EQU $7A ;# 122 ; SET Byte +SETW EQU $7C ;# 124 ; SET Word +MSKTD EQU $7E ;# 127 ; MaSK joystick in B To Deltas +; +; +; ********** +; * MACROS * +; ********** +; Assembler directives in lower case to distinguish from OPCODEs. +; +; MACROs to define PATTERNs: +DEF2 macro AA,AB + DB AA + DB AB + endm +DEF3 macro BA,BB,BCC + DB BA + DB BB + DB BCC ; 'BC' reserved, so used 'BCC' + endm +DEF4 macro CA,CB,CC,CD + DB CA + DB CB + DB CC + DB CD + endm +DEF5 macro DA,DBB,DC,DD,DEE + DB DA + DB DBB + DB DC + DB DD + DB DEE + endm +DEF6 macro EA,EB,EC,ED,EE,EF + DB EA + DB EB + DB EC + DB ED + DB EE + DB EF + endm +DEF8 macro GA,GB,GC,GD,GEE,GF,GG,GH + DB GA + DB GB + DB GC + DB GD + DB GEE ; 'GE' reserved, so used 'GEE' + DB GF + DB GG + DB GH + endm +; +; MACRO to compute CONSTANT SCREEN Addresses: +XYRELL macro p1,p2,p3 ; RELative LOAD + LD p1,[(p3 SHL 8) + p2] + endm +; +; MACROs to generate SYSTEM CALLs: +SYSTEM macro NUMBA + RST $38 + DB NUMBA + if NUMBA = INTPC +INTPCC DEFL 1 + endif + endm +; MACRO to generate SYSTEM CALL with SUCK option ON: +SYSSUK macro UMBA + RST $38 + DB UMBA + 1 + if UMBA = INTPC +INTPCC DEFL 1 + endif + endm +; +; MACROs to generate MACRO INTERPRETER CALLs: +; INTERPRET without INLINE SUCK: +DONT macro CID + DB CID + endm +; INTERPRET with INLINE SUCK option ON: +DO macro CID + DB CID + 1 + endm +; +; FILL screen with constant data (was 'FILL?'): +FILLq macro START,NBYTES,DATA + DB FILL + 1 + DW START + DW NBYTES + DB DATA + endm +; DISPLAY a STRING: (only inside interpreter?) +TEXTD macro AA,BB,CC,DD + DB STRDIS + 1 + DB BB + DB CC + DB DD + DW AA + endm +; +; EXIT interpreter with context restore: +EXIT macro + DB XINTC +INTPCC DEFL 0 + endm +; +ENDx EQU $C0 ; END of DOIT Table +; +; MACRO CALLs from DOIT Table (only): +MCALL macro AA, BB, EE + DB AA + $80 + DW BB + if EE = ENDx + DB EE + endif + endm +; REAL CALL from DOIT Table: +RCALL macro AA,BB,EE + DB AA + $40 + DW BB + if EE = ENDx + DB EE + endif + endm +; REAL JUMP from DOIT Table: +JMPd macro AA,BB,EE + DB AA + DW BB + if EE = ENDx + DB EE + endif + endm +; +;************** +; MUSIC MACROS: +; $00 to $7F = NOTE DURation, FREQuency(s): +NOTE1 macro DUR,N1 + DB (DUR) AND ($7F) + DB N1 + endm +NOTE2 macro DUR,N1,N2 + DB (DUR) AND ($7F) + DB N1 + DB N2 + endm +NOTE3 macro DUR,N1,N2,N3 + DB (DUR) AND ($7F) + DB N1 + DB N2 + DB N3 + endm +NOTE4 macro DUR,N1,N2,N3,N4 + DB (DUR) AND ($7F) + DB N1 + DB N2 + DB N3 + DB N4 + endm +NOTE5 macro DUR,N1,N2,N3,N4,N5 + DB (DUR) AND ($7F) + DB N1 + DB N2 + DB N3 + DB N4 + DB N5 + endm +; $80 = Set MASTER Osc, Offset: +MASTER macro OFFSET + DB $80 + DB OFFSET + endm +; $80 to $88 = Stuff OUTPUT Port# (0 to 7 only!), Data +; or OUTPUT SNDBX, Data10, D11,..., Data17: +OUTPUT macro PORT,D0,D1,D2,D3,D4,D5,D6,D7 + if PORT != $18 + DB $80 + ((PORT) AND ($7F)) + DB D0 ; <-- D0 is NOT $D0 + else ; on PORT = $18 + DB $88 + DEF8 D7,D6,D5,D4,D3,D2,D1,D0 + endif + endm +; $90 = Set VOICE MASK byte: +; The format of the Voice MASK is: +; * I * A * I * B * I * C * V * N * +; bit 7 6 5 4 3 2 1 0 +; read right-to-left, where I = INC PC and +; A, B, or C = load TONE A,B,C with data at PC +; V = load Vibrato with data at PC and INC PC +; N = load Noise with data at PC and INC PC +VOICEM macro MASK ; 'VOICES' TO 'VOICEM' + DB $90 + DB MASK + endm +; $A0 to $AF = PUSH Number 1 to 16 onto music stack: +PUSHN macro NUMB + DB $A0 + ((NUMB-1) AND $0F) + endm +; $BO = Set VOLUMEs: +VOLUME macro P1,P2 + DB $B0 + DB P1 + DB P2 + endm +; $C0 = Dec Stack top and JNZ: +DSJNZ macro ADD_IT + DB $C0 + DW ADD_IT + endm +; note: Music Processor also uses standard codes as $C3 for +; music JumP, $C9 for music RETurn, and $CD for music CALL. +; +; $D0 = Call RELative self+1 plus 0 to 15: +CREL macro BY + DB $D0 + (BY AND $0F) + endm +; $E0 = Flip LEGatto to STAcato: +LEGSTA macro + DB $E0 + endm +REST macro TIME + DB $E1 + DB TIME + endm +QUIET macro + DB $F0 + endm +; +; ***************** +; * MUSIC EQUATES * +; ***************** +; NOTE Values: +G0 EQU $FD ; 253 +GS0 EQU $EE ; 238 +A0 EQU $E1 ; 225 +AS0 EQU $D4 ; 212 +B0 EQU $C8 ; 200 +C1 EQU $BD ; 189 +CS1 EQU $B2 ; 178 +D1 EQU $A8 ; 168 +DS1 EQU $9F ; 159 +E1 EQU $96 ; 150 +F1 EQU $8D ; 141 +FS1 EQU $85 ; 133 +G1 EQU $7E ; 126 +GS1 EQU $77 ; 119 +A1 EQU $70 ; 112 +AS1 EQU $6A ; 106 +B1 EQU $64 ; 100 +C2 EQU $5E ; 94 +CS2 EQU $59 ; 89 +D2 EQU $54 ; 84 +DS2 EQU $4F ; 79 +E2 EQU $4A ; 74 +F2 EQU $46 ; 70 +FS2 EQU $42 ; 66 +G2 EQU $3E ; 62 +GS2 EQU $3B ; 59 +A2 EQU $37 ; 55 +AS2 EQU $34 ; 52 +B2 EQU $31 ; 49 +C3 EQU $2E ; 46 +CS3 EQU $2C ; 44 +D3 EQU $29 ; 41 +DS3 EQU $27 ; 39 +E3 EQU $25 ; 37 +F3 EQU $22 ; 34 +FS3 EQU $20 ; 32 +G3 EQU $1F ; 31 +GS3 EQU $1D ; 29 +A3 EQU $1B ; 27 +AS3 EQU $1A ; 26 +B3 EQU $18 ; 24 +C4 EQU $17 ; 23 +CS4 EQU $15 ; 21 +D4 EQU $14 ; 20 +DS4 EQU $13 ; 19 +E4 EQU $12 ; 18 +F4 EQU $11 ; 17 +FS4 EQU $10 ; 16 +G4 EQU $0F ; 15 +GS4 EQU $0E ; 14 +A4 EQU $0D ; 13 +C5 EQU $0B ; 11 +CS5 EQU $0A ; 10 +DS5 EQU $09 ; 9 +F5 EQU $08 ; 8 +G5 EQU $07 ; 7 +A5 EQU $06 ; 6 +C6 EQU $05 ; 5 +DS6 EQU $04 ; 4 +G6 EQU $03 ; 3 +C7 EQU $02 ; 2 +G7 EQU $01 ; 1 +G8 EQU $00 ; 0 +; +; MASTER OSCILATOR Offsets: +OB0 EQU $FE ; 254 +OC0 EQU $F1 ; 241 +OD1 EQU $D6 ; 214 +OE1 EQU $BF ; 191 +OF1 EQU $B4 ; 180 +OG1 EQU $A0 ; 160 +OA1 EQU $8F ; 143 +OA2 EQU $47 ; 71 +OA3 EQU $23 ; 35 +OA4 EQU $11 ; 17 +OA5 EQU $08 ; 8 +; +; +; *************************** +; * SYSTEM RAM MEMORY Cells * +; *************************** +WASTE EQU $0FFF +WASTER EQU WASTE +; +SYSRAM EQU $4FCE ; Resides at the highest possible address +BEGRAM EQU SYSRAM ; typically used for initial Stack Pointer +; Used by MUSIC PROCESSOR: +MUZPC EQU $4FCE ; MUSic Program Counter +MUZSP EQU $4FD0 ; MUSic Stack Pointer +PVOLAB EQU $4FD2 ; Preset VOLume for tones A and B +PVOLMC EQU $4FD3 ; Preset VOLuMe for tone C and Noise Mode +VOICES EQU $4FD4 ; music VOICES mask +; COUNTER TIMERS (used by DECCTS,ACTINT,CTIMER): +CT0 EQU $4FD5 ; Counter Timer 0 +CT1 EQU $4FD6 ; Counter Timer 1 +CT2 EQU $4FD7 ; Counter Timer 2 +CT3 EQU $4FD8 ; Counter Timer 3 +CT4 EQU $4FD9 ; Counter Timer 4 +CT5 EQU $4FDA ; Counter Timer 5 +CT6 EQU $4FDB ; Counter Timer 6 +CT7 EQU $4FDC ; Counter Timer 7 +;Used by SENTRY to track controls: +CNT EQU $4FDD ; Counter update & Number Tracking +SEMI4S EQU $4FDE ; SEMAPHORE flag bitS +OPOT0 EQU $4FDF ; Old POT 0 tracking byte +OPOT1 EQU $4FE0 ; Old POT 1 tracking byte +OPOT2 EQU $4FE1 ; Old POT 2 tracking byte +OPOT3 EQU $4FE2 ; Old POT 3 tracking byte +KEYSEX EQU $4FE3 ; KEYS-EX tracking byte +OSW0 EQU $4FE4 ; Old SWitch 0 tracking byte +OSW1 EQU $4FE5 ; Old SWitch 1 tracking byte +OSW2 EQU $4FE6 ; Old SWitch 2 tracking byte +OSW3 EQU $4FE7 ; Old SWitch 3 tracking byte +COLLST EQU $4FE8 ; COLset LaST address for P.B. A +; Used by STIMER: +DURAT EQU $4FEA ; note DURATion +TMR60 EQU $4FEB ; TiMeR for SIXTY'ths of sec +TIMOUT EQU $4FEC ; TIMer for blackOUT +GTSECS EQU $4FED ; Game Time SECondS +GTMINS EQU $4FEE ; Game Time MINuteS +; Used by MENU: +RANSHT EQU $4FEF ; RANdom number SHifT register +NUMPLY EQU $4FF3 ; NUMber of PLaYers +ENDSCR EQU $4FF4 ; END SCoRe to 'play to' +MRLOCK EQU $4FF7 ; Magic Register LOCK out flag +GAMSTB EQU $4FF8 ; GAMe STatus Byte +PRIOR EQU $4FF9 ; PRIOR music protect flag +SENFLG EQU $4FFA ; SENtry control seizure FLaG +; User UPI Routines, even numbers from $80 to $FE ( + 1 for SUCK): +UMARGT EQU $4FFB ; User Mask ARGument Table + (routine / 2) +USERTB EQU $4FFD ; USER Table Base + routine = JumP address +; +URINAL EQU $4FFF ; WASTER flushes here! +; +; diff --git a/src/audio.ts b/src/audio.ts index 16faf7b1..6ca18bc7 100644 --- a/src/audio.ts +++ b/src/audio.ts @@ -3,36 +3,41 @@ // from TSS declare var MasterChannel, AudioLooper, PsgDeviceChannel; -export var MasterAudio = function() { - this.master = new MasterChannel(); - this.looper = new AudioLooper(512); - this.start = function() { +export class MasterAudio { + master = new MasterChannel(); + looper = new AudioLooper(512); + start() { this.looper.setChannel(this.master); this.looper.activate(); } - this.stop = function() { + stop() { this.looper.setChannel(null); } } -export var AY38910_Audio = function(master) { - this.psg = new PsgDeviceChannel(); - this.psg.setMode(PsgDeviceChannel.MODE_SIGNED); - this.psg.setDevice(PsgDeviceChannel.DEVICE_AY_3_8910); - master.master.addChannel(this.psg); - var curreg = 0; +export class AY38910_Audio { + master : MasterAudio; + psg = new PsgDeviceChannel(); + curreg = 0; + + constructor(master : MasterAudio) { + this.master = master; + this.psg.setMode(PsgDeviceChannel.MODE_SIGNED); + this.psg.setDevice(PsgDeviceChannel.DEVICE_AY_3_8910); + master.master.addChannel(this.psg); + } - this.reset = function() { + reset() { for (var i=15; i>=0; i--) { this.selectRegister(i); this.setData(0); } } - this.selectRegister = function(val) { - curreg = val & 0xf; + selectRegister(val : number) { + this.curreg = val & 0xf; } - this.setData = function(val) { - this.psg.writeRegisterAY(curreg, val & 0xff); + setData(val : number) { + this.psg.writeRegisterAY(this.curreg, val & 0xff); } } diff --git a/src/baseplatform.ts b/src/baseplatform.ts index 61231542..0a85d6ef 100644 --- a/src/baseplatform.ts +++ b/src/baseplatform.ts @@ -168,6 +168,7 @@ export abstract class BaseDebugPlatform extends BasePlatform { } } +// TODO: what's the diff? why z80 not use? unify these things export abstract class BaseFrameBasedPlatform extends BaseDebugPlatform { debugPCDelta = -1; @@ -245,6 +246,12 @@ export abstract class BaseFrameBasedPlatform extends BaseDebugPlatform { return false; }); } + /* + runToVsync() { + this.nextFrame(false); + this.runEval(() => { return true; }); + } + */ } ////// 6502 diff --git a/src/cpu/z80fast.js b/src/cpu/z80fast.js index 889210f2..f3227d79 100644 --- a/src/cpu/z80fast.js +++ b/src/cpu/z80fast.js @@ -106,7 +106,7 @@ memory.write(regPairs[11], regPairs[12] & 0xff);; l = (tstates += ( 3), memory.read(inttemp)); inttemp = (inttemp+1) & 0xffff; h = (tstates += ( 3), memory.read(inttemp)); - console.log(hex(interruptDataBus), hex(inttemp), hex(l), hex(h)); + //console.log(hex(interruptDataBus), hex(inttemp), hex(l), hex(h)); regPairs[12] = (h<<8) | l; tstates += 7; break; diff --git a/src/platform/astrocade.ts b/src/platform/astrocade.ts new file mode 100644 index 00000000..e4de58c7 --- /dev/null +++ b/src/platform/astrocade.ts @@ -0,0 +1,369 @@ +"use strict"; + +import { Platform, BaseZ80Platform } from "../baseplatform"; +import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap } from "../emu"; +import { hex, lzgmini, stringToByteArray } from "../util"; +import { MasterAudio, AY38910_Audio } from "../audio"; + +const ASTROCADE_PRESETS = [ + {id:'01-helloworlds.asm', name:'Hello World'}, + {id:'02-telephone.asm', name:'Telephone'}, + {id:'03-horcbpal.asm', name:'Paddle Demo'}, +]; + +// TODO: fix keys, more controllers, paddles, vibrato/noise, border color + +const ASTROCADE_KEYCODE_MAP = makeKeycodeMap([ + // player 1 + [Keys.VK_UP, 0x10, 0x1], + [Keys.VK_DOWN, 0x10, 0x2], + [Keys.VK_LEFT, 0x10, 0x4], + [Keys.VK_RIGHT, 0x10, 0x8], + [Keys.VK_SPACE, 0x10, 0x10], + // keypad $14 + [Keys.VK_P, 0x14, 0x1], + [Keys.VK_SLASH, 0x14, 0x2], + [Keys.VK_X, 0x14, 0x4], + [Keys.VK_MINUS, 0x14, 0x8], + [Keys.VK_COMMA, 0x14, 0x10], + [Keys.VK_EQUALS,0x14, 0x20], + // keypad $15 + [Keys.VK_Z, 0x15, 0x1], + [Keys.VK_H, 0x15, 0x2], + [Keys.VK_9, 0x15, 0x4], + [Keys.VK_6, 0x15, 0x8], + [Keys.VK_3, 0x15, 0x10], + [Keys.VK_PERIOD,0x15, 0x20], + // keypad $16 + [Keys.VK_A, 0x16, 0x1], + [Keys.VK_S, 0x16, 0x2], + [Keys.VK_8, 0x16, 0x4], + [Keys.VK_5, 0x16, 0x8], + [Keys.VK_2, 0x16, 0x10], + [Keys.VK_0, 0x16, 0x20], + // keypad $17 + [Keys.VK_C, 0x17, 0x1], + [Keys.VK_R, 0x17, 0x2], + [Keys.VK_7, 0x17, 0x4], + [Keys.VK_4, 0x17, 0x8], + [Keys.VK_1, 0x17, 0x10], + [Keys.VK_E, 0x17, 0x20], +]); + +const _BallyAstrocadePlatform = function(mainElement) { + + var cpu, ram, membus, iobus, rom, bios; + var probe; + var video, timer, pixels; + var audio, psg; + var inputs = new Uint8Array(0x20); + //var watchdog_counter; + const swidth = 160; + const sheight = 102; + const cpuFrequency = 1789000; + const cpuCyclesPerLine = cpuFrequency/(60*sheight); + const INITIAL_WATCHDOG = 256; + const PIXEL_ON = 0xffeeeeee; + const PIXEL_OFF = 0xff000000; + + var magicop = 0; + var xpand = 0; + var xplower = false; + var shift2 = 0; + var horcb = 0; + var inmod = 0; + var inlin = 0; + var infbk = 0; + var verbl = sheight; + var palette = new Uint32Array(8); + // default palette + for (var i=0; i<8; i++) + palette[i] = ASTROCADE_PALETTE[i]; + + function ramwrite(a:number, v:number) { + ram.mem[a] = v; + var ofs = a*4+3; // 4 pixels per byte + for (var i=0; i<4; i++) { + var lr = ((a % 0x28) >= (horcb & 0x3f)) ? 0 : 4; + pixels[ofs--] = palette[lr + (v & 3)]; + v >>= 2; + } + } + + function magicwrite(a:number, v:number) { + // expand + if (magicop & 0x8) { + var v2 = 0; + if (!xplower) + v >>= 4; + for (var i=0; i<4; i++) { + var pix = (v&1) ? ((xpand>>2)&3) : (xpand&3); + v2 |= pix << (i*2); + v >>= 1; + } + v = v2; + xplower = !xplower; + } + // shift + var sh = (magicop & 3) << 1; + var v2 = (v >> sh) | shift2; + shift2 = (v << (8-sh)) & 0xff; + v = v2; + // flop + if (magicop & 0x40) { + var v2 = 0; + for (var i=0; i<4; i++) { + v2 |= (v & 3) << (6-i*2); + v >>= 2; + } + v = v2; + } + // or/xor + if (magicop & 0x30) { + var oldv = ram.mem[a]; + if (magicop & 0x10) + v |= oldv; + if (magicop & 0x20) + v ^= oldv; // TODO: what if both? + // collision detect + var icpt = 0; + for (var i=0; i<8; i+=2) { + icpt <<= 1; + // pixel changed from off to on? + if ( !((oldv>>i)&3) && ((v>>i)&3) ) + icpt |= 1; + } + // upper 4 bits persist, lower are just since last write + inputs[8] = (inputs[8] & 0xf0) | icpt | (icpt<<4); + } + // commit write to ram/screen + ramwrite(a, v); + } + + function setpalette(a:number, v:number) { + palette[a&7] = ASTROCADE_PALETTE[v&0xff]; + } + + function setbordercolor() { + var col = horcb >> 6; + // TODO + } + + class BallyAstrocadePlatform extends BaseZ80Platform implements Platform { + + getPresets() { + return ASTROCADE_PRESETS; + } + + start = function() { + ram = new RAM(0x2000); + bios = new lzgmini().decode(stringToByteArray(atob(window['ASTROCADE_LZGROM']))); + //displayPCs = new Uint16Array(new ArrayBuffer(0x2000*2)); + membus = { + read: newAddressDecoder([ + [0x0000, 0x1fff, 0x1fff, function(a) { return bios ? bios[a] : 0; }], + [0x2000, 0x3fff, 0x1fff, function(a) { return rom ? rom[a] : 0; }], + [0x4000, 0x4fff, 0xfff, function(a) { return ram.mem[a]; }], + ]), + write: newAddressDecoder([ + [0x4000, 0x4fff, 0xfff, ramwrite], + [0x0000, 0x3fff, 0x3fff, magicwrite], + ]), + isContended: function() { return false; }, + }; + iobus = { + read: function(addr) { + addr &= 0x1f; + var rtn = inputs[addr]; + if (addr == 8) + inputs[addr] = 0; + return rtn; + }, + write: function(addr, val) { + addr &= 0x1f; + val &= 0xff; + switch (addr) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + setpalette(addr,val); + break; + case 9: // HORCB (horizontal boundary byte) + horcb = val; + setbordercolor(); + break; + case 0xa: // VERBL (vertical blank) + verbl = val >> 1; + break; + case 0xb: // OTIR (set palette) + setpalette(cpu.getBC()>>8, membus.read(cpu.getHL())); + break; + case 0xc: // magic register + magicop = val; + shift2 = 0; + break; + case 0xd: // INFBK (interrupt feedback) + infbk = val; + break; + case 0xe: // INMOD (interrupt enable) + inmod = val; + break; + case 0xf: // INLIN (interrupt line) + inlin = val >> 1; + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + psg.setACRegister(addr, val); + break; + case 0x18: + psg.setACRegister(cpu.getBC()>>8, membus.read(cpu.getHL())); + break; + case 0x19: // XPAND + xpand = val; + xplower = false; + break; + default: + console.log('IO write', hex(addr,4), hex(val,2)); + break; + } + } + }; + cpu = this.newCPU(membus, iobus); + audio = new MasterAudio(); + psg = new AstrocadeAudio(audio); + video = new RasterVideo(mainElement,swidth,sheight,{}); + video.create(); + var idata = video.getFrameData(); + setKeyboardFromMap(video, inputs, ASTROCADE_KEYCODE_MAP); + pixels = video.getFrameData(); + timer = new AnimationTimer(60, this.nextFrame.bind(this)); + } + + readAddress(addr) { + return membus.read(addr); + } + + advance(novideo : boolean) { + for (var sl=0; sl>8)&0xff); // freq hi + console.log(i,j); + break; + case 5: + this.psg.writeRegisterAY(10, val & 0xf); // tone c vol + break; + case 6: + this.psg.writeRegisterAY(8, val & 0xf); // tone a vol + this.psg.writeRegisterAY(9, (val>>4) & 0xf); // tone b vol + break; + } + } +} + +///// + +PLATFORMS['astrocade'] = _BallyAstrocadePlatform; + +//http://glankonian.com/~lance/astrocade_palette.html +var ASTROCADE_PALETTE = [0x000000,0x242424,0x484848,0x6D6D6D,0x919191,0xB6B6B6,0xDADADA,0xFFFFFF,0x2500BB,0x4900E0,0x6E11FF,0x9235FF,0xB75AFF,0xDB7EFF,0xFFA3FF,0xFFC7FF,0x4900B0,0x6D00D5,0x9201F9,0xB625FF,0xDA4AFF,0xFF6EFF,0xFF92FF,0xFFB7FF,0x6A009F,0x8E00C3,0xB300E7,0xD718FF,0xFB3CFF,0xFF61FF,0xFF85FF,0xFFA9FF,0x870087,0xAB00AB,0xD000D0,0xF40EF4,0xFF32FF,0xFF56FF,0xFF7BFF,0xFF9FFF,0x9F006A,0xC3008E,0xE700B3,0xFF07D7,0xFF2CFB,0xFF50FF,0xFF74FF,0xFF99FF,0xB00049,0xD5006D,0xF90092,0xFF05B6,0xFF29DA,0xFF4DFF,0xFF72FF,0xFF96FF,0xBB0025,0xE00049,0xFF006E,0xFF0692,0xFF2AB7,0xFF4FDB,0xFF73FF,0xFF98FF,0xBF0000,0xE30024,0xFF0048,0xFF0B6D,0xFF3091,0xFF54B6,0xFF79DA,0xFF9DFF,0xBB0000,0xE00000,0xFF0023,0xFF1447,0xFF396C,0xFF5D90,0xFF82B5,0xFFA6D9,0xB00000,0xD50000,0xF90000,0xFF2124,0xFF4548,0xFF6A6C,0xFF8E91,0xFFB3B5,0x9F0000,0xC30000,0xE70C00,0xFF3003,0xFF5527,0xFF794B,0xFF9E70,0xFFC294,0x870000,0xAB0000,0xD01E00,0xF44200,0xFF670A,0xFF8B2E,0xFFAF53,0xFFD477,0x6A0000,0x8E0D00,0xB33100,0xD75600,0xFB7A00,0xFF9E17,0xFFC33B,0xFFE75F,0x490000,0x6D2100,0x924500,0xB66A00,0xDA8E00,0xFFB305,0xFFD729,0xFFFC4E,0x251100,0x493500,0x6E5A00,0x927E00,0xB7A300,0xDBC700,0xFFEB1E,0xFFFF43,0x002500,0x244900,0x486D00,0x6D9200,0x91B600,0xB6DB00,0xDAFF1B,0xFFFF3F,0x003700,0x005B00,0x238000,0x47A400,0x6CC900,0x90ED00,0xB5FF1E,0xD9FF43,0x004700,0x006C00,0x009000,0x24B400,0x48D900,0x6CFD05,0x91FF29,0xB5FF4E,0x005500,0x007900,0x009D00,0x03C200,0x27E600,0x4BFF17,0x70FF3B,0x94FF5F,0x005F00,0x008300,0x00A800,0x00CC00,0x0AF00A,0x2EFF2E,0x53FF53,0x77FF77,0x006500,0x008A00,0x00AE00,0x00D203,0x00F727,0x17FF4B,0x3BFF70,0x5FFF94,0x006800,0x008C00,0x00B100,0x00D524,0x00F948,0x05FF6C,0x29FF91,0x4EFFB5,0x006600,0x008B00,0x00AF23,0x00D447,0x00F86C,0x00FF90,0x1EFFB5,0x43FFD9,0x006100,0x008524,0x00AA48,0x00CE6D,0x00F391,0x00FFB6,0x1BFFDA,0x3FFFFE,0x005825,0x007C49,0x00A16E,0x00C592,0x00EAB7,0x00FFDB,0x1EFFFF,0x43FFFF,0x004B49,0x00706D,0x009492,0x00B9B6,0x00DDDA,0x05FFFF,0x29FFFF,0x4EFFFF,0x003C6A,0x00608E,0x0085B3,0x00A9D7,0x00CEFB,0x17F2FF,0x3BFFFF,0x5FFFFF,0x002A87,0x004FAB,0x0073D0,0x0097F4,0x0ABCFF,0x2EE0FF,0x53FFFF,0x77FFFF,0x00179F,0x003BC3,0x0060E7,0x0384FF,0x27A8FF,0x4BCDFF,0x70F1FF,0x94FFFF,0x0002B0,0x0027D5,0x004BF9,0x2470FF,0x4894FF,0x6CB9FF,0x91DDFF,0xB5FFFF,0x0000BB,0x0013E0,0x2337FF,0x475BFF,0x6C80FF,0x90A4FF,0xB5C9FF,0xD9EDFF]; +// swap palette RGB to BGR +for (var i=0; i<256; i++) { + var x = ASTROCADE_PALETTE[i]; + x = ((x&0xff)<<16) | ((x>>16)&0xff) | (x&0x00ff00); + ASTROCADE_PALETTE[i] = x | 0xff000000; +} diff --git a/src/platform/vector.ts b/src/platform/vector.ts index 26b5a932..4664d4dc 100644 --- a/src/platform/vector.ts +++ b/src/platform/vector.ts @@ -45,8 +45,8 @@ function newPOKEYAudio() { var pokey1 = new POKEYDeviceChannel(); var pokey2 = new POKEYDeviceChannel(); var audio = new MasterAudio(); - audio.pokey1 = pokey1; - audio.pokey2 = pokey2; + audio['pokey1'] = pokey1; // TODO: cheezy + audio['pokey2'] = pokey2; audio.master.addChannel(pokey1); audio.master.addChannel(pokey2); return audio; diff --git a/src/project.ts b/src/project.ts index 68cb45e4..08e6a8c1 100644 --- a/src/project.ts +++ b/src/project.ts @@ -56,7 +56,7 @@ export class CodeProject { parseIncludeDependencies(text:string):string[] { var files = []; if (this.platform_id == 'verilog') { - var re = /^\s*(`include|[.]include)\s+"(.+?)"/gm; + var re = /^\s*(`include|[.]include)\s+"(.+?)"/gmi; var m; while (m = re.exec(text)) { files.push('local/'+m[2]); @@ -65,7 +65,7 @@ export class CodeProject { } else { // for .asm -- [.]include "file" // for .c -- #include "file" - var re2 = /^\s+([.#]?include)\s+"(.+?)"/gm; + var re2 = /^\s+([.#]?include)\s+"(.+?)"/gmi; while (m = re2.exec(text)) { files.push('local/'+m[2]); files.push(m[2]);