1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-05 02:29:31 +00:00

c64: more work on WASMMachine; use more await for ui

This commit is contained in:
Steven Hugg 2019-12-18 11:20:15 -06:00
parent 7d6e910e57
commit 4a1ac1bbac
5 changed files with 184 additions and 88 deletions

View File

@ -925,8 +925,8 @@ export function lookupSymbol(platform:Platform, addr:number, extra:boolean) {
/// new Machine platform adapters
import { Bus, Resettable, FrameBased, VideoSource, SampledAudioSource, AcceptsROM, AcceptsKeyInput, SavesState, SavesInputState, HasCPU, TrapCondition } from "./devices";
import { Probeable, RasterFrameBased, AcceptsPaddleInput } from "./devices";
import { Bus, Resettable, FrameBased, VideoSource, SampledAudioSource, AcceptsROM, AcceptsKeyInput, SavesState, SavesInputState, HasCPU, TrapCondition, CPU } from "./devices";
import { Probeable, RasterFrameBased, AcceptsPaddleInput, SampledAudioSink } from "./devices";
import { SampledAudio } from "./audio";
import { ProbeRecorder } from "./recorder";
@ -986,7 +986,7 @@ export abstract class BaseMachinePlatform<T extends Machine> extends BaseDebugPl
start() {
const m = this.machine;
this.timer = new AnimationTimer(60, this.nextFrame.bind(this));
var videoFrequency;
if (hasVideo(m)) {
var vp = m.getVideoParams();
this.video = new RasterVideo(this.mainElement, vp.width, vp.height, {overscan:!!vp.overscan,rotate:vp.rotate|0});
@ -997,7 +997,9 @@ export abstract class BaseMachinePlatform<T extends Machine> extends BaseDebugPl
this.video.setKeyboardEvents(m.setKeyInput.bind(m));
this.poller = new ControllerPoller(m.setKeyInput.bind(m));
}
videoFrequency = vp.videoFrequency;
}
this.timer = new AnimationTimer(videoFrequency || 60, this.nextFrame.bind(this));
if (hasAudio(m)) {
var ap = m.getAudioParams();
this.audio = new SampledAudio(ap.sampleRate);
@ -1125,31 +1127,36 @@ export class WASMMachine implements Machine {
pixel_dest : Uint32Array;
pixel_src : Uint32Array;
romptr : number;
romlen : number;
romarr : Uint8Array;
// TODO
cpu = {
getPC() : number {
return 0;
},
getSP() : number {
return 0;
},
isStable() : boolean {
return false;
},
reset() {
},
connectMemoryBus() {
},
saveState() {
},
loadState() {
}
}
stateptr : number;
statearr : Uint8Array;
cpu : CPU;
audio : SampledAudioSink;
audioarr : Float32Array;
prgstart : number;
initstring : string;
initindex : number;
constructor(prefix: string) {
this.prefix = prefix;
var self = this;
this.cpu = {
getPC: self.getPC.bind(self),
getSP: self.getSP.bind(self),
isStable: self.isStable.bind(self),
reset: self.reset.bind(self),
saveState: () => {
self.exports.machine_save_state(self.sys, self.stateptr);
return self.getCPUState();
},
loadState: () => {
console.log("loadState not implemented")
},
connectMemoryBus() {
console.log("connectMemoryBus not implemented")
},
}
}
async loadWASM() {
// fetch WASM
@ -1170,28 +1177,71 @@ export class WASMMachine implements Machine {
// init machine instance
this.sys = this.exports.machine_init(cBIOSPointer);
console.log('machine_init', this.sys);
// create state buffer
var statesize = this.exports.machine_get_state_size();
this.stateptr = this.exports.malloc(statesize);
this.statearr = new Uint8Array(this.exports.memory.buffer, this.stateptr, statesize);
// create audio buffer
var sampbufsize = 4096*4;
this.audioarr = new Float32Array(this.exports.memory.buffer, this.exports.machine_get_sample_buffer(), sampbufsize);
}
reset() {
this.exports.machine_reset(this.sys);
// load rom
if (this.romptr && this.romlen) {
this.exports.machine_load_rom(this.sys, this.romptr, this.romlen);
this.prgstart = this.romarr[0] + (this.romarr[1]<<8); // TODO: get starting address
if (this.prgstart == 0x801) this.prgstart = 0x80d;
}
// set init string
if (this.prgstart) {
this.initstring = "\r\r\r\r\r\r\rSYS " + this.prgstart + "\r";
this.initindex = 0;
}
}
getPC() : number {
return this.exports.machine_cpu_get_pc(this.sys);
}
getSP() : number {
return this.exports.machine_cpu_get_sp(this.sys);
}
isStable() : boolean {
return this.exports.machine_cpu_is_stable(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);
this.romlen = rom.length;
this.reset();
}
advanceFrame(trap: TrapCondition) : number {
var i : number;
var cpf = 19656; // TODO: pal, const
if (trap) {
// TODO
for (i=0; i<cpf; i++) {
if (trap && trap()) {
break;
}
this.exports.machine_tick(this.sys);
}
} else {
this.exports.c64_exec(this.sys, 16421);
this.exports.machine_exec(this.sys, cpf);
i = cpf;
this.typeInitString(); // TODO: type init string into console (doesnt work on reset)
}
this.syncVideo();
return 0; // TODO
this.syncAudio();
return i;
}
typeInitString() {
if (this.initstring) {
var ch = this.initstring.charCodeAt(this.initindex >> 1);
this.setKeyInput(ch, 0, (this.initindex&1) ? KeyFlags.KeyUp : KeyFlags.KeyDown);
this.initindex++;
}
}
read(address: number) : number {
return this.exports.machine_mem_read(this.sys, address & 0xffff);
@ -1202,17 +1252,54 @@ export class WASMMachine implements Machine {
write(address: number, value: number) : void {
this.exports.machine_mem_write(this.sys, address & 0xffff, value & 0xff);
}
saveState() : EmuState {
return null;
getCPUState() {
return {
PC:this.getPC(),
SP:this.getSP(),
A:this.statearr[14],
X:this.statearr[15],
Y:this.statearr[16],
S:this.statearr[17],
flags:this.statearr[18],
C:this.statearr[18] & 1,
Z:this.statearr[18] & 2,
I:this.statearr[18] & 4,
D:this.statearr[18] & 8,
V:this.statearr[18] & 64,
N:this.statearr[18] & 128,
}
}
loadState(state: EmuState) : void {
/*
setPC(pc: number) {
this.exports.machine_save_state(this.sys, this.stateptr);
this.statearr[10] = pc & 0xff;
this.statearr[11] = pc >> 8;
this.exports.machine_load_state(this.sys, this.stateptr);
}
*/
saveState() {
this.exports.machine_save_state(this.sys, this.stateptr);
// TODO: take out CPU state, memory
return {
c:this.getCPUState(),
state:this.statearr.slice(0)
};
}
loadState(state) : void {
this.statearr.set(state.state);
this.exports.machine_load_state(this.sys, this.stateptr);
}
saveControlsState() : any {
// TODO
}
loadControlsState(state) : void {
// TODO
}
getVideoParams() {
return {width:392, height:272, overscan:true}; // TODO: const
return {width:392, height:272, overscan:true, videoFrequency:50}; // TODO: const
}
getAudioParams() {
return {sampleRate:44100, stereo:false};
}
connectVideo(pixels:Uint32Array) : void {
this.pixel_dest = pixels;
@ -1227,10 +1314,25 @@ export class WASMMachine implements Machine {
}
}
setKeyInput(key: number, code: number, flags: number): void {
// TODO: handle shifted keys
if (key == 16 || key == 17 || key == 18 || key == 224) return; // meta keys
//console.log(key, code, flags);
//if (flags & KeyFlags.Shift) { key += 64; }
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);
}
}
connectAudio(audio : SampledAudioSink) : void {
this.audio = audio;
}
syncAudio() {
if (this.audio != null) {
var n = this.exports.machine_get_sample_count();
for (var i=0; i<n; i++) {
this.audio.feedSample(this.audioarr[i], 1);
}
}
}
}

View File

@ -39,6 +39,7 @@ export interface VideoParams {
height : number;
overscan? : boolean;
rotate? : number;
videoFrequency? : number; // default = 60
}
// TODO: frame buffer optimization (apple2, etc)

View File

@ -299,30 +299,28 @@ function loadMainWindow(preset_id:string) {
current_project.setMainFile(preset_id);
}
function loadProject(preset_id:string) {
async function loadProject(preset_id:string) {
// set current file ID
// TODO: this is done twice
current_project.mainPath = preset_id;
setLastPreset(preset_id);
// load files from storage or web URLs
current_project.loadFiles([preset_id]).then((result) => {
measureTimeLoad = new Date(); // for timing calc.
if (result && result.length) {
// file found; continue
loadMainWindow(preset_id);
} else {
getSkeletonFile(preset_id).then((skel) => {
current_project.filedata[preset_id] = skel || "\n";
loadMainWindow(preset_id);
// don't alert if we selected "new file"
if (!qs['newfile']) {
alertInfo("Could not find file \"" + preset_id + "\". Loading default file.");
}
delete qs['newfile'];
replaceURLState();
});
var result = await current_project.loadFiles([preset_id]);
measureTimeLoad = new Date(); // for timing calc.
if (result && result.length) {
// file found; continue
loadMainWindow(preset_id);
} else {
var skel = await getSkeletonFile(preset_id);
current_project.filedata[preset_id] = skel || "\n";
loadMainWindow(preset_id);
// don't alert if we selected "new file"
if (!qs['newfile']) {
alertInfo("Could not find file \"" + preset_id + "\". Loading default file.");
}
});
delete qs['newfile'];
replaceURLState();
}
}
function reloadProject(id:string) {
@ -932,21 +930,19 @@ function populateRepos(sel) {
}
}
function populateFiles(sel:JQuery, category:string, prefix:string, foundFiles:{}, callback:() => void) {
store.keys().then( (keys:string[]) => {
var numFound = 0;
if (!keys) keys = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (key.startsWith(prefix) && !foundFiles[key]) {
if (numFound++ == 0)
sel.append($("<option />").text("------- " + category + " -------").attr('disabled','true'));
var name = key.substring(prefix.length);
sel.append($("<option />").val(key).text(name).attr('selected',(key==current_project.mainPath)?'selected':null));
}
async function populateFiles(sel:JQuery, category:string, prefix:string, foundFiles:{}) {
var keys = await store.keys();
var numFound = 0;
if (!keys) keys = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (key.startsWith(prefix) && !foundFiles[key]) {
if (numFound++ == 0)
sel.append($("<option />").text("------- " + category + " -------").attr('disabled','true'));
var name = key.substring(prefix.length);
sel.append($("<option />").val(key).text(name).attr('selected',(key==current_project.mainPath)?'selected':null));
}
if (callback) { callback(); }
});
}
}
function finishSelector(sel) {
@ -958,21 +954,19 @@ function finishSelector(sel) {
}
}
function updateSelector() {
async function updateSelector() {
var sel = $("#preset_select").empty();
if (!repo_id) {
// normal: populate repos, examples, and local files
populateRepos(sel);
var foundFiles = populateExamples(sel);
populateFiles(sel, "Local Files", "", foundFiles, () => {
finishSelector(sel);
});
await populateFiles(sel, "Local Files", "", foundFiles);
finishSelector(sel);
} else {
sel.append($("<option />").val('/').text('Leave Repository'));
// repo: populate all files
populateFiles(sel, repo_id, "", {}, () => {
finishSelector(sel);
});
await populateFiles(sel, repo_id, "", {});
finishSelector(sel);
}
// set click handlers
sel.off('change').change(function(e) {
@ -1037,15 +1031,16 @@ function setCompileOutput(data: WorkerResult) {
}
}
function loadBIOSFromProject() {
async function loadBIOSFromProject() {
if (platform.loadBIOS) {
var biospath = platform_id + '.rom';
store.getItem(biospath).then( (biosdata) => {
if (biosdata instanceof Uint8Array) {
console.log('loading BIOS')
platform.loadBIOS('BIOS', biosdata);
}
});
var biosdata = await store.getItem(biospath);
if (biosdata instanceof Uint8Array) {
console.log('loading BIOS')
platform.loadBIOS('BIOS', biosdata);
} else {
console.log('BIOS file must be binary')
}
}
}
@ -1815,14 +1810,14 @@ async function startPlatform() {
// start platform and load file
replaceURLState();
await platform.start();
installGAHooks();
loadBIOSFromProject();
initProject();
loadProject(qs['file']);
await loadBIOSFromProject();
await initProject();
await loadProject(qs['file']);
setupDebugControls();
updateSelector();
addPageFocusHandlers();
showInstructions();
installGAHooks();
revealTopBar();
}

View File

@ -190,7 +190,7 @@ var PLATFORM_PARAMS = {
'apple2': {
define: '__APPLE2__',
cfgfile: 'apple2-hgr.cfg',
libargs: ['apple2.lib'],
libargs: [ '--lib-path', '/share/target/apple2/drv', '-D', '__EXEHDR__=0', 'apple2.lib'],
__CODE_RUN__: 16384,
code_start: 0x803,
},
@ -241,7 +241,7 @@ var PLATFORM_PARAMS = {
},
'c64': {
define: '__C64__',
cfgfile: 'c64.cfg', // SYS 2058
cfgfile: 'c64.cfg', // SYS 2061
libargs: ['c64.lib'],
//extra_link_files: ['c64-cart.cfg'],
},
@ -952,8 +952,6 @@ function linkLD65(step:BuildStep) {
var cfgfile = params.cfgfile;
var args = ['--cfg-path', '/share/cfg',
'--lib-path', '/share/lib',
'--lib-path', '/share/target/apple2/drv', // TODO
'-D', '__EXEHDR__=0', // TODO
'-C', cfgfile,
'-Ln', 'main.vice',
//'--dbgfile', 'main.dbg', // TODO: get proper line numbers

Binary file not shown.