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`)
|
with Z88DK (target `+sms`)
|
||||||
- [Viciious](https://github.com/compiler-explorer/viciious) (https://static.ce-cdn.net/viciious/viciious.html) - for
|
- [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`)
|
`.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
|
## Examples
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,10 @@ export class z88dkCompiler extends BaseCompiler {
|
|||||||
return `${this.outputFilebase}.sms`;
|
return `${this.outputFilebase}.sms`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getGbfilename() {
|
||||||
|
return `${this.outputFilebase}.gb`;
|
||||||
|
}
|
||||||
|
|
||||||
override async objdump(
|
override async objdump(
|
||||||
outputFilename: string,
|
outputFilename: string,
|
||||||
result: any,
|
result: any,
|
||||||
@@ -189,6 +193,11 @@ export class z88dkCompiler extends BaseCompiler {
|
|||||||
if (await utils.fileExists(smsFilepath)) {
|
if (await utils.fileExists(smsFilepath)) {
|
||||||
await addArtifactToResult(result, smsFilepath, ArtifactType.smsrom);
|
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;
|
return result;
|
||||||
|
|||||||
@@ -1782,6 +1782,8 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
|||||||
this.emulateC64Prg(artifact);
|
this.emulateC64Prg(artifact);
|
||||||
} else if (artifact.type === ArtifactType.heaptracktxt) {
|
} else if (artifact.type === ArtifactType.heaptracktxt) {
|
||||||
this.offerViewInSpeedscope(artifact);
|
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 +
|
tmstr +
|
||||||
'#customFilename=' +
|
'#customFilename=' +
|
||||||
artifact.name +
|
encodeURIComponent(artifact.name) +
|
||||||
'&b64data=' +
|
'&b64data=' +
|
||||||
artifact.content;
|
encodeURIComponent(artifact.content);
|
||||||
window.open(speedscope_url);
|
window.open(speedscope_url);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -1876,7 +1878,11 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
|||||||
if ('contentWindow' in miracleMenuFrame) {
|
if ('contentWindow' in miracleMenuFrame) {
|
||||||
const emuwindow = unwrap(miracleMenuFrame.contentWindow);
|
const emuwindow = unwrap(miracleMenuFrame.contentWindow);
|
||||||
const tmstr = Date.now();
|
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 emuwindow = unwrap(speccyemuframe.contentWindow);
|
||||||
const tmstr = Date.now();
|
const tmstr = Date.now();
|
||||||
emuwindow.location =
|
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 emuwindow = unwrap(jsbeebemuframe.contentWindow);
|
||||||
const tmstr = Date.now();
|
const tmstr = Date.now();
|
||||||
emuwindow.location =
|
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 emuwindow = unwrap(jsnesemuframe.contentWindow);
|
||||||
const tmstr = Date.now();
|
const tmstr = Date.now();
|
||||||
emuwindow.location =
|
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?' +
|
'https://static.ce-cdn.net/viciious/viciious.html?' +
|
||||||
tmstr +
|
tmstr +
|
||||||
'#filename=' +
|
'#filename=' +
|
||||||
prg.title +
|
encodeURIComponent(prg.title) +
|
||||||
'&b64c64=' +
|
'&b64c64=' +
|
||||||
prg.content;
|
encodeURIComponent(prg.content);
|
||||||
|
|
||||||
window.open(url, '_blank');
|
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 {
|
onEditorChange(editor: number, source: string, langId: string, compilerId?: number): void {
|
||||||
if (this.sourceTreeId) {
|
if (this.sourceTreeId) {
|
||||||
const tree = this.hub.getTreeById(this.sourceTreeId);
|
const tree = this.hub.getTreeById(this.sourceTreeId);
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ export enum ArtifactType {
|
|||||||
timetrace = 'timetracejson',
|
timetrace = 'timetracejson',
|
||||||
c64prg = 'c64prg',
|
c64prg = 'c64prg',
|
||||||
heaptracktxt = 'heaptracktxt',
|
heaptracktxt = 'heaptracktxt',
|
||||||
|
gbrom = 'gbrom',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Artifact = {
|
export type Artifact = {
|
||||||
|
|||||||
@@ -36,3 +36,5 @@ include jsspeccyemu
|
|||||||
include miracleemu
|
include miracleemu
|
||||||
|
|
||||||
include jsnesemu
|
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