c64: started WASM implementation from https://github.com/sehugg/chips

use async functions in startUI()
This commit is contained in:
Steven Hugg 2019-12-17 19:30:42 -06:00
parent 0daea22c2a
commit 7d6e910e57
7 changed files with 243 additions and 40 deletions

View File

@ -590,7 +590,7 @@ $( ".dropdown-submenu" ).click(function(event) {
</script>
<script>
startUI(true);
startUI();
</script>
<script>

49
presets/c64/hello.dasm Normal file
View File

@ -0,0 +1,49 @@
processor 6502
org $7ffe
word $8000 ; load address
; cartridge header (http://swut.net/c64cart-howto.html)
.byte $09, $80, $25, $80
.byte $c3, $c2, $cd, $38, $30
.byte $8e, $16, $d0, $20, $a3, $fd, $20
.byte $50, $fd, $20, $15, $fd, $20, $5b
.byte $ff, $58
.byte $ea, $ea, $ea, $ea, $ea, $ea, $ea
.byte $ea, $ea, $ea, $ea, $ea
; program start
Temp equ $00
Start
sei ; turn off interrupts
ldy #0
sty $d020 ; reset border color
Loop
lda Message,y ; load message byte
beq EOM ; 0 = end of string
clc
adc #$c0 ; + 192
sta $400+41,y ; store to screen
iny
bne Loop ; next character
EOM
Wait1
lda $d011
bmi Wait1 ; wait for line < 256
Wait2
lda $d012 ; get current scanline
Wait3
cmp $d012
beq Wait3 ; wait for scanline to change
lsr
lsr
clc
adc Temp
sta $d020 ; set border color
lda $d011 ; get status bits
bpl Wait2 ; repeat until line >= 256
sty $d020 ; reset border color
dec Temp ; scroll colors
jmp Wait1 ; endless loop
Message
; PETSCII - http://sta.c64.org/cbm64pet.html
byte "HELLO`WORLDa"
byte 0

View File

@ -1,6 +1,6 @@
import { RAM, RasterVideo, dumpRAM, AnimationTimer, setKeyboardFromMap, padBytes, ControllerPoller } from "./emu";
import { hex, printFlags, invertMap } from "./util";
import { RAM, RasterVideo, KeyFlags, dumpRAM, AnimationTimer, setKeyboardFromMap, padBytes, ControllerPoller } from "./emu";
import { hex, printFlags, invertMap, getBasePlatform } from "./util";
import { CodeAnalyzer } from "./analysis";
import { Segment } from "./workertypes";
import { disassemble6502 } from "./cpu/disasm6502";
@ -68,7 +68,7 @@ export interface Debuggable {
}
export interface Platform {
start() : void;
start() : void | Promise<void>;
reset() : void;
isRunning() : boolean;
getToolForFilename(s:string) : string;
@ -925,7 +925,7 @@ export function lookupSymbol(platform:Platform, addr:number, extra:boolean) {
/// new Machine platform adapters
import { Bus, Resettable, FrameBased, VideoSource, SampledAudioSource, AcceptsROM, AcceptsKeyInput, SavesState, SavesInputState, HasCPU } from "./devices";
import { Bus, Resettable, FrameBased, VideoSource, SampledAudioSource, AcceptsROM, AcceptsKeyInput, SavesState, SavesInputState, HasCPU, TrapCondition } from "./devices";
import { Probeable, RasterFrameBased, AcceptsPaddleInput } from "./devices";
import { SampledAudio } from "./audio";
import { ProbeRecorder } from "./recorder";
@ -1038,7 +1038,7 @@ export abstract class BaseMachinePlatform<T extends Machine> extends BaseDebugPl
}
isRunning() {
return this.timer.isRunning();
return this.timer && this.timer.isRunning();
}
resume() {
@ -1113,3 +1113,124 @@ export abstract class BaseZ80MachinePlatform<T extends Machine> extends BaseMach
}
}
// WASM Support
export class WASMMachine implements Machine {
prefix : string;
instance : WebAssembly.Instance;
exports : any;
sys : number;
pixel_dest : Uint32Array;
pixel_src : Uint32Array;
romptr : number;
romarr : Uint8Array;
// TODO
cpu = {
getPC() : number {
return 0;
},
getSP() : number {
return 0;
},
isStable() : boolean {
return false;
},
reset() {
},
connectMemoryBus() {
},
saveState() {
},
loadState() {
}
}
constructor(prefix: string) {
this.prefix = prefix;
}
async loadWASM() {
// fetch WASM
var wasmResponse = await fetch('wasm/'+this.prefix+'.wasm');
var wasmBinary = await wasmResponse.arrayBuffer();
var wasmCompiled = await WebAssembly.compile(wasmBinary);
var wasmResult = await WebAssembly.instantiate(wasmCompiled);
this.instance = wasmResult;
this.exports = wasmResult.exports;
this.exports.memory.grow(32);
// fetch BIOS
var biosResponse = await fetch('wasm/'+this.prefix+'.bios');
var biosBinary = await biosResponse.arrayBuffer();
const cBIOSPointer = this.exports.malloc(0x5000);
const srcArray = new Uint8Array(biosBinary);
const destArray = new Uint8Array(this.exports.memory.buffer, cBIOSPointer, 0x5000);
destArray.set(srcArray);
// init machine instance
this.sys = this.exports.machine_init(cBIOSPointer);
console.log('machine_init', this.sys);
}
reset() {
this.exports.machine_reset(this.sys);
}
loadROM(rom: Uint8Array) {
if (!this.romptr) {
this.romptr = this.exports.malloc(0x10000);
this.romarr = new Uint8Array(this.exports.memory.buffer, this.romptr, 0x10000);
}
this.reset();
// this.exports.c64_exec(this.sys, 1000000);
this.romarr.set(rom);
this.exports.machine_load_rom(this.sys, this.romptr, rom.length);
}
advanceFrame(trap: TrapCondition) : number {
if (trap) {
// TODO
} else {
this.exports.c64_exec(this.sys, 16421);
}
this.syncVideo();
return 0; // TODO
}
read(address: number) : number {
return this.exports.machine_mem_read(this.sys, address & 0xffff);
}
readConst(address: number) : number {
return this.exports.machine_mem_read(this.sys, address & 0xffff);
}
write(address: number, value: number) : void {
this.exports.machine_mem_write(this.sys, address & 0xffff, value & 0xff);
}
saveState() : EmuState {
return null;
}
loadState(state: EmuState) : void {
}
saveControlsState() : any {
}
loadControlsState(state) : void {
}
getVideoParams() {
return {width:392, height:272, overscan:true}; // TODO: const
}
connectVideo(pixels:Uint32Array) : void {
this.pixel_dest = pixels;
// save video pointer
var pixbuf = this.exports.machine_get_pixel_buffer(this.sys);
this.pixel_src = new Uint32Array(this.exports.memory.buffer, pixbuf, pixels.length);
console.log(pixbuf, pixels.length);
}
syncVideo() {
if (this.pixel_dest != null) {
this.pixel_dest.set(this.pixel_src);
}
}
setKeyInput(key: number, code: number, flags: number): void {
if (flags & KeyFlags.KeyDown) {
this.exports.machine_key_down(this.sys, key);
} else if (flags & KeyFlags.KeyUp) {
this.exports.machine_key_up(this.sys, key);
}
}
}

View File

@ -1789,7 +1789,7 @@ function installGAHooks() {
}
}
function startPlatform() {
async function startPlatform() {
if (!PLATFORMS[platform_id]) throw Error("Invalid platform '" + platform_id + "'.");
platform = new PLATFORMS[platform_id]($("#emuscreen")[0]);
setPlatformUI();
@ -1814,7 +1814,7 @@ function startPlatform() {
}
// start platform and load file
replaceURLState();
platform.start();
await platform.start();
installGAHooks();
loadBIOSFromProject();
initProject();
@ -1824,7 +1824,6 @@ function startPlatform() {
addPageFocusHandlers();
showInstructions();
revealTopBar();
return true;
}
function revealTopBar() {
@ -1896,7 +1895,7 @@ function setPlatformUI() {
}
// start
export function startUI(loadplatform : boolean) {
export function startUI() {
// import from github?
if (qs['githubURL']) {
importProjectFromGithub(qs['githubURL'], true);
@ -1932,33 +1931,38 @@ export function startUI(loadplatform : boolean) {
return;
}
// load and start platform object
if (loadplatform) {
loadAndStartPlatform();
} else {
startPlatform();
revealTopBar();
}
loadAndStartPlatform();
});
}
function loadAndStartPlatform() {
async function loadAndStartPlatform() {
var platformfn = 'gen/platform/' + platform_id.split(/[.-]/)[0] + '.js'; // required file
var machinefn = platformfn.replace('/platform/', '/machine/'); // optional file
loadScript(platformfn).then( () => {
return loadScript(machinefn).catch(() => { console.log('skipped',machinefn); }); // optional file skipped
}).then( () => {
try {
await loadScript(platformfn); // load platform file
} catch (e) {
console.log(e);
alertError('Platform "' + platform_id + '" not supported.');
return;
}
try {
await loadScript(machinefn); // load machine file
} catch (e) {
console.log('skipped',machinefn); // optional file skipped
}
try {
console.log("starting platform", platform_id); // loaded required <platform_id>.js file
try {
startPlatform();
await startPlatform();
showWelcomeMessage();
document.title = document.title + " [" + platform_id + "] - " + (repo_id?('['+repo_id+'] - '):'') + current_project.mainPath;
} finally {
revealTopBar();
}
}).catch( (e) => {
} catch (e) {
console.log(e);
alertError('Platform "' + platform_id + '" not supported.');
});
alertError('Platform "' + platform_id + '" failed to load.');
}
}
// HTTPS REDIRECT

View File

@ -1,32 +1,61 @@
import { C64 } from "../machine/c64";
import { Platform, Base6502MachinePlatform } from "../common/baseplatform";
import { Platform, WASMMachine, Base6502MachinePlatform, getToolForFilename_6502, getOpcodeMetadata_6502 } from "../common/baseplatform";
import { PLATFORMS } from "../common/emu";
var C64_PRESETS = [
const C64_PRESETS = [
{id:'hello.dasm', name:'Hello World (ASM)'},
];
const C64_MEMORY_MAP = { main:[
{name:'6510 Registers',start:0x0, size:0x2,type:'io'},
{name:'RAM', start:0x2, size:0x7ffe,type:'ram'},
{name:'Cartridge ROM',start:0x8000,size:0x2000,type:'rom'},
{name:'BASIC ROM', start:0xa000,size:0x2000,type:'rom'},
{name:'RAM', start:0xc000,size:0x1000,type:'ram'},
{name:'VIC-II I/O', start:0xd000,size:0x0400,type:'io'},
{name:'Color RAM', start:0xd800,size:0x0400,type:'io'},
{name:'CIA 1', start:0xdc00,size:0x0100,type:'io'},
{name:'CIA 2', start:0xdd00,size:0x0100,type:'io'},
{name:'KERNAL ROM', start:0xe000,size:0x2000,type:'rom'},
] }
class C64Platform extends Base6502MachinePlatform<C64> implements Platform {
newMachine() { return new C64(); }
getPresets() { return C64_PRESETS; }
getDefaultExtension() { return ".c"; };
readAddress(a) { return this.machine.readConst(a); }
loadBios(bios) { this.machine.loadBIOS(bios); }
getMemoryMap() { return { main:[
{name:'6510 Registers',start:0x0, size:0x2,type:'io'},
{name:'RAM', start:0x2, size:0x7ffe,type:'ram'},
{name:'Cartridge ROM',start:0x8000,size:0x2000,type:'rom'},
{name:'BASIC ROM', start:0xa000,size:0x2000,type:'rom'},
{name:'RAM', start:0xc000,size:0x1000,type:'ram'},
{name:'VIC-II I/O', start:0xd000,size:0x0400,type:'io'},
{name:'Color RAM', start:0xd800,size:0x0400,type:'io'},
{name:'CIA 1', start:0xdc00,size:0x0100,type:'io'},
{name:'CIA 2', start:0xdd00,size:0x0100,type:'io'},
{name:'KERNAL ROM', start:0xe000,size:0x2000,type:'rom'},
] } };
loadBios(bios) { this.machine.loadBIOS(bios); }
getMemoryMap() { return C64_MEMORY_MAP; }
}
PLATFORMS['c64'] = C64Platform;
class C64WASMPlatform extends Base6502MachinePlatform<WASMMachine> implements Platform {
newMachine() { return new WASMMachine('c64'); }
async start() {
// TODO: start() needs to block
await this.machine.loadWASM();
super.start();
}
getPresets() { return C64_PRESETS; }
getDefaultExtension() { return ".c"; };
readAddress(a) { return this.machine.readConst(a); }
getMemoryMap() { return C64_MEMORY_MAP; }
}
/*
class C64WASMPlatform extends BaseWASMPlatform implements Platform {
prefix = 'c64';
getPresets() { return C64_PRESETS; }
getToolForFilename = getToolForFilename_6502;
getOpcodeMetadata = getOpcodeMetadata_6502;
getDefaultExtension() { return ".c"; };
}
*/
PLATFORMS['c64'] = C64Platform;
PLATFORMS['c64.wasm'] = C64WASMPlatform;

BIN
wasm/c64.bios Normal file

Binary file not shown.

BIN
wasm/c64.wasm Executable file

Binary file not shown.