diff --git a/doc/notes.txt b/doc/notes.txt index 623c28f6..63e38da4 100644 --- a/doc/notes.txt +++ b/doc/notes.txt @@ -79,6 +79,9 @@ TODO: - rename, delete, save as - sdcc: can't link asm files before c files - what if >1 file with same name? (local/nonlocal/directory) +- can't upload files already exist +- upload files w/o new project +- what if .c and .s names collide? WEB WORKER FORMAT diff --git a/presets/coleco/mode2bitmap.c b/presets/coleco/mode2bitmap.c index ad2d025b..a2d13fe1 100644 --- a/presets/coleco/mode2bitmap.c +++ b/presets/coleco/mode2bitmap.c @@ -12,7 +12,7 @@ /* link in MODE 2 bitmap data */ -//#link "bitmaps/sailboat.s" +//#link "sailboat.s" extern const unsigned char msx_bitmap[0x3807]; diff --git a/presets/coleco/mode2compressed.c b/presets/coleco/mode2compressed.c index 53532583..6b6ac23f 100644 --- a/presets/coleco/mode2compressed.c +++ b/presets/coleco/mode2compressed.c @@ -14,7 +14,7 @@ //#link "lzg.c" -//#link "bitmaps/sailboat-lzg.s" +//#link "sailboat-lzg.s" extern const unsigned char msx_bitmap_lzg[]; diff --git a/presets/coleco/bitmaps/sailboat-lzg.s b/presets/coleco/sailboat-lzg.s similarity index 100% rename from presets/coleco/bitmaps/sailboat-lzg.s rename to presets/coleco/sailboat-lzg.s diff --git a/presets/coleco/bitmaps/sailboat.s b/presets/coleco/sailboat.s similarity index 100% rename from presets/coleco/bitmaps/sailboat.s rename to presets/coleco/sailboat.s diff --git a/src/platform/msx.ts b/src/platform/msx.ts new file mode 100644 index 00000000..1711efc4 --- /dev/null +++ b/src/platform/msx.ts @@ -0,0 +1,389 @@ +"use strict"; + +import { Platform, BaseZ80Platform, getToolForFilename_z80 } from "../baseplatform"; +import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap } from "../emu"; +import { hex, lzgmini, stringToByteArray } from "../util"; +import { MasterAudio, SN76489_Audio } from "../audio"; +import { TMS9918A } from "../video/tms9918a"; + +// https://www.konamiman.com/msx/msx-e.html#msx2th +// https://www.msx.org/wiki/MSX_Cartridge_slot +// http://map.grauw.nl/resources/msx_io_ports.php +// https://openmsx.org/manual/setup.html +// https://www.msx.org/wiki/Slots +// https://www.msx.org/wiki/SDCC + +var MSX_PRESETS = [ + {id:'helloworld.asm', name:'Hello World (ASM)'}, +]; + +var MSX_KEYCODE_MAP = makeKeycodeMap([ + [Keys.VK_UP, 0, 0x1], + [Keys.VK_DOWN, 0, 0x4], + [Keys.VK_LEFT, 0, 0x8], + [Keys.VK_RIGHT, 0, 0x2], + [Keys.VK_SPACE, 0, 0x40], + [Keys.VK_CONTROL, 1, 0x40], + + [Keys.VK_W, 2, 0x1], + [Keys.VK_S, 2, 0x4], + [Keys.VK_A, 2, 0x8], + [Keys.VK_D, 2, 0x2], + [Keys.VK_Z, 2, 0x40], + [Keys.VK_X, 3, 0x40], +]); + +/// standard emulator + +const _MSXPlatform = function(mainElement) { + + const cpuFrequency = 3579545; // MHz + const canvasWidth = 304; + const numTotalScanlines = 262; + const numVisibleScanlines = 240; + const cpuCyclesPerLine = Math.round(cpuFrequency / 60 / numTotalScanlines); + + var cpu, ram, membus, iobus, rom, bios; + var video, vdp, timer; + var audio, psg; + var inputs = new Uint8Array(4); + var slotmask = 0; + var slots : MSXSlot[]; + + interface MSXSlot { + read(addr:number) : number; + write(addr:number, val:number) : void; + } + + class MSXPlatform extends BaseZ80Platform implements Platform { + + getPresets() { return MSX_PRESETS; } + getToolForFilename = getToolForFilename_z80; + getDefaultExtension() { return ".c"; }; + + start() { + ram = new RAM(0x10000); + bios = new lzgmini().decode(stringToByteArray(atob(MSX1_BIOS_LZG))); + slots = [ + // slot 0 : BIOS + { + read: (a) => { return bios[a] | 0; }, + write: (a,v) => { } + }, + // slot 1: cartridge + { + read: (a) => { return rom[a] | 0; }, + write: (a,v) => { } + }, + // slot 2 : empty + null, + // slot 3 : RAM + { + read: (a) => { return ram[a] | 0; }, + write: (a,v) => { ram[a] = v; } + }, + ]; + // slot mapper + membus = { + read: (a) => { + let shift = (a >> 14) << 1; + let slotnum = (slotmask >> shift) & 3; + let slot = slots[slotnum]; + return slot ? slot.read(a) : 0; + }, + write: (a,v) => { + let shift = (a >> 14) << 1; + let slotnum = (slotmask >> shift) & 3; + let slot = slots[slotnum]; + if (slot) slot.write(a, v); + }, + isContended: function() { return false; }, + }; + iobus = { + read: function(addr) { + addr &= 0xff; + //console.log('IO read', hex(addr,4)); + switch (addr) { + case 0x98: return vdp.readData(); + case 0x99: return vdp.readStatus(); + case 0xa8: return slotmask; + } + return 0; + }, + write: function(addr, val) { + addr &= 0xff; + val &= 0xff; + //console.log('IO write', hex(addr,4), hex(val,2)); + switch (addr) { + case 0x98: vdp.writeData(val); break; + case 0x99: vdp.writeAddress(val); break; + case 0xa8: slotmask = val; break; + } + } + }; + cpu = this.newCPU(membus, iobus); + video = new RasterVideo(mainElement,canvasWidth,numVisibleScanlines); + video.create(); + audio = new MasterAudio(); + psg = new SN76489_Audio(audio); + var cru = { + setVDPInterrupt: (b) => { + if (b) { + cpu.nonMaskableInterrupt(); + } else { + // TODO: reset interrupt? + } + } + }; + vdp = new TMS9918A(video.canvas, cru, false); + setKeyboardFromMap(video, inputs, MSX_KEYCODE_MAP); + timer = new AnimationTimer(60, this.nextFrame.bind(this)); + } + + readAddress(addr) { + return membus.read(addr); + } + + advance(novideo : boolean) { + for (var sl=0; sl 0) + if (dir.length > 0 && dir != 'local') // TODO files.push(dir + '/' + fn); } diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 00000000..cd516673 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,19 @@ + +all: binaries images/parrot.c + +%.hex: % + cat $< | hexdump -v -e '"\n.byte" 16/1 ",0x%02x"' | sed "s/byte,/byte /" > $@ + +%.c: %.CHR.lzg.hex %.CLR.lzg.hex + echo "// MSX mode 2 data" > $@ + xxd -i $(word 1,$^) >> $@ + xxd -i $(word 2,$^) >> $@ + +%.lzg: % + lzg -9 $< $@ + +%.CHR: %.tga + ./scr2floyd_percept $< + +binaries: scr2floyd scr2floyd_percept galois + diff --git a/tools/convertmode2.sh b/tools/convertmode2.sh new file mode 100755 index 00000000..90ae65c3 --- /dev/null +++ b/tools/convertmode2.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +./scr2floyd_percept $1.tga +lzg -9 $1.CHR > $1.CHR.lzg +lzg -9 $1.CLR > $1.CLR.lzg +rm -f $1.s +echo "\t.area _CODE" >> $1.s +echo "\t.globl _msx_mode2_pattern_lzg" >> $1.s +echo "\t.globl _msx_mode2_color_lzg" >> $1.s +echo "\n_msx_mode2_pattern_lzg:" >> $1.s +cat $1.CHR.lzg | hexdump -v -e '"\n.db " 16/1 ",0x%02x"' | sed "s/n.db,/ .db /" | tail -n +3 >> $1.s +echo "\n_msx_mode2_color_lzg:" >> $1.s +cat $1.CLR.lzg | hexdump -v -e '"\n.db " 16/1 ",0x%02x"' | sed "s/n.db,/ .db /" | tail -n +3 >> $1.s + diff --git a/tools/images/parrot.tga b/tools/images/parrot.tga new file mode 100644 index 00000000..942644eb Binary files /dev/null and b/tools/images/parrot.tga differ