diff --git a/presets/msx-libcv b/presets/msx-libcv new file mode 120000 index 00000000..2fb6abf1 --- /dev/null +++ b/presets/msx-libcv @@ -0,0 +1 @@ +coleco \ No newline at end of file diff --git a/presets/msx/helloworld.asm b/presets/msx/helloworld.asm index bf641e8f..21d727ae 100644 --- a/presets/msx/helloworld.asm +++ b/presets/msx/helloworld.asm @@ -1,13 +1,10 @@ - + ; Hello World example ; ROM routine for character output CHPUT: equ $00A2 -; waste space @ 0x0000 - 0x3fff - org 0x0000 - db 0 - ds 0x3fff + org 0x4000 ; MSX cartridge header @ 0x4000 - 0x400f dw 0x4241 diff --git a/presets/msx/helloworld.s b/presets/msx/helloworld.s new file mode 100644 index 00000000..808c8f04 --- /dev/null +++ b/presets/msx/helloworld.s @@ -0,0 +1,34 @@ + +; Hello World example + +; ROM routine for character output +CHGET = #0x009F +CHPUT = #0x00A2 + +; Bank 1 +.area _CODE +; MSX cartridge header @ 0x4000 - 0x400f + .dw 0x4241 + .dw Init + .dw Init + .dw 0 + .dw 0 + .dw 0 + .dw 0 + .dw 0 + +; initialize and print message +Init: + ld hl,#msg + call puts + jp Init ; loop forever +puts: ; print 0-terminated string in HL + ld a,(hl) + or a + ret z + call CHPUT ; displays one character in A + inc hl + jr puts + +; ASCII message + CR LF +msg: .ascii "Hello, world!\n\r\0" diff --git a/src/audio.ts b/src/audio.ts index b61c72e3..655252a6 100644 --- a/src/audio.ts +++ b/src/audio.ts @@ -39,6 +39,10 @@ export class AY38910_Audio { setData(val : number) { this.psg.writeRegisterAY(this.curreg, val & 0xff); } + readData() { + return this.psg.readRegister(this.curreg); + } + currentRegister() { return this.curreg; } } export class SN76489_Audio { diff --git a/src/baseplatform.ts b/src/baseplatform.ts index 70b1b21b..e96e8029 100644 --- a/src/baseplatform.ts +++ b/src/baseplatform.ts @@ -1086,7 +1086,7 @@ export abstract class BasicZ80ScanlinePlatform extends BaseZ80Platform { audio; psg; pixels : Uint32Array; - inputs = new Uint8Array(16); + inputs : Uint8Array = new Uint8Array(32); mainElement : HTMLElement; poller : ControllerPoller; diff --git a/src/emu.ts b/src/emu.ts index ae228225..3b7a45da 100644 --- a/src/emu.ts +++ b/src/emu.ts @@ -335,7 +335,8 @@ interface KeyMapEntry { type KeyCodeMap = Map; -export const Keys : {[keycode:string]:KeyDef} = { +export const Keys = { + ANYKEY: {c: 0, n: "?"}, // gamepad and keyboard (player 0) UP: {c: 38, n: "Up", plyr:0, yaxis:-1}, DOWN: {c: 40, n: "Down", plyr:0, yaxis:1}, @@ -471,7 +472,12 @@ type KeyMapFunction = (o:KeyMapEntry, key:number, code:number, flags:number) => export function setKeyboardFromMap(video:RasterVideo, switches:number[]|Uint8Array, map:KeyCodeMap, func?:KeyMapFunction) { var handler = (key,code,flags) => { + if (!map) { + func(null, key, code, flags); + return; + } var o : KeyMapEntry = map[key]; + if (!o) o = map[0]; if (o && func) { func(o, key, code, flags); } diff --git a/src/platform/msx.ts b/src/platform/msx.ts index 3468edc9..08da37b5 100644 --- a/src/platform/msx.ts +++ b/src/platform/msx.ts @@ -1,9 +1,9 @@ "use strict"; import { Platform, BasicZ80ScanlinePlatform } from "../baseplatform"; -import { PLATFORMS, newAddressDecoder, padBytes, noise, makeKeycodeMap, Keys } from "../emu"; +import { PLATFORMS, newAddressDecoder, padBytes, noise, makeKeycodeMap, KeyFlags, Keys, EmuHalt } from "../emu"; import { hex, lzgmini, stringToByteArray } from "../util"; -import { MasterAudio, SN76489_Audio } from "../audio"; +import { MasterAudio, AY38910_Audio } from "../audio"; import { TMS9918A } from "../video/tms9918a"; // https://www.konamiman.com/msx/msx-e.html#msx2th @@ -12,28 +12,48 @@ import { TMS9918A } from "../video/tms9918a"; // https://openmsx.org/manual/setup.html // https://www.msx.org/wiki/Slots // https://www.msx.org/wiki/SDCC -// http://cbios.sourceforge.net/ var MSX_PRESETS = [ {id:'helloworld.asm', name:'Hello World (ASM)'}, ]; var MSX_KEYCODE_MAP = makeKeycodeMap([ - [Keys.UP, 0, 0x1], - [Keys.DOWN, 0, 0x4], - [Keys.LEFT, 0, 0x8], - [Keys.RIGHT, 0, 0x2], - [Keys.A, 0, 0x40], - [Keys.B, 1, 0x40], + [Keys.UP, 0, 0x1], + [Keys.DOWN, 0, 0x2], + [Keys.LEFT, 0, 0x4], + [Keys.RIGHT, 0, 0x8], + [Keys.A, 0, 0x10], + [Keys.B, 0, 0x20], - [Keys.P2_UP, 2, 0x1], - [Keys.P2_DOWN, 2, 0x4], - [Keys.P2_LEFT, 2, 0x8], - [Keys.P2_RIGHT, 2, 0x2], - [Keys.P2_A, 2, 0x40], - [Keys.P2_B, 3, 0x40], + [Keys.P2_UP, 1, 0x1], + [Keys.P2_DOWN, 1, 0x2], + [Keys.P2_LEFT, 1, 0x4], + [Keys.P2_RIGHT, 1, 0x8], + [Keys.P2_A, 1, 0x10], + [Keys.P2_B, 1, 0x20], + + [Keys.ANYKEY, 2, 0x0], ]); +const JOY_INPUT_0 = 0; +const JOY_INPUT_1 = 1; +const KEYBOARD_ROW_0 = 16; + +const MSX_KEYMATRIX_INTL_NOSHIFT = [ + Keys.VK_7, Keys.VK_6, Keys.VK_5, Keys.VK_4, Keys.VK_3, Keys.VK_2, Keys.VK_1, Keys.VK_0, + Keys.VK_SEMICOLON, Keys.VK_CLOSE_BRACKET, Keys.VK_OPEN_BRACKET, Keys.VK_BACK_SLASH, Keys.VK_EQUALS, Keys.VK_MINUS, Keys.VK_9, Keys.VK_8, + Keys.VK_B, Keys.VK_A, null/*DEAD*/, Keys.VK_SLASH, Keys.VK_PERIOD, Keys.VK_COMMA, Keys.VK_ACUTE, Keys.VK_QUOTE, + Keys.VK_J, Keys.VK_I, Keys.VK_H, Keys.VK_G, Keys.VK_F, Keys.VK_E, Keys.VK_D, Keys.VK_C, + Keys.VK_R, Keys.VK_Q, Keys.VK_P, Keys.VK_O, Keys.VK_N, Keys.VK_M, Keys.VK_L, Keys.VK_K, + Keys.VK_Z, Keys.VK_Y, Keys.VK_X, Keys.VK_W, Keys.VK_V, Keys.VK_U, Keys.VK_T, Keys.VK_S, + Keys.VK_F3, Keys.VK_F2, Keys.VK_F1, null, Keys.VK_CAPS_LOCK, null, Keys.VK_CONTROL, Keys.VK_SHIFT, + Keys.VK_ENTER, null, Keys.VK_BACK_SPACE, null, Keys.VK_TAB, Keys.VK_ESCAPE, Keys.VK_F5, Keys.VK_F4, + Keys.VK_RIGHT, Keys.VK_DOWN, Keys.VK_UP, Keys.VK_LEFT, Keys.VK_DELETE, Keys.VK_INSERT, Keys.VK_HOME, Keys.VK_SPACE, + null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, + // TODO: null keycodes +]; + /// standard emulator interface MSXSlot { @@ -47,16 +67,38 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform { canvasWidth = 304; numTotalScanlines = 262; numVisibleScanlines = 240; - defaultROMSize = 0x10000; + defaultROMSize = 0x8000; vdp : TMS9918A; bios : Uint8Array; slots : MSXSlot[]; slotmask : number = 0; + ppi_c : number = 0; getPresets() { return MSX_PRESETS; } getKeyboardMap() { return MSX_KEYCODE_MAP; } + + // http://map.grauw.nl/articles/keymatrix.php + getKeyboardFunction() { + return (o,key,code,flags) => { + //console.log(o,key,code,flags); + var keymap = MSX_KEYMATRIX_INTL_NOSHIFT; + for (var i=0; i> 3; + let bit = 7 - (i & 7); + //console.log(key, row, bit); + if (flags & KeyFlags.KeyDown) { + this.inputs[KEYBOARD_ROW_0+row] |= (1<> 1) & 7; + this.ppi_c = (this.ppi_c & ~(1< { return this.rom[a] | 0; }, + read: (a) => { return this.rom[a - 0x4000] | 0; }, + write: (a,v) => { } + }, + // slot 2: cartridge + { + read: (a) => { return this.rom[a - 0x4000] | 0; }, write: (a,v) => { } }, - // slot 2 : empty - null, // slot 3 : RAM { read: (a) => { return this.ram[a] | 0; }, @@ -130,11 +199,11 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform { }, ]; this.audio = new MasterAudio(); - this.psg = new SN76489_Audio(this.audio); + this.psg = new AY38910_Audio(this.audio); var cru = { setVDPInterrupt: (b) => { if (b) { - this.cpu.nonMaskableInterrupt(); + this.cpu.requestInterrupt(0x38); } else { // TODO: reset interrupt? } @@ -158,11 +227,15 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform { super.loadState(state); this.vdp.restoreState(state['vdp']); this.slotmask = state['slotmask']; + this.ppi_c = state['ppi_c']; + this.psg.selectRegister(state['psgRegister']); } saveState() { var state = super.saveState(); state['vdp'] = this.vdp.getState(); state['slotmask'] = this.slotmask; + state['ppi_c'] = this.ppi_c; + state['psgRegister'] = this.psg.currentRegister(); return state; } reset() { @@ -170,6 +243,15 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform { this.vdp.reset(); this.psg.reset(); this.slotmask = 0; + this.ppi_c = 0; + } + resume() { + super.resume(); + this.resetInputs(); + } + resetInputs() { + // clear keyboard matrix + this.inputs.fill(0); } getDebugCategories() { @@ -192,9 +274,18 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform { /// PLATFORMS['msx'] = MSXPlatform; +PLATFORMS['msx-libcv'] = MSXPlatform; /// +/* + C-BIOS is a BIOS compatible with the MSX BIOS + C-BIOS was written from scratch by BouKiCHi + C-BIOS is available for free, including its source code (2-clause BSD license) + C-BIOS can be shipped with MSX emulators so they are usable out-of-the-box without copyright issues + + http://cbios.sourceforge.net/ +*/ var MSX1_BIOS_LZG = ` TFpHAADAAAAAI8Sp+W4NAVo7UZPzwxINvxuYmMPtEADDvyMAw/+T4QAkAMMbEQDDNJPhIZPhc5Ph JxEhAgAAAMM5EZOhk+HmGMNOEcNYEcMWAsMiAsMuAsNFAsNNAsNVAsNgAsNtAsOBAsOXAsOtAsPU diff --git a/src/worker/lib/msx-libcv/crt0-msx.lst b/src/worker/lib/msx-libcv/crt0-msx.lst new file mode 100644 index 00000000..4da0a681 --- /dev/null +++ b/src/worker/lib/msx-libcv/crt0-msx.lst @@ -0,0 +1,91 @@ + 1 ; crt0.s for Colecovision cart + 2 + 3 .module crt0 + 4 .globl _main + 5 .globl _cv_init + 6 .globl _cv_spint_handler + 7 .globl _cv_vint + 8 .globl _cv_start + 9 .globl ___sdcc_call_hl + 10 + 11 ; Ordering of segments for the linker - copied from sdcc crt0.s + 12 .area _CODE + 13 .area _INITIALIZER + 14 .area _HOME + 15 .area _GSINIT + 16 .area _GSFINAL + 17 .area _DATA + 18 .area _INITIALIZED + 19 .area _BSEG + 20 .area _BSS + 21 .area _HEAP + 22 + 23 .area _CODE + 24 ; MSX cartridge header @ 0x4000 - 0x400f + 0000 41 42 25 .dw 0x4241 + 0002r10r00 26 .dw _cv_start + 0004r10r00 27 .dw _cv_start + 0006 00 00 28 .dw 0 + 0008 00 00 29 .dw 0 + 000A 00 00 30 .dw 0 + 000C 00 00 31 .dw 0 + 000E 00 00 32 .dw 0 + 33 + 0010 34 _cv_start: + 0010 F3 [ 4] 35 di + 0011 31 00 E0 [10] 36 ld sp, #0xe000 ; Set stack pointer directly above top of memory. + 0014 ED 56 [ 8] 37 im 1 + 38 + 0016 CDr00r00 [17] 39 call gsinit ; Initialize global and static variables. + 0019 CDr00r00 [17] 40 call vinthook + 001C CDr00r00 [17] 41 call _cv_init ; Initialize Colecovision specific stuff. + 001F CDr00r00 [17] 42 call _main + 0022 C7 [11] 43 rst 0x0 ; Restart when main() returns. + 44 + 45 .area _GSINIT + 0000 46 gsinit:: + 47 + 48 ; Implicitly zeroed global and static variables. + 0000 01r00r00 [10] 49 ld bc, #l__DATA + 0003 78 [ 4] 50 ld a, b + 0004 B1 [ 4] 51 or a, c + 0005 28 0F [12] 52 jr Z, zeroed_data + 0007 21r00r00 [10] 53 ld hl, #s__DATA + 000A 36 00 [10] 54 ld (hl), #0x00 + 000C 0B [ 6] 55 dec bc + 000D 78 [ 4] 56 ld a, b + 000E B1 [ 4] 57 or a, c + 000F 28 05 [12] 58 jr Z, zeroed_data + 0011 5D [ 4] 59 ld e, l + 0012 54 [ 4] 60 ld d, h + 0013 13 [ 6] 61 inc de + 0014 ED B0 [21] 62 ldir + 0016 63 zeroed_data: + 64 + 65 ; Explicitly initialized global variables. + 0016 01r00r00 [10] 66 ld bc, #l__INITIALIZER + 0019 78 [ 4] 67 ld a, b + 001A B1 [ 4] 68 or a, c + 001B 28 08 [12] 69 jr Z, gsinit_static + 001D 11r00r00 [10] 70 ld de, #s__INITIALIZED + 0020 21r00r00 [10] 71 ld hl, #s__INITIALIZER + 0023 ED B0 [21] 72 ldir + 73 + 0025 74 gsinit_static: + 75 ; Explicitly initialized static variables inserted by compiler here. + 76 + 77 .area _GSFINAL + 0000 C9 [10] 78 ret + 79 + 80 .area _HOME + 81 + 82 ; set up timer hook + FD9F 83 H_TIMI = 0xFD9F + 0000 84 vinthook: + 0000 3E C3 [ 7] 85 ld a,#0xc3 + 0002 32 9F FD [13] 86 ld (H_TIMI),a + 0005 3Er00 [ 7] 87 ld a, #<(_cv_vint) + 0007 32 A0 FD [13] 88 ld (H_TIMI+1),a + 000A 3Es00 [ 7] 89 ld a, #>(_cv_vint) + 000C 32 A1 FD [13] 90 ld (H_TIMI+2),a + 000F C9 [10] 91 ret diff --git a/src/worker/lib/msx-libcv/crt0-msx.rel b/src/worker/lib/msx-libcv/crt0-msx.rel new file mode 100644 index 00000000..53e83abf --- /dev/null +++ b/src/worker/lib/msx-libcv/crt0-msx.rel @@ -0,0 +1,58 @@ +XL2 +H A areas D global symbols +M crt0 +S _cv_spint_handler Ref0000 +S l__DATA Ref0000 +S _main Ref0000 +S s__DATA Ref0000 +S _cv_init Ref0000 +S _cv_vint Ref0000 +S .__.ABS. Def0000 +S s__INITIALIZED Ref0000 +S ___sdcc_call_hl Ref0000 +S l__INITIALIZER Ref0000 +S s__INITIALIZER Ref0000 +A _CODE size 23 flags 0 addr 0 +S _cv_start Def0010 +A _INITIALIZER size 0 flags 0 addr 0 +A _HOME size 10 flags 0 addr 0 +A _GSINIT size 25 flags 0 addr 0 +S gsinit Def0000 +A _GSFINAL size 1 flags 0 addr 0 +A _DATA size 0 flags 0 addr 0 +A _INITIALIZED size 0 flags 0 addr 0 +A _BSEG size 0 flags 0 addr 0 +A _BSS size 0 flags 0 addr 0 +A _HEAP size 0 flags 0 addr 0 +T 00 00 41 42 10 00 10 00 00 00 00 00 00 00 00 00 +R 00 00 00 00 00 04 00 00 00 06 00 00 +T 0E 00 00 00 +R 00 00 00 00 +T 10 00 +R 00 00 00 00 +T 10 00 F3 31 00 E0 ED 56 CD 00 00 CD 00 00 CD +R 00 00 00 00 00 09 03 00 00 0C 02 00 +T 1D 00 00 00 CD 00 00 C7 +R 00 00 00 00 02 02 04 00 02 05 02 00 +T 00 00 +R 00 00 03 00 +T 00 00 01 00 00 78 B1 28 0F 21 00 00 36 00 0B 78 +R 00 00 03 00 02 03 01 00 02 0A 03 00 +T 0E 00 B1 28 05 5D 54 13 ED B0 +R 00 00 03 00 +T 16 00 +R 00 00 03 00 +T 16 00 01 00 00 78 B1 28 08 11 00 00 21 00 00 ED +R 00 00 03 00 02 03 09 00 02 0A 07 00 02 0D 0A 00 +T 24 00 B0 +R 00 00 03 00 +T 25 00 +R 00 00 03 00 +T 00 00 C9 +R 00 00 04 00 +T 00 00 +R 00 00 02 00 +T 00 00 3E C3 32 9F FD 3E 00 00 32 A0 FD 3E 00 00 +R 00 00 02 00 0B 08 05 00 8B 0E 05 00 +T 0C 00 32 A1 FD C9 +R 00 00 02 00 diff --git a/src/worker/lib/msx-libcv/cv.h b/src/worker/lib/msx-libcv/cv.h new file mode 100755 index 00000000..a6867567 --- /dev/null +++ b/src/worker/lib/msx-libcv/cv.h @@ -0,0 +1,62 @@ +// (c) 2013 Philipp Klaus Krause + +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#ifndef CV_H +#define CV_H 1 + +#include + +#define CV_LIBVERSION_MAJOR 0 +#define CV_LIBVERSION_MINOR 24 +#define CV_LIBVERSION_STRING "0.24" + +#include "cv_input.h" +#include "cv_graphics.h" +#include "cv_sound.h" + +// Set the handler for the vertical retrace interrupt. +extern void cv_set_vint_handler(void (* handler)(void)); + +// Get the handler for the vertical retrace interrupt. +extern void *cv_get_vint_handler(void); + +// Get the vertical retrace frequency in Hz. 50 for PAL, 60 for NTSC. +unsigned char cv_get_vint_frequency(void); + +#ifdef CV_CV +enum cv_machine { + CV_COLECOVISION = 0, // Coleco ColecoVision + //CV_ADAM = 1, // Coleco Adam - TODO + //CV_SUPERGAME = 2, // Coleco ColecoVision with super game module +}; +#endif +#ifdef CV_SMS +enum cv_machine { + CV_SG1000 = 0, // Sega SG-1000 + CV_SC3000 = 1, // Sega SC-3000 + CV_MARKIII = 2, // Sega Mark III or Master System + //CV_GAMEGEAR = 3, // Sega Game Gear - TODO +}; +#endif + +// Find out on which machine we are running +enum cv_machine cv_get_machine(void); + +// Get the contents of the refresh register R. Can be useful for seeding PRNGs. +uint8_t cv_get_r(void) __preserves_regs(b, c, d, e, h, iyl, iyh); + +#endif + diff --git a/src/worker/lib/msx-libcv/cv_graphics.h b/src/worker/lib/msx-libcv/cv_graphics.h new file mode 100755 index 00000000..8507da1ca --- /dev/null +++ b/src/worker/lib/msx-libcv/cv_graphics.h @@ -0,0 +1,255 @@ +#ifndef CV_GRAPHICS_H +#define CV_GRAPHICS_H 1 + +#include +#include +#include + +/* + These are the functions for controlling the graphics chip. + While a function marked as not reentrant is called no other + such function from this file may be called at the same time. +*/ + +typedef uint16_t cv_vmemp; // 14-Bit video memory address type + +#ifdef CV_SMS +typedef uint8_t cv_cmemp; // 5-bit color memory address type +#endif + +/* + Activate / deactivate screen + + This function is not reentrant! +*/ +extern void cv_set_screen_active(bool status); + +/* + Get screen status +*/ +extern bool cv_get_screen_active(void); + +/* + Enable / disable external video source. + + This function is not reentrant! +*/ +extern void cv_set_external_video(bool status); + +/* + Get external video source enabled. +*/ +extern bool cv_get_external_video(void); + +// TMS99xxA and Sega Master System screen modes +enum cv_screenmode { + CV_SCREENMODE_STANDARD = 0x00, // Standard screen modes + CV_SCREENMODE_TEXT = 0x10, + CV_SCREENMODE_MULTICOLOR = 0x08, + CV_SCREENMODE_BITMAP = 0x02, + CV_SCREENMODE_BITMAP_TEXT = 0x12, // Usefull undocumented screen modes + CV_SCREENMODE_BITMAP_MULTICOLOR = 0x0a, + CV_SCREENMODE_TEXT_MULTICOLOR = 0x18, // Useless undocumented screen modes + CV_SCREENMODE_BITMAP_TEXT_MULTICOLOR = 0x1a, + CV_SCREENMODE_4 = 0x06, // Sega Master System 315-5124 mode + CV_SCREENMODE_4_224 = 0x16, // Sega Master System 315-5246 modes + CV_SCREENMODE_4_240 = 0x0e, +}; + +/* + Set screen mode. + + This function is not reentrant! +*/ +extern void cv_set_screen_mode(enum cv_screenmode mode); + +/* + Get screen mode. +*/ +extern enum cv_screenmode cv_get_screen_mode(void); + +// TMS99xxA colors +enum cv_color { + CV_COLOR_TRANSPARENT = 0x0, + CV_COLOR_BLACK = 0x1, + CV_COLOR_GREEN = 0x2, + CV_COLOR_LIGHT_GREEN = 0x3, + CV_COLOR_BLUE = 0x4, + CV_COLOR_LIGHT_BLUE = 0x5, + CV_COLOR_DARK_RED = 0x6, + CV_COLOR_CYAN = 0x7, + CV_COLOR_RED = 0x8, + CV_COLOR_LIGHT_RED = 0x9, + CV_COLOR_YELLOW = 0xa, + CV_COLOR_LIGHT_YELLOW = 0xb, + CV_COLOR_DARK_GREEN = 0xc, + CV_COLOR_MAGENTA = 0xd, + CV_COLOR_GRAY = 0xe, + CV_COLOR_WHITE = 0xf +}; + +/* + Set colors. The foreground color is the text color in text mode, + in other modes it is unused. + The background color is used in all modes for the backdrop plane + (screen outside display area) and as the color that appears under + transparent characters. In text mode it is used for character + background. If the background color is the to cv_transparent, + the external video source is used as background image. +*/ +extern void cv_set_colors(enum cv_color foreground, enum cv_color background); + +/* + Set the location of the screen image table. + Must be a multiple of 0x400. Valid range: [0; 15360]. + When the screenmode is CV_SCREENMODE4 on the Sega 315-5124, + the location is a multible of 0x800, and the bit 0x400 is and mask to the location. + This masking functionality is undocumented. To use only the documented + graphics chip functionality always set bit 0x400. +*/ +extern void cv_set_image_table(cv_vmemp loc); + +/* + Set the location of the color table. Must be a multiple of 0x40. + Valid range: [0; 16320]. + When the screen mode ist CV_SCREENMODE_BITMAP, + CV_SCREENMODE_BITMAP_TEXT or CV_SCREENMODE_BITMAP_MULTICOLOR + this has a different meaning: The location of the color pattern table is + either 0 or 8192. The bits 4096 downto 128 are an and mask to the location. + This masking functionality is undocumented. To use only the documented + graphics chip functionality always set bits 4096 downto 128. +*/ +void cv_set_color_table(cv_vmemp loc); + +/* + Set the location of the character pattern table. Must be a multiple + of 0x800. Valid range: [0; 14336]. + When the screen mode ist CV_SCREENMODE_BITMAP, + CV_SCREENMODE_BITMAP_TEXT or CV_SCREENMODE_BITMAP_MULTICOLOR + this has a different meaning: The location of the character pattern table is + either 0 or 8192. Unless you add 4096 to the location the first third of the table + is used for the last third of the screen. Unless you add 2048 to the location the + first third of the table is used for the middle part of the screen. + Thus the bits 4096 and 2048 are and and mask to the highest bits of the + address. This masking functionality is undocumented. To use only the + documented graphics chip functionality always set bits 4096 and 2048. +*/ +// sdcc doesn't accept long function names. +extern void cv_set_character_pattern_t(cv_vmemp loc); + +/* + Set the location of the sprite pattern table. + Must be a multiple of 0x800. Valid range: [0; 14336]. + When the screenmode is CV_SCREENMODE4 the location is a multiple of 0x2000. + For the Sega 315-5124 and CV_SCREENMODE4, bits 0x800 and 0x1000 are + used as and mask. This masking functionality is undocumented. To use only the documented + graphics chip functionality always set bits 0x1000 downto 0x800. +*/ +extern void cv_set_sprite_pattern_table(cv_vmemp loc); + +/* + Set the location of the sprite attribute table. + Must be a multiple of 0x80. Valid range: [0; 16256]. +*/ +extern void cv_set_sprite_attribute_table(cv_vmemp loc); + +/* + Set sprite size; When active, sprites are 16x16 pixels instead of 8x8. + + This function is not reentrant! +*/ +extern void cv_set_sprite_big(bool status); + +/* + Get sprite size. +*/ +extern bool cv_get_sprite_big(void); + +/* + Set sprite magnification. When active, all sprites are displayed twice as big. + + This function is not reentrant! +*/ +extern void cv_set_sprite_magnification(bool status); + +/* + Get sprite magnification. +*/ +extern bool cv_get_sprite_magnification(void); + +/* + Get sprite collission. +*/ +extern bool cv_get_sprite_collission(void); + +/* + Get invalid sprite. Returns true if there was an invalid sprite. + If sprite is not 0 it will point to the number of the invalid sprite. +*/ +extern bool cv_get_sprite_invalid(uint8_t *sprite); + +extern void cv_set_write_vram_address(cv_vmemp address) __preserves_regs(b, c, d, e); + +extern void cv_set_read_vram_address(cv_vmemp address) __preserves_regs(b, c, d, e); + +#ifdef CV_SMS +extern void cv_set_write_cram_address(cv_cmemp address) __preserves_regs(b, c, d, e); +#endif + +extern void cv_memtovmemcpy_slow(const void *src, size_t n); + +extern void cv_memtovmemcpy_fast(const void *src, size_t n); + +extern void cv_vmemtomemcpy_slow(void *dest, size_t n); + +extern void cv_vmemtomemcpy_fast(void *dest, size_t n); + +extern void cv_vmemset_slow(int c, size_t n) __preserves_regs(iyl, iyh); + +extern void cv_vmemset_fast(int c, size_t n) __preserves_regs(iyl, iyh); + +#ifdef CV_MSX +static volatile __sfr __at 0x98 cv_graphics_port; +#else +static volatile __sfr __at 0xbe cv_graphics_port; +#endif + +inline void cv_voutb(const uint8_t value) +{ +__asm + cp a, (hl) + cp a, (hl) + nop +__endasm; + cv_graphics_port = value; +} + +inline uint8_t cv_vinb(void) +{ +__asm + cp a, (hl) + cp a, (hl) + nop +__endasm; + return(cv_graphics_port); +} + +#ifdef CV_SMS +void cv_set_left_column_blank(bool status); + +void cv_set_sprite_shift(bool status); + +enum cv_scroll_inhibit { + CV_HORIZONTAL_SCROLL_INHIBIT = 0x40, // Do not scroll top 2 rows + CV_VERTICAL_SCROLL_INHIBIT = 0x80, // Do not scroll right 8 columns +}; + +void cv_set_scroll_inhibit(enum cv_scroll_inhibit inhibit); + +void cv_set_hscroll(uint8_t offset); + +void cv_set_vscroll(uint8_t offset); +#endif + +#endif + diff --git a/src/worker/lib/msx-libcv/cv_input.h b/src/worker/lib/msx-libcv/cv_input.h new file mode 100755 index 00000000..68c251bb --- /dev/null +++ b/src/worker/lib/msx-libcv/cv_input.h @@ -0,0 +1,60 @@ +#ifndef CV_INPUT_H +#define CV_INPUT_H 1 + +#include + +#ifdef CV_CV + +#define CV_FIRE_0 0x40 +#define CV_FIRE_1 0x80 +#define CV_FIRE_2 0x10 +#define CV_FIRE_3 0x20 +#define CV_LEFT 0x08 +#define CV_DOWN 0x04 +#define CV_RIGHT 0x02 +#define CV_UP 0x01 + +#endif + +#ifdef CV_SMS + +#define CV_UP 0x01 +#define CV_DOWN 0x02 +#define CV_LEFT 0x04 +#define CV_RIGHT 0x08 +#define CV_FIRE_0 0x10 +#define CV_FIRE_1 0x20 + +#endif + +#ifdef CV_MSX + +#define CV_UP 0x01 +#define CV_DOWN 0x02 +#define CV_LEFT 0x04 +#define CV_RIGHT 0x08 +#define CV_FIRE_0 0x10 +#define CV_FIRE_1 0x20 + +#endif + +struct cv_controller_state +{ + uint8_t keypad; // Keypad: 0 - 9 as on keypad, * as 0xa, # as 0xb, 0xf for no key pressed or error. + uint8_t joystick;// Joystick: lowest 4 bit for joystick, higher 4 bit for fire buttons. +}; + +// Get keypad and joystick values. +void cv_get_controller_state(struct cv_controller_state *state, uint_fast8_t controller); + +#define CV_SPIN_ACTIVE 0x10 +#define CV_SPIN_RIGHT 0x20 + +// Set the handler for the spinner interrupt. +// This handler will be called when the wheel on the super action controller or the ball in the roller controller spin. +// The parameters passed to the handler correspond to the two super action controllers or +// the two axis in the roller controller. They can be anded with the above masks to test if they spinned, and which direction. +void cv_set_spint_handler(void (* handler)(uint_fast8_t, uint_fast8_t)); + +#endif + diff --git a/src/worker/lib/msx-libcv/cv_sound.h b/src/worker/lib/msx-libcv/cv_sound.h new file mode 100644 index 00000000..9099dd33 --- /dev/null +++ b/src/worker/lib/msx-libcv/cv_sound.h @@ -0,0 +1,43 @@ +#ifndef CV_SOUND_H +#define CV_SOUND_H 1 + +#include +#include + +enum cv_soundchannel { + CV_SOUNDCHANNEL_0 = 0x0, + CV_SOUNDCHANNEL_1 = 0x2, + CV_SOUNDCHANNEL_2 = 0x4, + CV_SOUNDCHANNEL_NOISE = 0x6 +}; + +enum cv_shift { + CV_NOISE_SHIFT_512 = 0, + CV_NOISE_SHIFT_1024 = 1, + CV_NOISE_SHIFT_2048 = 2, + CV_NOISE_SHIFT_CHAN2 = 3 +}; + +/* + Set attenuation for given sound channel in dezibel. Maximum attenuation is 28 db, + granularity is 2 db. +*/ +extern void cv_set_attenuation(enum cv_soundchannel channel, uint8_t dezibel); + +/* + Set frequency of a tone generator. The frequency is 3.579/frequency_divider Mhz. + This function is not reentrant. While it is called neither cv_set_attenuation() nor + cv_set_noise() may be called. n should be a multiple of 32. The valid range is [0, 32736]. +*/ + +extern void cv_set_frequency(enum cv_soundchannel channel, uint16_t frequency_divider); + +extern void cv_set_noise(bool white, enum cv_shift shift); + +#ifdef CV_MSX +static volatile __sfr __at 0xa0 psg_port_register; +static volatile __sfr __at 0xa1 psg_port_write; +static volatile __sfr __at 0xa2 psg_port_read; +#endif + +#endif diff --git a/src/worker/lib/msx-libcv/cv_support.h b/src/worker/lib/msx-libcv/cv_support.h new file mode 100755 index 00000000..20dc4a9e --- /dev/null +++ b/src/worker/lib/msx-libcv/cv_support.h @@ -0,0 +1,19 @@ +#ifndef __CV_SUPPORT_H +#define __CV_SUPPORT_H 1 + +#include + +#include "cv_graphics.h" + +extern void cv_init(void); // Initialize Colecovision library. + +extern void cv_vdpout(const uint8_t reg, const uint8_t data) __preserves_regs(d, e, iyl, iyh); // Write data to VDP control register reg. + +#ifndef CV_MSX +extern void cv_enable_nmi(void); + +extern void cv_disable_nmi(void); +#endif + +#endif + diff --git a/src/worker/lib/msx-libcv/cvu.h b/src/worker/lib/msx-libcv/cvu.h new file mode 100644 index 00000000..42e9343a --- /dev/null +++ b/src/worker/lib/msx-libcv/cvu.h @@ -0,0 +1,32 @@ +// (c) 2013 Philipp Klaus Krause + +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#ifndef CVU_H +#define CVU_H 1 + +#define CVU_LIBVERSION_MAJOR 0 +#define CVU_LIBVERSION_MINOR 17 +#define CVU_LIBVERSION_STRING "0.17" + +#include "cvu_input.h" +#include "cvu_graphics.h" +#include "cvu_sound.h" +#include "cvu_compression.h" +#include "cvu_f.h" +#include "cvu_c.h" + +#endif + diff --git a/src/worker/lib/msx-libcv/cvu_c.h b/src/worker/lib/msx-libcv/cvu_c.h new file mode 100644 index 00000000..0bb1c6a3 --- /dev/null +++ b/src/worker/lib/msx-libcv/cvu_c.h @@ -0,0 +1,37 @@ +#ifndef CVU_C_H +#define CVU_C_H 1 + +#include "cvu_f.h" + +// Complex fixed-point type +struct cvu_c +{ + cvu_f r; + cvu_f i; +}; + +// Addition +//extern void cadd(struct c *l, const struct c *r); +#define cvu_cadd(x, y) {(x)->r += (y)->r; (x)->i += (y)->i;} + +// Subtraction +//extern void csub(struct c *l, const struct c *r); +#define cvu_csub(x, y) {(x)->r -= (y)->r; (x)->i -= (y)->i;} + +// Multiplication +extern void cvu_cmul(struct cvu_c *l, const struct cvu_c *r); + +// Very inaccurate approximation +extern cvu_f cvu_cabs(const struct cvu_c *l); + +// Dot product: Returns l.r^2 + l.i^2 +extern cvu_f cvu_cdot(const struct cvu_c *l); + +// Multiplication by fixed-point number. +extern void cvu_cfmul(struct cvu_c *l, cvu_f r); + +// Convert from polar to coordinate representation +extern void cvu_c_from_polar(struct cvu_c *c, cvu_f phi, cvu_f d); + +#endif + diff --git a/src/worker/lib/msx-libcv/cvu_compression.h b/src/worker/lib/msx-libcv/cvu_compression.h new file mode 100644 index 00000000..17f581e0 --- /dev/null +++ b/src/worker/lib/msx-libcv/cvu_compression.h @@ -0,0 +1,93 @@ +// These decompression routines are rather complicated to allow customization. +// If you only want to decompress some data into graphics memory, you can use +// the functions at the end of this file instead. + +#ifndef CVU_COMPRESSION_H +#define CVU_COMPRESSION_H 1 + +#include +#include "cvu_graphics.h" + +// Huffman decompression +#undef CVU_HUFFMAN_ITERATIVE +#undef CVU_HUFFMAN_RECURSIVE + +struct cvu_huffman_node // Changing this struct will affect asm implementation of cvu_get_huffman +{ + uint8_t left; // Position of left node in tree or character. + uint8_t right; // Position of right node in tree or character. +}; + +struct cvu_huffman_state // Changing this struct will affect asm implementation of cvu_get_huffman, _read_from_array +{ + uint8_t (*input)(void); + const struct cvu_huffman_node *nodes; // Array of nodes + uint8_t root; // Position of root node among nodes + uint8_t ls, bs, rs; + unsigned char bit; // Position of currently processed bit + uint8_t buffer; // Currently processed input byte +#ifdef CVU_HUFFMAN_RECURSIVE + uint8_t current; // Currently processed node +#endif +}; + +void cvu_init_huffman(struct cvu_huffman_state *restrict state, uint8_t (* input)(void), const struct cvu_huffman_node *restrict tree, uint8_t root, uint8_t ls, uint8_t bs, uint8_t rs); +uint8_t cvu_get_huffman(struct cvu_huffman_state *state); + +// RLE decompression +struct cvu_rle_state // Changing this struct will affect asm implementation of cvu_get_rle, _read_from_array +{ + uint8_t (*input)(void); + uint8_t escape; + uint8_t left; + uint8_t buffer; +}; + +void cvu_init_rle(struct cvu_rle_state *restrict state, uint8_t (* input)(void), uint8_t escape); +uint8_t cvu_get_rle(struct cvu_rle_state *state); + +// LZK decompression +struct cvu_lzk_state +{ + uint8_t (*input)(void); + uint8_t escape; + uint8_t left; + uint8_t offset; + uint8_t start; + uint8_t buffer[64]; +}; + +void cvu_init_lzk(struct cvu_lzk_state *restrict state, uint8_t (* input)(void), uint8_t escape); +uint8_t cvu_get_lzk(struct cvu_lzk_state *state); + +// Decompression routines which will handle all the details for you. +// Just create a cvu_compression_state struct, initialize it and decompress. +struct cvu_compression_state // Changing this struct will affect asm implementation of _read_from_array +{ + struct cvu_huffman_state huffman; + struct cvu_rle_state rle; + const uint8_t *data; +}; + +// Initilization: +// data: compressed data +// state: compression struct to initialize +// tree: huffman tree generated by huffman_analyzer +// root, ls, bs, rs: constants generated by huffman_analyzer +// escape: constant generated by rle_analyzer +void cvu_init_compression(const uint8_t *restrict data, struct cvu_compression_state *restrict state, const struct cvu_huffman_node *restrict tree, uint8_t root, uint8_t ls, uint8_t bs, uint8_t rs, uint8_t escape); + +// The functions below can be mixed: + +// This function will return a decompressed octet on each invocation. +uint8_t cvu_get_compression(struct cvu_compression_state *state); + +// This function will decompress and write n octets to graphics memory at dest. +// It is not reentrant and may not be called why any function from cvu_graphics.h marked as such is called. +void cvu_memtovmemcpy_compression(cv_vmemp dest, struct cvu_compression_state *state, size_t n); + +// This function will decompress and write n octets to memory at dest. +void *cvu_memcpy_compression(void *restrict dest, struct cvu_compression_state *state, size_t n); + +#endif + diff --git a/src/worker/lib/msx-libcv/cvu_f.h b/src/worker/lib/msx-libcv/cvu_f.h new file mode 100644 index 00000000..51b99747 --- /dev/null +++ b/src/worker/lib/msx-libcv/cvu_f.h @@ -0,0 +1,46 @@ +// Fixed-point math can be useful where e.g. smooth movement is desired, but +// using float would make the application too slow and big. +// cvu_f is a 10.6 fixed point type. 10.6 has been chosen to ensure that the +// type can represent coordinates on the ColecoVision screen and in some +// "buffer" space surrounding it (to allow calculation of e.g. reflection). + +#ifndef CVU_F_H +#define CVU_F_H 1 + +#include +#include + +typedef int16_t cvu_f; // 10.6 fixed-point type. + +#define CVU_F_R 6 + +#define CVU_F_PI 201 +#define CVU_F_PI_2 100 +#define CVU_F_SQRT2 90 +#define CVU_F_SQRT1_2 45 +#define CVU_F_MIN INT16_MIN +#define CVU_F_MAX INT16_MAX + +// Convert integer to fixed-point +#define CVU_F2I(l) ((l) >> CVU_F_R) + +// Convert fixed-point to integer +#define CVU_I2F(l) ((l) << CVU_F_R) + +// Fixed-point multiplication +extern cvu_f cvu_fmul2(cvu_f l, cvu_f r); + +// Fixed-point division +extern cvu_f cvu_fdiv2(cvu_f l, cvu_f r); + +// Fixed-point sine +extern cvu_f cvu_fsin(cvu_f x); + +// Fixed-point cosine +extern cvu_f cvu_fcos(cvu_f x); + +// Fixed-point arcus tangens of x / y. +extern cvu_f cvu_fatan2(cvu_f y, cvu_f x); + +#endif + diff --git a/src/worker/lib/msx-libcv/cvu_graphics.h b/src/worker/lib/msx-libcv/cvu_graphics.h new file mode 100644 index 00000000..12e64928 --- /dev/null +++ b/src/worker/lib/msx-libcv/cvu_graphics.h @@ -0,0 +1,122 @@ +#ifndef CVU_GRAPHICS_H +#define CVU_GRAPHICS_H 1 + +#include + +#include "cv_graphics.h" + +#ifdef CV_SMS +/* + Copy n bytes of data from RAM at src to CRAM at dest. + + This function is not reentrant! + + The speed of this function depends on the active video mode + and if the screen is active. +*/ +extern void cvu_memtocmemcpy(cv_cmemp dest, const void * src, size_t n); +#endif + +/* + Copy n bytes of data from RAM at src to VRAM at dest. + + This function is not reentrant! + + The speed of this function depends on the active video mode + and if the screen is active. +*/ +extern void cvu_memtovmemcpy(cv_vmemp dest, const void * src, size_t n); + +/* + Copy n bytes of data from VRAM at src to RAM at dest. + + This function is not reentrant! + + The speed of this function depends on the active video mode + and if the screen is active. +*/ +extern void cvu_vmemtomemcpy(void *dest, cv_vmemp src, size_t n); + +/* + Set n bytes of VRAM at dest to c. + + This function is not reentrant! + + The speed of this function depends on the active video mode + and if the screen is active. +*/ +extern void cvu_vmemset(cv_vmemp dest, int c, size_t n); + +/* + Write an octet to graphics memory at dest. + + This function is not reentrant! +*/ +extern void cvu_voutb(const uint8_t value, const cv_vmemp dest); + +/* + Read an octet from graphics memory at src. + + This function is not reentrant! +*/ +extern uint8_t cvu_vinb(const cv_vmemp src); + +struct cvu_sprite +{ + uint8_t y; + uint8_t x; + uint8_t name; + uint8_t tag; +}; +#ifdef CV_SMS +struct cvu_sprite4 +{ + uint8_t y; + uint8_t x; + uint8_t name; +}; +#endif + +// Write sprite to display memory. Use the location of the sprite table as base. number should be in [0, 31]. +inline void cvu_set_sprite(const cv_vmemp base, uint_fast8_t number, const struct cvu_sprite *sprite) +{ + cv_set_write_vram_address((base) + (number) * 0x4); + cv_memtovmemcpy_slow((sprite), 4); +} + +// Write sprite to display memory (in mode 4). Use the location of the sprite table as base. number should be in [0, 63]. +#ifdef CV_SMS +inline void cvu_set_sprite4(const cv_vmemp base, uint_fast8_t number, const struct cvu_sprite4 *sprite) +{ + cvu_voutb(sprite->y, base + number); + cv_set_write_vram_address(base + 0x80 + number * 2); + cv_voutb(sprite->x); + cv_voutb(sprite->name); +} +#endif + +// Todo: is cvu_get_sprite needed? + +// Set the x coordinate of the sprite's upper left corner. x will be clamped to [-32, 255] +extern void cvu_set_sprite_x(struct cvu_sprite *sprite, int x) __preserves_regs(d, e); + +extern int cvu_get_sprite_x(const struct cvu_sprite *sprite) __preserves_regs(b, c, d, e); + +// Set the y coordinate of the sprite's upper left corner. y will be clamped to [-32, 207] +extern void cvu_set_sprite_y(struct cvu_sprite *sprite, int y) __preserves_regs(d, e); + +extern int cvu_get_sprite_y(const struct cvu_sprite *sprite) __preserves_regs(d, e); + +// Set them both at once. +extern void cvu_set_sprite_xy(struct cvu_sprite *sprite, int x, int y); + +// Set the sprite's color. +inline void cvu_set_sprite_color(struct cvu_sprite *sprite, enum cv_color color) +{ + sprite->tag = (sprite->tag & 0x80) | color; +} + +extern enum cv_color cvu_get_sprite_color(struct cvu_sprite *sprite); + +#endif + diff --git a/src/worker/lib/msx-libcv/cvu_input.h b/src/worker/lib/msx-libcv/cvu_input.h new file mode 100644 index 00000000..0353a889 --- /dev/null +++ b/src/worker/lib/msx-libcv/cvu_input.h @@ -0,0 +1,15 @@ +#ifndef CVU_INPUT_H +#define CVU_INPUT_H 1 + +#include + +#include "cv_input.h" + +// For the super action controllers this gives the spinner movement (total relative movement since last call, negative for left, positive for right) +// For the roller controller this gives the ball movement (total relative as above). +// Using this function will set a libvu-specific spint handler, so it is incompatible with using a custom spint handler. + +int_fast8_t cvu_get_spinner(uint_fast8_t controller); + +#endif + diff --git a/src/worker/lib/msx-libcv/cvu_sound.h b/src/worker/lib/msx-libcv/cvu_sound.h new file mode 100644 index 00000000..77f94468 --- /dev/null +++ b/src/worker/lib/msx-libcv/cvu_sound.h @@ -0,0 +1,45 @@ +#ifndef CVU_SOUND_H +#define CVU_SOUND 1 + +#include + +#include "cv_sound.h" + +extern const uint16_t CVU_TUNING_ISO16_EQUAL[15]; // ISO 16 pitch (A at 440 Hz) with equal tuning. +extern const uint16_t CVU_TUNING_SCIENTIFIC_EQUAL[15]; // Scientific pitch (C at 256 Hz) with equal tuning. + +extern const uint8_t CVU_VOLUME_DEFAULT[4]; + +extern const uint16_t CVU_EMPTY_MUSIC; + +// channel holds the channel that will be used to play the music. +// volume is a pointer to an array of loudnesses in Dezibel for p, mp, mf, f. +// tuning is a pointer to an arrays of frequency dividers for the halftones of oktave 0. +// sixteenth_notes_per_second should explain itself. +// notes is a pointer to the music in the following format: +// Every note cosists of 16 bits. The most significant four mark the octave, the next 4 +// the halftone (0xf means pause) the next 4 bits give the absolute length. The next 2 +// give the relative length. the last 2 bits are the loudness. +// The rest of the structure's members are for internal use by cvu_play_music(). +struct cvu_music +{ + enum cv_soundchannel channel; + const uint8_t *volume; + const uint16_t *tuning; + uint8_t sixteenth_notes_per_second; + const uint16_t *notes; + + uint16_t note_ticks_remaining; + uint16_t pause_ticks_remaining; +}; + +// This will initialize a cvu_music structure with default values for all +// members except notes. +extern void cvu_init_music(struct cvu_music *music); + +// This function should be placed inside the vint handler or triggered by the vint handler. +// It will return false once it is finished playing the music. +extern bool cvu_play_music(struct cvu_music *restrict music); + +#endif + diff --git a/src/worker/lib/msx-libcv/libcv-msx.lib b/src/worker/lib/msx-libcv/libcv-msx.lib new file mode 100644 index 00000000..9199e2bf Binary files /dev/null and b/src/worker/lib/msx-libcv/libcv-msx.lib differ diff --git a/src/worker/lib/msx-libcv/libcvu-msx.lib b/src/worker/lib/msx-libcv/libcvu-msx.lib new file mode 100644 index 00000000..5b873381 Binary files /dev/null and b/src/worker/lib/msx-libcv/libcvu-msx.lib differ diff --git a/src/worker/lib/msx/Makefile b/src/worker/lib/msx/Makefile new file mode 100644 index 00000000..c407ef00 --- /dev/null +++ b/src/worker/lib/msx/Makefile @@ -0,0 +1,3 @@ + +%.rel: %.s + sdasz80 -plosgff %< diff --git a/src/worker/lib/msx/crt0-msx.lst b/src/worker/lib/msx/crt0-msx.lst new file mode 100644 index 00000000..0942c587 --- /dev/null +++ b/src/worker/lib/msx/crt0-msx.lst @@ -0,0 +1,75 @@ + 1 ; crt0.s for Colecovision cart + 2 + 3 .module crt0 + 4 .globl _main + 5 .globl ___sdcc_call_hl + 6 + 7 ; Ordering of segments for the linker - copied from sdcc crt0.s + 8 .area _CODE + 9 .area _INITIALIZER + 10 .area _HOME + 11 .area _GSINIT + 12 .area _GSFINAL + 13 .area _DATA + 14 .area _INITIALIZED + 15 .area _BSEG + 16 .area _BSS + 17 .area _HEAP + 18 + 19 .area _CODE + 20 ; MSX cartridge header @ 0x4000 - 0x400f + 0000 41 42 21 .dw 0x4241 + 0002r10r00 22 .dw _Start + 0004r10r00 23 .dw _Start + 0006 00 00 24 .dw 0 + 0008 00 00 25 .dw 0 + 000A 00 00 26 .dw 0 + 000C 00 00 27 .dw 0 + 000E 00 00 28 .dw 0 + 29 + 0010 30 _Start: + 0010 F3 [ 4] 31 di + 0011 31 00 E0 [10] 32 ld sp, #0xe000 ; Set stack pointer directly above top of memory. + 0014 ED 56 [ 8] 33 im 1 + 34 + 0016 CDr00r00 [17] 35 call gsinit ; Initialize global and static variables. + 0019 CDr00r00 [17] 36 call _main + 001C C7 [11] 37 rst 0x0 ; Restart when main() returns. + 38 + 39 .area _GSINIT + 0000 40 gsinit:: + 41 + 42 ; Implicitly zeroed global and static variables. + 0000 01r00r00 [10] 43 ld bc, #l__DATA + 0003 78 [ 4] 44 ld a, b + 0004 B1 [ 4] 45 or a, c + 0005 28 0F [12] 46 jr Z, zeroed_data + 0007 21r00r00 [10] 47 ld hl, #s__DATA + 000A 36 00 [10] 48 ld (hl), #0x00 + 000C 0B [ 6] 49 dec bc + 000D 78 [ 4] 50 ld a, b + 000E B1 [ 4] 51 or a, c + 000F 28 05 [12] 52 jr Z, zeroed_data + 0011 5D [ 4] 53 ld e, l + 0012 54 [ 4] 54 ld d, h + 0013 13 [ 6] 55 inc de + 0014 ED B0 [21] 56 ldir + 0016 57 zeroed_data: + 58 + 59 ; Explicitly initialized global variables. + 0016 01r00r00 [10] 60 ld bc, #l__INITIALIZER + 0019 78 [ 4] 61 ld a, b + 001A B1 [ 4] 62 or a, c + 001B 28 08 [12] 63 jr Z, gsinit_static + 001D 11r00r00 [10] 64 ld de, #s__INITIALIZED + 0020 21r00r00 [10] 65 ld hl, #s__INITIALIZER + 0023 ED B0 [21] 66 ldir + 67 + 0025 68 gsinit_static: + 69 ; Explicitly initialized static variables inserted by compiler here. + 70 + 71 .area _GSFINAL + 0000 C9 [10] 72 ret + 73 + 74 .area _HOME + 75 diff --git a/src/worker/lib/msx/crt0-msx.rel b/src/worker/lib/msx/crt0-msx.rel new file mode 100644 index 00000000..0008bc46 --- /dev/null +++ b/src/worker/lib/msx/crt0-msx.rel @@ -0,0 +1,46 @@ +XL2 +H A areas 9 global symbols +M crt0 +S l__DATA Ref0000 +S _main Ref0000 +S s__DATA Ref0000 +S .__.ABS. Def0000 +S s__INITIALIZED Ref0000 +S ___sdcc_call_hl Ref0000 +S l__INITIALIZER Ref0000 +S s__INITIALIZER Ref0000 +A _CODE size 1D flags 0 addr 0 +A _INITIALIZER size 0 flags 0 addr 0 +A _HOME size 0 flags 0 addr 0 +A _GSINIT size 25 flags 0 addr 0 +S gsinit Def0000 +A _GSFINAL size 1 flags 0 addr 0 +A _DATA size 0 flags 0 addr 0 +A _INITIALIZED size 0 flags 0 addr 0 +A _BSEG size 0 flags 0 addr 0 +A _BSS size 0 flags 0 addr 0 +A _HEAP size 0 flags 0 addr 0 +T 00 00 41 42 10 00 10 00 00 00 00 00 00 00 00 00 +R 00 00 00 00 00 04 00 00 00 06 00 00 +T 0E 00 00 00 +R 00 00 00 00 +T 10 00 +R 00 00 00 00 +T 10 00 F3 31 00 E0 ED 56 CD 00 00 CD 00 00 C7 +R 00 00 00 00 00 09 03 00 02 0C 01 00 +T 00 00 +R 00 00 03 00 +T 00 00 01 00 00 78 B1 28 0F 21 00 00 36 00 0B 78 +R 00 00 03 00 02 03 00 00 02 0A 02 00 +T 0E 00 B1 28 05 5D 54 13 ED B0 +R 00 00 03 00 +T 16 00 +R 00 00 03 00 +T 16 00 01 00 00 78 B1 28 08 11 00 00 21 00 00 ED +R 00 00 03 00 02 03 06 00 02 0A 04 00 02 0D 07 00 +T 24 00 B0 +R 00 00 03 00 +T 25 00 +R 00 00 03 00 +T 00 00 C9 +R 00 00 04 00 diff --git a/src/worker/lib/msx/crt0-msx.s b/src/worker/lib/msx/crt0-msx.s new file mode 100644 index 00000000..6eeb94a2 --- /dev/null +++ b/src/worker/lib/msx/crt0-msx.s @@ -0,0 +1,75 @@ +; crt0.s for Colecovision cart + + .module crt0 + .globl _main + .globl ___sdcc_call_hl + + ; Ordering of segments for the linker - copied from sdcc crt0.s + .area _CODE + .area _INITIALIZER + .area _HOME + .area _GSINIT + .area _GSFINAL + .area _DATA + .area _INITIALIZED + .area _BSEG + .area _BSS + .area _HEAP + + .area _CODE +; MSX cartridge header @ 0x4000 - 0x400f + .dw 0x4241 + .dw _Start + .dw _Start + .dw 0 + .dw 0 + .dw 0 + .dw 0 + .dw 0 + +_Start: + di + ld sp, #0xe000 ; Set stack pointer directly above top of memory. + im 1 + + call gsinit ; Initialize global and static variables. + call _main + rst 0x0 ; Restart when main() returns. + + .area _GSINIT +gsinit:: + + ; Implicitly zeroed global and static variables. + ld bc, #l__DATA + ld a, b + or a, c + jr Z, zeroed_data + ld hl, #s__DATA + ld (hl), #0x00 + dec bc + ld a, b + or a, c + jr Z, zeroed_data + ld e, l + ld d, h + inc de + ldir +zeroed_data: + + ; Explicitly initialized global variables. + ld bc, #l__INITIALIZER + ld a, b + or a, c + jr Z, gsinit_static + ld de, #s__INITIALIZED + ld hl, #s__INITIALIZER + ldir + +gsinit_static: + ; Explicitly initialized static variables inserted by compiler here. + + .area _GSFINAL + ret + + .area _HOME + diff --git a/src/worker/lib/msx/crt0-msx.sym b/src/worker/lib/msx/crt0-msx.sym new file mode 100644 index 00000000..0a9dacf2 --- /dev/null +++ b/src/worker/lib/msx/crt0-msx.sym @@ -0,0 +1,27 @@ + ASxxxx Assembler V02.00 + NoICE + SDCC mods (Zilog Z80 / Hitachi HD64180 / ZX-Next / eZ80), page 1. +Hexadecimal [16-Bits] + +Symbol Table + + .__.$$$.= 2710 L | .__.ABS.= 0000 G | .__.CPU.= 0000 L + .__.H$L.= 0000 L | 0 _Start 0010 R | ___sdcc_ **** GX + _main **** GX | 3 gsinit 0000 GR | 3 gsinit_s 0025 R + l__DATA **** GX | l__INITI **** GX | s__DATA **** GX + s__INITI **** GX | s__INITI **** GX | 3 zeroed_d 0016 R + + ASxxxx Assembler V02.00 + NoICE + SDCC mods (Zilog Z80 / Hitachi HD64180 / ZX-Next / eZ80), page 2. +Hexadecimal [16-Bits] + +Area Table + + 0 _CODE size 1D flags 0 + 1 _INITIAL size 0 flags 0 + 2 _HOME size 0 flags 0 + 3 _GSINIT size 25 flags 0 + 4 _GSFINAL size 1 flags 0 + 5 _DATA size 0 flags 0 + 6 _INITIAL size 0 flags 0 + 7 _BSEG size 0 flags 0 + 8 _BSS size 0 flags 0 + 9 _HEAP size 0 flags 0 + diff --git a/src/worker/lib/sms-sg1000-libcv/cv.h b/src/worker/lib/sms-sg1000-libcv/cv.h index f258ed17..a6867567 100644 --- a/src/worker/lib/sms-sg1000-libcv/cv.h +++ b/src/worker/lib/sms-sg1000-libcv/cv.h @@ -36,13 +36,14 @@ extern void *cv_get_vint_handler(void); // Get the vertical retrace frequency in Hz. 50 for PAL, 60 for NTSC. unsigned char cv_get_vint_frequency(void); -#ifndef CV_SMS +#ifdef CV_CV enum cv_machine { CV_COLECOVISION = 0, // Coleco ColecoVision //CV_ADAM = 1, // Coleco Adam - TODO //CV_SUPERGAME = 2, // Coleco ColecoVision with super game module }; -#else +#endif +#ifdef CV_SMS enum cv_machine { CV_SG1000 = 0, // Sega SG-1000 CV_SC3000 = 1, // Sega SC-3000 diff --git a/src/worker/lib/sms-sg1000-libcv/cv_graphics.h b/src/worker/lib/sms-sg1000-libcv/cv_graphics.h index 4e1c09ac..8507da1ca 100644 --- a/src/worker/lib/sms-sg1000-libcv/cv_graphics.h +++ b/src/worker/lib/sms-sg1000-libcv/cv_graphics.h @@ -12,6 +12,7 @@ */ typedef uint16_t cv_vmemp; // 14-Bit video memory address type + #ifdef CV_SMS typedef uint8_t cv_cmemp; // 5-bit color memory address type #endif @@ -207,7 +208,11 @@ extern void cv_vmemset_slow(int c, size_t n) __preserves_regs(iyl, iyh); extern void cv_vmemset_fast(int c, size_t n) __preserves_regs(iyl, iyh); +#ifdef CV_MSX +static volatile __sfr __at 0x98 cv_graphics_port; +#else static volatile __sfr __at 0xbe cv_graphics_port; +#endif inline void cv_voutb(const uint8_t value) { diff --git a/src/worker/lib/sms-sg1000-libcv/cv_input.h b/src/worker/lib/sms-sg1000-libcv/cv_input.h index 83466c36..68c251bb 100644 --- a/src/worker/lib/sms-sg1000-libcv/cv_input.h +++ b/src/worker/lib/sms-sg1000-libcv/cv_input.h @@ -3,7 +3,7 @@ #include -#ifndef CV_SMS +#ifdef CV_CV #define CV_FIRE_0 0x40 #define CV_FIRE_1 0x80 @@ -14,7 +14,20 @@ #define CV_RIGHT 0x02 #define CV_UP 0x01 -#else +#endif + +#ifdef CV_SMS + +#define CV_UP 0x01 +#define CV_DOWN 0x02 +#define CV_LEFT 0x04 +#define CV_RIGHT 0x08 +#define CV_FIRE_0 0x10 +#define CV_FIRE_1 0x20 + +#endif + +#ifdef CV_MSX #define CV_UP 0x01 #define CV_DOWN 0x02 diff --git a/src/worker/lib/sms-sg1000-libcv/cv_sound.h b/src/worker/lib/sms-sg1000-libcv/cv_sound.h index 5241d0b9..9099dd33 100644 --- a/src/worker/lib/sms-sg1000-libcv/cv_sound.h +++ b/src/worker/lib/sms-sg1000-libcv/cv_sound.h @@ -34,4 +34,10 @@ extern void cv_set_frequency(enum cv_soundchannel channel, uint16_t frequency_di extern void cv_set_noise(bool white, enum cv_shift shift); +#ifdef CV_MSX +static volatile __sfr __at 0xa0 psg_port_register; +static volatile __sfr __at 0xa1 psg_port_write; +static volatile __sfr __at 0xa2 psg_port_read; +#endif + #endif diff --git a/src/worker/lib/sms-sg1000-libcv/cv_support.h b/src/worker/lib/sms-sg1000-libcv/cv_support.h index cfed5ca5..20dc4a9e 100644 --- a/src/worker/lib/sms-sg1000-libcv/cv_support.h +++ b/src/worker/lib/sms-sg1000-libcv/cv_support.h @@ -9,9 +9,11 @@ extern void cv_init(void); // Initialize Colecovision library. extern void cv_vdpout(const uint8_t reg, const uint8_t data) __preserves_regs(d, e, iyl, iyh); // Write data to VDP control register reg. +#ifndef CV_MSX extern void cv_enable_nmi(void); extern void cv_disable_nmi(void); +#endif #endif diff --git a/src/worker/lib/sms-sg1000-libcv/cvu_graphics.h b/src/worker/lib/sms-sg1000-libcv/cvu_graphics.h index 7aa47d90..12e64928 100644 --- a/src/worker/lib/sms-sg1000-libcv/cvu_graphics.h +++ b/src/worker/lib/sms-sg1000-libcv/cvu_graphics.h @@ -86,8 +86,7 @@ inline void cvu_set_sprite(const cv_vmemp base, uint_fast8_t number, const struc // Write sprite to display memory (in mode 4). Use the location of the sprite table as base. number should be in [0, 63]. #ifdef CV_SMS -/* TODO: used to be inline, but sdcc barfs */ -void cvu_set_sprite4(const cv_vmemp base, uint_fast8_t number, const struct cvu_sprite4 *sprite) +inline void cvu_set_sprite4(const cv_vmemp base, uint_fast8_t number, const struct cvu_sprite4 *sprite) { cvu_voutb(sprite->y, base + number); cv_set_write_vram_address(base + 0x80 + number * 2); diff --git a/src/worker/lib/sms-sg1000-libcv/libcv-sms.lib b/src/worker/lib/sms-sg1000-libcv/libcv-sms.lib index 3ed3bba5..69767bc7 100644 Binary files a/src/worker/lib/sms-sg1000-libcv/libcv-sms.lib and b/src/worker/lib/sms-sg1000-libcv/libcv-sms.lib differ diff --git a/src/worker/lib/sms-sg1000-libcv/libcvu-sms.lib b/src/worker/lib/sms-sg1000-libcv/libcvu-sms.lib index 08ee3296..2d5fdd23 100644 Binary files a/src/worker/lib/sms-sg1000-libcv/libcvu-sms.lib and b/src/worker/lib/sms-sg1000-libcv/libcvu-sms.lib differ diff --git a/src/worker/workermain.ts b/src/worker/workermain.ts index 214680ab..44530c08 100644 --- a/src/worker/workermain.ts +++ b/src/worker/workermain.ts @@ -171,13 +171,49 @@ var PLATFORM_PARAMS = { data_start: 0x7000, data_size: 0x400, stack_end: 0x8000, - extra_preproc_args: ['-I', '/share/include/coleco'], + extra_preproc_args: ['-I', '/share/include/coleco', '-D', 'CV_CV'], extra_link_args: ['-k', '/share/lib/coleco', '-l', 'libcv', '-l', 'libcvu', 'crt0.rel'], extra_segments:[ {name:'BIOS',start:0x0,size:0x2000,type:'rom'}, {name:'Cartridge Header',start:0x8000,size:0x100,type:'rom'}, ], }, + 'msx': { + rom_start: 0x4000, + code_start: 0x4000, + rom_size: 0x8000, + data_start: 0xc000, + data_size: 0x3000, + stack_end: 0xffff, + extra_link_args: ['crt0-msx.rel'], + extra_link_files: ['crt0-msx.rel', 'crt0-msx.lst'], + extra_segments:[ + {name:'BIOS',start:0x0,size:0x4000,type:'rom'}, + //{name:'Cartridge',start:0x4000,size:0x4000,type:'rom'}, + {name:'RAM',start:0xc000,size:0x3200,type:'ram'}, + {name:'Stack',start:0xf000,size:0x300,type:'ram'}, + {name:'BIOS Work RAM',start:0xf300,size:0xd00}, + ], + }, + 'msx-libcv': { + rom_start: 0x4000, + code_start: 0x4000, + rom_size: 0x8000, + data_start: 0xc000, + data_size: 0x3000, + stack_end: 0xffff, + extra_preproc_args: ['-I', '.', '-D', 'CV_MSX'], + extra_link_args: ['-k', '.', '-l', 'libcv-msx', '-l', 'libcvu-msx', 'crt0-msx.rel'], + extra_link_files: ['libcv-msx.lib', 'libcvu-msx.lib', 'crt0-msx.rel', 'crt0-msx.lst'], + extra_compile_files: ['cv.h','cv_graphics.h','cv_input.h','cv_sound.h','cv_support.h','cvu.h','cvu_c.h','cvu_compression.h','cvu_f.h','cvu_graphics.h','cvu_input.h','cvu_sound.h'], + extra_segments:[ + {name:'BIOS',start:0x0,size:0x4000,type:'rom'}, + //{name:'Cartridge',start:0x4000,size:0x4000,type:'rom'}, + {name:'RAM',start:0xc000,size:0x3200,type:'ram'}, + {name:'Stack',start:0xf000,size:0x300,type:'ram'}, + {name:'BIOS Work RAM',start:0xf300,size:0xd00}, + ], + }, 'sms-sg1000-libcv': { rom_start: 0x0000, code_start: 0x0100,