mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 10:33:59 -05:00
Add Game Boy emulator support using WasmBoy (#7717)
This commit is contained in:
@@ -13,6 +13,7 @@ These are using Javascript and/or using external websites to facilitate emulatio
|
||||
with Z88DK (target `+sms`)
|
||||
- [Viciious](https://github.com/compiler-explorer/viciious) (https://static.ce-cdn.net/viciious/viciious.html) - for
|
||||
`.prg` files built with LLVM MOS C64 or CC65 (`--target c64`)
|
||||
- [WasmBoy](https://github.com/compiler-explorer/wasmboy) (https://static.ce-cdn.net/wasmboy/index.html) - for `.gb` ROM files built with z88dk (target `+gb`)
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -129,6 +129,10 @@ export class z88dkCompiler extends BaseCompiler {
|
||||
return `${this.outputFilebase}.sms`;
|
||||
}
|
||||
|
||||
getGbfilename() {
|
||||
return `${this.outputFilebase}.gb`;
|
||||
}
|
||||
|
||||
override async objdump(
|
||||
outputFilename: string,
|
||||
result: any,
|
||||
@@ -189,6 +193,11 @@ export class z88dkCompiler extends BaseCompiler {
|
||||
if (await utils.fileExists(smsFilepath)) {
|
||||
await addArtifactToResult(result, smsFilepath, ArtifactType.smsrom);
|
||||
}
|
||||
|
||||
const gbFilepath = path.join(result.dirPath, this.getGbfilename());
|
||||
if (await utils.fileExists(gbFilepath)) {
|
||||
await addArtifactToResult(result, gbFilepath, ArtifactType.gbrom);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1782,6 +1782,8 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
this.emulateC64Prg(artifact);
|
||||
} else if (artifact.type === ArtifactType.heaptracktxt) {
|
||||
this.offerViewInSpeedscope(artifact);
|
||||
} else if (artifact.type === ArtifactType.gbrom) {
|
||||
this.emulateGameBoyROM(artifact);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1807,9 +1809,9 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
'?' +
|
||||
tmstr +
|
||||
'#customFilename=' +
|
||||
artifact.name +
|
||||
encodeURIComponent(artifact.name) +
|
||||
'&b64data=' +
|
||||
artifact.content;
|
||||
encodeURIComponent(artifact.content);
|
||||
window.open(speedscope_url);
|
||||
});
|
||||
},
|
||||
@@ -1876,7 +1878,11 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
if ('contentWindow' in miracleMenuFrame) {
|
||||
const emuwindow = unwrap(miracleMenuFrame.contentWindow);
|
||||
const tmstr = Date.now();
|
||||
emuwindow.location = 'https://xania.org/miracle/miracle.html?' + tmstr + '#b64sms=' + image;
|
||||
emuwindow.location =
|
||||
'https://xania.org/miracle/miracle.html?' +
|
||||
tmstr +
|
||||
'#b64sms=' +
|
||||
encodeURIComponent(image);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -1905,7 +1911,10 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
const emuwindow = unwrap(speccyemuframe.contentWindow);
|
||||
const tmstr = Date.now();
|
||||
emuwindow.location =
|
||||
'https://static.ce-cdn.net/jsspeccy/index.html?' + tmstr + '#b64tape=' + image;
|
||||
'https://static.ce-cdn.net/jsspeccy/index.html?' +
|
||||
tmstr +
|
||||
'#b64tape=' +
|
||||
encodeURIComponent(image);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -1932,7 +1941,10 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
const emuwindow = unwrap(jsbeebemuframe.contentWindow);
|
||||
const tmstr = Date.now();
|
||||
emuwindow.location =
|
||||
'https://bbc.godbolt.org/?' + tmstr + '#embed&autoboot&disc1=b64data:' + bbcdiskimage;
|
||||
'https://bbc.godbolt.org/?' +
|
||||
tmstr +
|
||||
'#embed&autoboot&disc1=b64data:' +
|
||||
encodeURIComponent(bbcdiskimage);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -1959,7 +1971,10 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
const emuwindow = unwrap(jsnesemuframe.contentWindow);
|
||||
const tmstr = Date.now();
|
||||
emuwindow.location =
|
||||
'https://static.ce-cdn.net/jsnes-ceweb/index.html?' + tmstr + '#b64nes=' + nesrom;
|
||||
'https://static.ce-cdn.net/jsnes-ceweb/index.html?' +
|
||||
tmstr +
|
||||
'#b64nes=' +
|
||||
encodeURIComponent(nesrom);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -1981,9 +1996,9 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
'https://static.ce-cdn.net/viciious/viciious.html?' +
|
||||
tmstr +
|
||||
'#filename=' +
|
||||
prg.title +
|
||||
encodeURIComponent(prg.title) +
|
||||
'&b64c64=' +
|
||||
prg.content;
|
||||
encodeURIComponent(prg.content);
|
||||
|
||||
window.open(url, '_blank');
|
||||
});
|
||||
@@ -1992,6 +2007,52 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
);
|
||||
}
|
||||
|
||||
emulateGameBoyROM(prg: Artifact): void {
|
||||
const dialog = $('#gbemu');
|
||||
|
||||
this.alertSystem.notify(
|
||||
'Click <a target="_blank" id="emulink" style="cursor:pointer;" click="javascript:;">here</a> to emulate with a debugger, ' +
|
||||
'or <a target="_blank" id="emulink-play" style="cursor:pointer;" click="javascript:;">here</a> to emulate just to play.',
|
||||
{
|
||||
group: 'emulation',
|
||||
collapseSimilar: true,
|
||||
dismissTime: 10000,
|
||||
onBeforeShow: elem => {
|
||||
elem.find('#emulink').on('click', () => {
|
||||
const tmstr = Date.now();
|
||||
const url =
|
||||
'https://static.ce-cdn.net/wasmboy/index.html?' +
|
||||
tmstr +
|
||||
'#rom-name=' +
|
||||
encodeURIComponent(prg.title) +
|
||||
'&rom-data=' +
|
||||
encodeURIComponent(prg.content);
|
||||
window.open(url, '_blank');
|
||||
});
|
||||
|
||||
elem.find('#emulink-play').on('click', () => {
|
||||
BootstrapUtils.showModal(dialog);
|
||||
|
||||
const gbemuframe = dialog.find('#gbemuframe')[0];
|
||||
assert(gbemuframe instanceof HTMLIFrameElement);
|
||||
if ('contentWindow' in gbemuframe) {
|
||||
const emuwindow = unwrap(gbemuframe.contentWindow);
|
||||
const tmstr = Date.now();
|
||||
const url =
|
||||
'https://static.ce-cdn.net/wasmboy/iframe/index.html?' +
|
||||
tmstr +
|
||||
'#rom-name=' +
|
||||
encodeURIComponent(prg.title) +
|
||||
'&rom-data=' +
|
||||
encodeURIComponent(prg.content);
|
||||
emuwindow.location = url;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
onEditorChange(editor: number, source: string, langId: string, compilerId?: number): void {
|
||||
if (this.sourceTreeId) {
|
||||
const tree = this.hub.getTreeById(this.sourceTreeId);
|
||||
|
||||
@@ -59,6 +59,7 @@ export enum ArtifactType {
|
||||
timetrace = 'timetracejson',
|
||||
c64prg = 'c64prg',
|
||||
heaptracktxt = 'heaptracktxt',
|
||||
gbrom = 'gbrom',
|
||||
}
|
||||
|
||||
export type Artifact = {
|
||||
|
||||
@@ -36,3 +36,5 @@ include jsspeccyemu
|
||||
include miracleemu
|
||||
|
||||
include jsnesemu
|
||||
|
||||
include gbemu
|
||||
|
||||
5
views/popups/gbemu.pug
Normal file
5
views/popups/gbemu.pug
Normal file
@@ -0,0 +1,5 @@
|
||||
#gbemu.modal.fade.gl_keep(tabindex="-1" role="dialog")
|
||||
.modal-dialog.modal-xl
|
||||
.modal-content
|
||||
.modal-body
|
||||
iframe#gbemuframe(src="about:blank" width="670" height="560")
|
||||
Reference in New Issue
Block a user