mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-04-05 11:38:54 +00:00
Deploying to gh-pages from @ sehugg/8bitworkshop@3bacf50409 🚀
This commit is contained in:
parent
29255740fa
commit
d1024c06c6
File diff suppressed because one or more lines are too long
14
gen/c64-5MCMD5YC.js
Normal file
14
gen/c64-5MCMD5YC.js
Normal file
@ -0,0 +1,14 @@
|
||||
import{a as M}from"./chunk-PQDZBFBB.js";import{B as S,I as _,r as g,y as b}from"./chunk-HB3LWF25.js";import{J as n,O as a,U as p,a as l,g as o,u as x}from"./chunk-ATS7PSQG.js";import"./chunk-5XVCUSSZ.js";var f=class extends g{constructor(){super(...arguments);this.numTotalScanlines=312;this.cpuCyclesPerLine=63;this.joymask0=0;this.joymask1=0;this.lightpen_x=0;this.lightpen_y=0}loadBIOS(e){var s=59940-57344+12288;e[s]=96,super.loadBIOS(e)}reset(){super.reset();for(var e=0;e<128;e++)this.exports.machine_key_up(this.sys,e);if(this.romptr&&this.romlen){if(this.exports.machine_load_rom(this.sys,this.romptr,this.romlen),this.prgstart=this.romarr[0]+(this.romarr[1]<<8),this.prgstart==2049)if(this.romarr[6]==158){for(var s=0,t=0;t<5;t++){var e=this.romarr[7+t];if(e==155||e==0)break;s=s*10+(e&15)}this.prgstart=s,console.log("SYS",s,o(s))}else this.prgstart=this.romarr[2]+(this.romarr[3]<<8)+2,console.log("RUN",this.prgstart,o(this.prgstart));if(this.prgstart<32768){this.exports.machine_exec(this.sys,25e4);for(var i="\rSYS "+this.prgstart,t=0;t<i.length;t++){var r=i.charCodeAt(t);this.exports.machine_exec(this.sys,3e4),this.exports.machine_key_down(this.sys,r),this.exports.machine_exec(this.sys,3e4),this.exports.machine_key_up(this.sys,r),this.exports.machine_exec(this.sys,1)}this.exports.machine_key_down(this.sys,13),this.exports.machine_exec(this.sys,1);for(var t=0;t<1e5&&this.getPC()!=this.prgstart;t++)this.exports.machine_tick(this.sys)}else{this.exports.machine_exec(this.sys,100);for(var c=this.romarr[4]+this.romarr[5]*256,t=0;t<15e4&&this.getPC()!=c;t++)this.exports.machine_tick(this.sys)}}}advanceFrame(e){var s=this.getRasterY(),t=Math.floor((this.numTotalScanlines-s)*19656/this.numTotalScanlines),i=this.probe!=null;return i&&this.exports.machine_reset_probe_buffer(),t=super.advanceFrameClock(e,t),i&&this.copyProbeData(),t}getCPUState(){this.exports.machine_save_cpu_state(this.sys,this.cpustateptr);var e=this.cpustatearr,s=e[2]+(e[3]<<8);return{PC:s,SP:e[9],A:e[6],X:e[7],Y:e[8],C:e[10]&1,Z:e[10]&2,I:e[10]&4,D:e[10]&8,V:e[10]&64,N:e[10]&128,o:this.readConst(s),R:e[19]!=55}}saveState(){this.exports.machine_save_state(this.sys,this.stateptr);let e=this.getDebugStateOffset(1),s=this.getDebugStateOffset(2),t=this.getDebugStateOffset(3),i=this.getDebugStateOffset(4),r=this.getDebugStateOffset(5),c=this.getDebugStateOffset(9);return{c:this.getCPUState(),state:this.statearr.slice(0),ram:this.statearr.slice(r,r+65536),cia1:this.statearr.slice(e,e+64),cia2:this.statearr.slice(s,s+64),vic:this.statearr.slice(t+1,t+1+64),sid:this.statearr.slice(i,i+32),pla:this.statearr.slice(c,c+16)}}loadState(e){this.statearr.set(e.state),this.exports.machine_load_state(this.sys,this.stateptr)}getVideoParams(){return{width:392,height:272,overscan:!0,videoFrequency:50,aspect:392/272*.9365}}setKeyInput(e,s,t){if(!(e==16||e==17||e==18||e==224)){var i=0,r=0;switch(e){case 32:i=16;break;case 37:e=8,i=4;break;case 38:e=11,i=1;break;case 39:e=9,i=8;break;case 40:e=10,i=2;break;case 113:e=241;break;case 115:e=243;break;case 119:e=245;break;case 121:e=247;break;case 188:e=t&a.Shift?60:46;break;case 190:e=t&a.Shift?62:44;break;case 191:e=t&a.Shift?63:47;break;case 222:e=t&a.Shift?34:39;break;case 219:e=t&a.Shift?123:91;break;case 221:e=t&a.Shift?125:93;break;case 48:t&a.Shift&&(e=41);break;case 49:t&a.Shift&&(e=33);break;case 50:t&a.Shift&&(e=64);break;case 51:t&a.Shift&&(e=35);break;case 52:t&a.Shift&&(e=36);break;case 53:t&a.Shift&&(e=37);break;case 54:t&a.Shift&&(e=94);break;case 55:t&a.Shift&&(e=38);break;case 56:t&a.Shift&&(e=42);break;case 57:t&a.Shift&&(e=40);break;case 59:t&a.Shift&&(e=58);break;case 61:t&a.Shift&&(e=43);break;case 173:e=t&a.Shift?95:45;break}t&a.KeyDown?(this.exports.machine_key_down(this.sys,e),this.joymask0|=i,this.joymask1|=r):t&a.KeyUp&&(this.exports.machine_key_up(this.sys,e),this.joymask0&=~i,this.joymask1&=~r),this.exports.c64_joystick(this.sys,this.joymask0,this.joymask1)}}getRasterY(){return this.exports.machine_get_raster_line(this.sys)}getDebugStateOffset(e){var s=this.exports.machine_get_debug_pointer(this.sys,e);return s-this.sys}getDebugCategories(){return["CPU","ZPRAM","Stack","PLA","CIA","VIC","SID"]}getDebugInfo(e,s){switch(e){case"PLA":{let t="",i=s.pla[0],r=s.pla[3];return t+=`$0000 - $9FFF RAM
|
||||
`,t+=`$A000 - $BFFF ${(r&3)==3?"BASIC ROM":"RAM"}
|
||||
`,t+=`$C000 - $CFFF RAM
|
||||
`,t+=`$D000 - $DFFF ${i?"I/O":(r&3)!=0?"CHAR ROM":"RAM"}
|
||||
`,t+=`$E000 - $FFFF ${(r&2)==2?"KERNAL ROM":"RAM"}
|
||||
`,t}case"CIA":{let t="";for(let i=0;i<2;i++){let r=i?s.cia2:s.cia1;t+=`CIA ${i+1}
|
||||
`,t+=` A: Data ${o(r[0])} DDR ${o(r[1])} Input ${o(r[2])}`,t+=` Timer ${o(r[10]+r[11]*256,4)}
|
||||
`,t+=` B: Data ${o(r[4])} DDR ${o(r[5])} Input ${o(r[6])}`,t+=` Timer ${o(r[10+10]+r[11+10]*256,4)}
|
||||
`}return t}case"VIC":{let t=s.vic,i="",r=(s.cia2[0]&3^3)*16384,c=r+(s.vic[24]&14)*1024,m=r+(s.vic[24]>>4)*1024,h=s.vic[17]&32,A=(s.cia2[0]&1)==1&&(s.vic[24]&12)==4,R=s.state[244],$=this.getRasterY();return i+="Mode:",s.vic[17]&32?i+=" BITMAP":i+=" CHAR",s.vic[22]&16&&(i+=" MULTICOLOR"),s.vic[17]&64&&(i+=" EXTENDED"),i+=`
|
||||
`,i+=`Raster: (${l(R,3)}, ${l($,3)}) `,i+=`Scroll: (${s.vic[22]&7}, ${s.vic[17]&7})`,i+=`
|
||||
`,i+=`VIC Bank: $${o(r,4)} Scrn: $${o(m,4)} `,h?i+=`Bitmap: $${o(c&57344,4)}`:A?i+=`Char: ROM $${o(c,4)}`:i+=`Char: $${o(c,4)}`,i+=`
|
||||
`,i+=p(t,53248,64),i}case"SID":{let t=s.sid,i="";return i+=p(t,54272,32),i}}}setPaddleInput(e,s){e==0&&(this.lightpen_x=s),e==1&&(this.lightpen_y=s);let t=22,i=36,r=228,c=220,m=x(0,255,(this.lightpen_x-t)/(r-t)*160+24),h=x(0,255,(this.lightpen_y-i)/(c-i)*200+50);this.exports.machine_set_mouse(this.sys,m,h)}};var v=[{id:"hello.dasm",name:"Hello World (ASM)"},{id:"23matches.c",name:"23 Matches"},{id:"tgidemo.c",name:"TGI Graphics Demo"},{id:"upandaway.c",name:"Up, Up and Away"},{id:"siegegame.c",name:"Siege Game"},{id:"joymove.c",name:"Sprite Movement"},{id:"sprite_collision.c",name:"Sprite Collision"},{id:"scroll1.c",name:"Scrolling (Single Buffer)"},{id:"scroll2.c",name:"Scrolling (Double Buffer)"},{id:"scroll3.c",name:"Scrolling (Multidirectional)"},{id:"scroll4.c",name:"Scrolling (Color RAM Buffering)"},{id:"scroll5.c",name:"Scrolling (Camera Following)"},{id:"side_scroller.c",name:"Side-Scrolling Game"},{id:"fullscrollgame.c",name:"Full-Scrolling Game"},{id:"test_multiplex.c",name:"Sprite Retriggering"},{id:"test_multispritelib.c",name:"Sprite Multiplexing Library"},{id:"scrolling_text.c",name:"Big Scrolling Text"},{id:"mcbitmap.c",name:"Multicolor Bitmap Mode"},{id:"musicplayer.c",name:"Music Player"},{id:"siddemo.c",name:"SID Player Demo"},{id:"climber.c",name:"Climber Game"}],y={main:[{name:"6510 Registers",start:0,size:2,type:"io"},{name:"BIOS Reserved",start:512,size:167},{name:"Default Screen RAM",start:1024,size:1024,type:"ram"},{name:"Cartridge ROM",start:32768,size:8192,type:"rom"},{name:"BASIC ROM",start:40960,size:8192,type:"rom"},{name:"Upper RAM",start:49152,size:4096,type:"ram"},{name:"Character ROM",start:53248,size:4096,type:"rom"},{name:"VIC-II I/O",start:53248,size:1024,type:"io"},{name:"SID",start:54272,size:1024,type:"io"},{name:"Color RAM",start:55296,size:1024,type:"io"},{name:"CIA 1",start:56320,size:256,type:"io"},{name:"CIA 2",start:56576,size:256,type:"io"},{name:"I/O 1",start:56832,size:256,type:"io"},{name:"I/O 2",start:57088,size:256,type:"io"},{name:"KERNAL ROM",start:57344,size:8192,type:"rom"}]},d=class extends _{newMachine(){return new f("c64")}getPresets(){return v}getDefaultExtension(){return".c"}readAddress(e){return this.machine.readConst(e)}getMemoryMap(){return y}showHelp(){return"https://8bitworkshop.com/docs/platforms/c64/"}getROMExtension(e){return e&&e[0]==1&&e[1]==8?".prg":".bin"}},C=class extends M{constructor(){super(...arguments);this.getToolForFilename=b;this.getOpcodeMetadata=S}getPresets(){return v}getDefaultExtension(){return".c"}loadROM(e,s){if(!this.started)this.startModule(this.mainElement,{jsfile:"mame8bitpc.js",biosfile:"c64.zip",cfgfile:"c64.cfg",driver:"c64",width:418,height:235,romfn:"/emulator/image.crt",romdata:new Uint8Array(s),romsize:65536,extraargs:["-autoboot_delay","5","-autoboot_command",`load "$",8,1
|
||||
`],preInit:function(i){}});else{this.loadROMFile(s),this.loadRegion(":quickload",s);var t=this.luacall('image:load("/emulator/image.prg")');console.log("load rom",t)}}start(){}getMemoryMap(){return y}};n.c64=d;n["c64.wasm"]=d;n["c64.mame"]=C;
|
||||
//# sourceMappingURL=c64-5MCMD5YC.js.map
|
7
gen/c64-5MCMD5YC.js.map
Normal file
7
gen/c64-5MCMD5YC.js.map
Normal file
File diff suppressed because one or more lines are too long
@ -1,14 +0,0 @@
|
||||
import{a as M}from"./chunk-PQDZBFBB.js";import{B as S,I as _,r as g,y as b}from"./chunk-HB3LWF25.js";import{J as n,O as a,U as p,a as l,g as o,u as x}from"./chunk-ATS7PSQG.js";import"./chunk-5XVCUSSZ.js";var d=class extends g{constructor(){super(...arguments);this.numTotalScanlines=312;this.cpuCyclesPerLine=63;this.joymask0=0;this.joymask1=0;this.lightpen_x=0;this.lightpen_y=0}loadBIOS(e){var s=59940-57344+12288;e[s]=96,super.loadBIOS(e)}reset(){super.reset();for(var e=0;e<128;e++)this.exports.machine_key_up(this.sys,e);if(this.romptr&&this.romlen)if(this.exports.machine_load_rom(this.sys,this.romptr,this.romlen),this.prgstart=this.romarr[0]+(this.romarr[1]<<8),this.prgstart==2049&&(this.prgstart=this.romarr[2]+(this.romarr[3]<<8)+2,console.log("prgstart",o(this.prgstart))),this.prgstart<32768){this.exports.machine_exec(this.sys,25e4);for(var s="\rSYS "+this.prgstart+"\r",t=0;t<s.length;t++){var i=s.charCodeAt(t);this.exports.machine_exec(this.sys,2e4),this.exports.machine_key_down(this.sys,i),this.exports.machine_exec(this.sys,5e3),this.exports.machine_key_up(this.sys,i)}for(var t=0;t<1e5&&this.getPC()!=this.prgstart;t++)this.exports.machine_tick(this.sys)}else{this.exports.machine_exec(this.sys,100);for(var r=this.romarr[4]+this.romarr[5]*256,t=0;t<15e4&&this.getPC()!=r;t++)this.exports.machine_tick(this.sys)}}advanceFrame(e){var s=this.getRasterY(),t=Math.floor((this.numTotalScanlines-s)*19656/this.numTotalScanlines),i=this.probe!=null;return i&&this.exports.machine_reset_probe_buffer(),t=super.advanceFrameClock(e,t),i&&this.copyProbeData(),t}getCPUState(){this.exports.machine_save_cpu_state(this.sys,this.cpustateptr);var e=this.cpustatearr,s=e[2]+(e[3]<<8);return{PC:s,SP:e[9],A:e[6],X:e[7],Y:e[8],C:e[10]&1,Z:e[10]&2,I:e[10]&4,D:e[10]&8,V:e[10]&64,N:e[10]&128,o:this.readConst(s),R:e[19]!=55}}saveState(){this.exports.machine_save_state(this.sys,this.stateptr);let e=this.getDebugStateOffset(1),s=this.getDebugStateOffset(2),t=this.getDebugStateOffset(3),i=this.getDebugStateOffset(4),r=this.getDebugStateOffset(5),c=this.getDebugStateOffset(9);return{c:this.getCPUState(),state:this.statearr.slice(0),ram:this.statearr.slice(r,r+65536),cia1:this.statearr.slice(e,e+64),cia2:this.statearr.slice(s,s+64),vic:this.statearr.slice(t+1,t+1+64),sid:this.statearr.slice(i,i+32),pla:this.statearr.slice(c,c+16)}}loadState(e){this.statearr.set(e.state),this.exports.machine_load_state(this.sys,this.stateptr)}getVideoParams(){return{width:392,height:272,overscan:!0,videoFrequency:50,aspect:392/272*.9365}}setKeyInput(e,s,t){if(!(e==16||e==17||e==18||e==224)){var i=0,r=0;switch(e){case 32:i=16;break;case 37:e=8,i=4;break;case 38:e=11,i=1;break;case 39:e=9,i=8;break;case 40:e=10,i=2;break;case 113:e=241;break;case 115:e=243;break;case 119:e=245;break;case 121:e=247;break;case 188:e=t&a.Shift?60:46;break;case 190:e=t&a.Shift?62:44;break;case 191:e=t&a.Shift?63:47;break;case 222:e=t&a.Shift?34:39;break;case 219:e=t&a.Shift?123:91;break;case 221:e=t&a.Shift?125:93;break;case 48:t&a.Shift&&(e=41);break;case 49:t&a.Shift&&(e=33);break;case 50:t&a.Shift&&(e=64);break;case 51:t&a.Shift&&(e=35);break;case 52:t&a.Shift&&(e=36);break;case 53:t&a.Shift&&(e=37);break;case 54:t&a.Shift&&(e=94);break;case 55:t&a.Shift&&(e=38);break;case 56:t&a.Shift&&(e=42);break;case 57:t&a.Shift&&(e=40);break;case 59:t&a.Shift&&(e=58);break;case 61:t&a.Shift&&(e=43);break;case 173:e=t&a.Shift?95:45;break}t&a.KeyDown?(this.exports.machine_key_down(this.sys,e),this.joymask0|=i,this.joymask1|=r):t&a.KeyUp&&(this.exports.machine_key_up(this.sys,e),this.joymask0&=~i,this.joymask1&=~r),this.exports.c64_joystick(this.sys,this.joymask0,this.joymask1)}}getRasterY(){return this.exports.machine_get_raster_line(this.sys)}getDebugStateOffset(e){var s=this.exports.machine_get_debug_pointer(this.sys,e);return s-this.sys}getDebugCategories(){return["CPU","ZPRAM","Stack","PLA","CIA","VIC","SID"]}getDebugInfo(e,s){switch(e){case"PLA":{let t="",i=s.pla[0],r=s.pla[3];return t+=`$0000 - $9FFF RAM
|
||||
`,t+=`$A000 - $BFFF ${(r&3)==3?"BASIC ROM":"RAM"}
|
||||
`,t+=`$C000 - $CFFF RAM
|
||||
`,t+=`$D000 - $DFFF ${i?"I/O":(r&3)!=0?"CHAR ROM":"RAM"}
|
||||
`,t+=`$E000 - $FFFF ${(r&2)==2?"KERNAL ROM":"RAM"}
|
||||
`,t}case"CIA":{let t="";for(let i=0;i<2;i++){let r=i?s.cia2:s.cia1;t+=`CIA ${i+1}
|
||||
`,t+=` A: Data ${o(r[0])} DDR ${o(r[1])} Input ${o(r[2])}`,t+=` Timer ${o(r[10]+r[11]*256,4)}
|
||||
`,t+=` B: Data ${o(r[4])} DDR ${o(r[5])} Input ${o(r[6])}`,t+=` Timer ${o(r[10+10]+r[11+10]*256,4)}
|
||||
`}return t}case"VIC":{let t=s.vic,i="",r=(s.cia2[0]&3^3)*16384,c=r+(s.vic[24]&14)*1024,m=r+(s.vic[24]>>4)*1024,h=s.vic[17]&32,R=(s.cia2[0]&1)==1&&(s.vic[24]&12)==4,y=s.state[244],$=this.getRasterY();return i+="Mode:",s.vic[17]&32?i+=" BITMAP":i+=" CHAR",s.vic[22]&16&&(i+=" MULTICOLOR"),s.vic[17]&64&&(i+=" EXTENDED"),i+=`
|
||||
`,i+=`Raster: (${l(y,3)}, ${l($,3)}) `,i+=`Scroll: (${s.vic[22]&7}, ${s.vic[17]&7})`,i+=`
|
||||
`,i+=`VIC Bank: $${o(r,4)} Scrn: $${o(m,4)} `,h?i+=`Bitmap: $${o(c&57344,4)}`:R?i+=`Char: ROM $${o(c,4)}`:i+=`Char: $${o(c,4)}`,i+=`
|
||||
`,i+=p(t,53248,64),i}case"SID":{let t=s.sid,i="";return i+=p(t,54272,32),i}}}setPaddleInput(e,s){e==0&&(this.lightpen_x=s),e==1&&(this.lightpen_y=s);let t=22,i=36,r=228,c=220,m=x(0,255,(this.lightpen_x-t)/(r-t)*160+24),h=x(0,255,(this.lightpen_y-i)/(c-i)*200+50);this.exports.machine_set_mouse(this.sys,m,h)}};var v=[{id:"hello.dasm",name:"Hello World (ASM)"},{id:"23matches.c",name:"23 Matches"},{id:"tgidemo.c",name:"TGI Graphics Demo"},{id:"upandaway.c",name:"Up, Up and Away"},{id:"siegegame.c",name:"Siege Game"},{id:"joymove.c",name:"Sprite Movement"},{id:"sprite_collision.c",name:"Sprite Collision"},{id:"scroll1.c",name:"Scrolling (Single Buffer)"},{id:"scroll2.c",name:"Scrolling (Double Buffer)"},{id:"scroll3.c",name:"Scrolling (Multidirectional)"},{id:"scroll4.c",name:"Scrolling (Color RAM Buffering)"},{id:"scroll5.c",name:"Scrolling (Camera Following)"},{id:"side_scroller.c",name:"Side-Scrolling Game"},{id:"fullscrollgame.c",name:"Full-Scrolling Game"},{id:"test_multiplex.c",name:"Sprite Retriggering"},{id:"test_multispritelib.c",name:"Sprite Multiplexing Library"},{id:"scrolling_text.c",name:"Big Scrolling Text"},{id:"mcbitmap.c",name:"Multicolor Bitmap Mode"},{id:"musicplayer.c",name:"Music Player"},{id:"siddemo.c",name:"SID Player Demo"},{id:"climber.c",name:"Climber Game"}],C={main:[{name:"6510 Registers",start:0,size:2,type:"io"},{name:"BIOS Reserved",start:512,size:167},{name:"Default Screen RAM",start:1024,size:1024,type:"ram"},{name:"Cartridge ROM",start:32768,size:8192,type:"rom"},{name:"BASIC ROM",start:40960,size:8192,type:"rom"},{name:"Upper RAM",start:49152,size:4096,type:"ram"},{name:"Character ROM",start:53248,size:4096,type:"rom"},{name:"VIC-II I/O",start:53248,size:1024,type:"io"},{name:"SID",start:54272,size:1024,type:"io"},{name:"Color RAM",start:55296,size:1024,type:"io"},{name:"CIA 1",start:56320,size:256,type:"io"},{name:"CIA 2",start:56576,size:256,type:"io"},{name:"I/O 1",start:56832,size:256,type:"io"},{name:"I/O 2",start:57088,size:256,type:"io"},{name:"KERNAL ROM",start:57344,size:8192,type:"rom"}]},f=class extends _{newMachine(){return new d("c64")}getPresets(){return v}getDefaultExtension(){return".c"}readAddress(e){return this.machine.readConst(e)}getMemoryMap(){return C}showHelp(){return"https://8bitworkshop.com/docs/platforms/c64/"}getROMExtension(e){return e&&e[0]==1&&e[1]==8?".prg":".bin"}},A=class extends M{constructor(){super(...arguments);this.getToolForFilename=b;this.getOpcodeMetadata=S}getPresets(){return v}getDefaultExtension(){return".c"}loadROM(e,s){if(!this.started)this.startModule(this.mainElement,{jsfile:"mame8bitpc.js",biosfile:"c64.zip",cfgfile:"c64.cfg",driver:"c64",width:418,height:235,romfn:"/emulator/image.crt",romdata:new Uint8Array(s),romsize:65536,extraargs:["-autoboot_delay","5","-autoboot_command",`load "$",8,1
|
||||
`],preInit:function(i){}});else{this.loadROMFile(s),this.loadRegion(":quickload",s);var t=this.luacall('image:load("/emulator/image.prg")');console.log("load rom",t)}}start(){}getMemoryMap(){return C}};n.c64=f;n["c64.wasm"]=f;n["c64.mame"]=A;
|
||||
//# sourceMappingURL=c64-73FGKJFH.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
||||
import{a as d}from"./chunk-3XE5YOCV.js";import{o as c}from"./chunk-4TWVHUDP.js";import"./chunk-SXEVG2WS.js";import"./chunk-5SHCNQ2O.js";import"./chunk-4PJ2B2TK.js";import{I as m,o as u,t as h}from"./chunk-HB3LWF25.js";import{$ as i,B as o,J as l,m as n}from"./chunk-ATS7PSQG.js";import"./chunk-5XVCUSSZ.js";var s=31,a=class extends u{constructor(){super();this.cpuFrequency=1e6;this.defaultROMSize=32768;this.cpu=new h;this.ram=new Uint8Array(16384);this.read=i([[0,16383,16383,e=>this.ram[e]],[16384,16384,65535,e=>this.serial.byteAvailable()?128:0],[16385,16385,65535,e=>this.serial.recvByte()],[16386,16386,65535,e=>this.serial.clearToSend()?128:0],[32768,65535,32767,e=>this.rom&&this.rom[e]]]);this.write=i([[0,16383,16383,(e,t)=>{this.ram[e]=t}],[16387,16387,65535,(e,t)=>this.serial.sendByte(t)],[16399,16399,65535,(e,t)=>{this.inputs[s]=1}]]);this.connectCPUMemoryBus(this)}connectSerialIO(e){this.serial=e}readConst(e){return this.read(e)}advanceFrame(e){for(var t=0;t<this.cpuFrequency/60&&!(e&&e());)t+=this.advanceCPU();return t}advanceCPU(){if(this.isHalted())return 1;var e=super.advanceCPU();return this.serial&&this.serial.advance(e),e}reset(){this.inputs[s]=0,super.reset(),this.serial&&this.serial.reset()}isHalted(){return this.inputs[s]!=0}};var S=[{id:"hello.dasm",name:"Hello World (ASM)"}],f=class{constructor(e){e.style.overflowY="auto";var t=$('<div id="gameport"/>').appendTo(e);$('<p class="transcript-header">Serial Output</p>').appendTo(t);var y=$('<div id="windowport" class="transcript"/>').appendTo(t);this.div=y[0]}start(){this.tty=new d(this.div,!1)}reset(){this.tty.clear()}saveState(){return this.tty.saveState()}loadState(e){this.tty.loadState(e)}};function p(r){return r==10?"":r<32?String.fromCharCode(r+9216):String.fromCharCode(r)}var v=class{constructor(){this.bufferedRead=!0;this.cyclesPerByte=1e6/(57600/8);this.maxOutputBytes=4096}clearToSend(){return this.outputBytes.length<this.maxOutputBytes}sendByte(e){this.clearToSend()&&(this.outputBytes.push(e),this.viewer.tty.addtext(p(e),2|32),e==10&&this.viewer.tty.newline(),this.clearToSend()||(this.viewer.tty.newline(),this.viewer.tty.addtext("\u26A0\uFE0F OUTPUT BUFFER FULL \u26A0\uFE0F",4)))}byteAvailable(){return this.readIndex()>this.inputIndex}recvByte(){var e=this.readIndex();this.inputIndex=e;var t=(this.inputBytes&&this.inputBytes[e])|0;return this.viewer.tty.addtext(p(t),2|16),t==10&&this.viewer.tty.newline(),t}readIndex(){return this.bufferedRead?this.inputIndex+1:Math.floor(this.clk/this.cyclesPerByte)}reset(){this.inputIndex=-1,this.clk=0,this.outputBytes=[],this.bufin=""}advance(e){this.clk+=e}saveState(){return{clk:this.clk,idx:this.inputIndex,out:this.outputBytes.slice()}}loadState(e){this.clk=e.clk,this.inputIndex=e.idx,this.outputBytes=e.out.slice()}},x=class extends m{constructor(e){super(e);this.getMemoryMap=function(){return{main:[{name:"RAM",start:0,size:16384,type:"ram"},{name:"ROM",start:32768,size:32768,type:"rom"}]}};this.serview=new f(e)}async start(){super.start(),this.serial=new v,this.serial.viewer=this.serview,this.serview.start(),this.machine.connectSerialIO(this.serial)}reset(){this.serial.inputBytes=o(this.internalFiles["serialin.dat"]),super.reset(),this.serview.reset()}isBlocked(){return this.machine.isHalted()}advance(e){return this.isBlocked()?(this.internalFiles["serialout.dat"]=n(this.serial.outputBytes),c(),0):super.advance(e)}saveState(){var e=super.saveState();return e.serial=this.serial.saveState(),e.serview=this.serview.saveState(),e}loadState(e){super.loadState(e),this.serial.loadState(e.serial),this.serview.loadState(e.serview)}newMachine(){return new a}getPresets(){return S}getDefaultExtension(){return".dasm"}readAddress(e){return this.machine.readConst(e)}};l["devel-6502"]=x;export{v as SerialTestHarness};
|
||||
//# sourceMappingURL=devel-OECID263.js.map
|
||||
import{a as d}from"./chunk-3XE5YOCV.js";import{o as c}from"./chunk-R63KYPGV.js";import"./chunk-SXEVG2WS.js";import"./chunk-5SHCNQ2O.js";import"./chunk-Z2IKIN54.js";import{I as m,o as u,t as h}from"./chunk-HB3LWF25.js";import{$ as i,B as o,J as l,m as n}from"./chunk-ATS7PSQG.js";import"./chunk-5XVCUSSZ.js";var s=31,a=class extends u{constructor(){super();this.cpuFrequency=1e6;this.defaultROMSize=32768;this.cpu=new h;this.ram=new Uint8Array(16384);this.read=i([[0,16383,16383,e=>this.ram[e]],[16384,16384,65535,e=>this.serial.byteAvailable()?128:0],[16385,16385,65535,e=>this.serial.recvByte()],[16386,16386,65535,e=>this.serial.clearToSend()?128:0],[32768,65535,32767,e=>this.rom&&this.rom[e]]]);this.write=i([[0,16383,16383,(e,t)=>{this.ram[e]=t}],[16387,16387,65535,(e,t)=>this.serial.sendByte(t)],[16399,16399,65535,(e,t)=>{this.inputs[s]=1}]]);this.connectCPUMemoryBus(this)}connectSerialIO(e){this.serial=e}readConst(e){return this.read(e)}advanceFrame(e){for(var t=0;t<this.cpuFrequency/60&&!(e&&e());)t+=this.advanceCPU();return t}advanceCPU(){if(this.isHalted())return 1;var e=super.advanceCPU();return this.serial&&this.serial.advance(e),e}reset(){this.inputs[s]=0,super.reset(),this.serial&&this.serial.reset()}isHalted(){return this.inputs[s]!=0}};var S=[{id:"hello.dasm",name:"Hello World (ASM)"}],f=class{constructor(e){e.style.overflowY="auto";var t=$('<div id="gameport"/>').appendTo(e);$('<p class="transcript-header">Serial Output</p>').appendTo(t);var y=$('<div id="windowport" class="transcript"/>').appendTo(t);this.div=y[0]}start(){this.tty=new d(this.div,!1)}reset(){this.tty.clear()}saveState(){return this.tty.saveState()}loadState(e){this.tty.loadState(e)}};function p(r){return r==10?"":r<32?String.fromCharCode(r+9216):String.fromCharCode(r)}var v=class{constructor(){this.bufferedRead=!0;this.cyclesPerByte=1e6/(57600/8);this.maxOutputBytes=4096}clearToSend(){return this.outputBytes.length<this.maxOutputBytes}sendByte(e){this.clearToSend()&&(this.outputBytes.push(e),this.viewer.tty.addtext(p(e),2|32),e==10&&this.viewer.tty.newline(),this.clearToSend()||(this.viewer.tty.newline(),this.viewer.tty.addtext("\u26A0\uFE0F OUTPUT BUFFER FULL \u26A0\uFE0F",4)))}byteAvailable(){return this.readIndex()>this.inputIndex}recvByte(){var e=this.readIndex();this.inputIndex=e;var t=(this.inputBytes&&this.inputBytes[e])|0;return this.viewer.tty.addtext(p(t),2|16),t==10&&this.viewer.tty.newline(),t}readIndex(){return this.bufferedRead?this.inputIndex+1:Math.floor(this.clk/this.cyclesPerByte)}reset(){this.inputIndex=-1,this.clk=0,this.outputBytes=[],this.bufin=""}advance(e){this.clk+=e}saveState(){return{clk:this.clk,idx:this.inputIndex,out:this.outputBytes.slice()}}loadState(e){this.clk=e.clk,this.inputIndex=e.idx,this.outputBytes=e.out.slice()}},x=class extends m{constructor(e){super(e);this.getMemoryMap=function(){return{main:[{name:"RAM",start:0,size:16384,type:"ram"},{name:"ROM",start:32768,size:32768,type:"rom"}]}};this.serview=new f(e)}async start(){super.start(),this.serial=new v,this.serial.viewer=this.serview,this.serview.start(),this.machine.connectSerialIO(this.serial)}reset(){this.serial.inputBytes=o(this.internalFiles["serialin.dat"]),super.reset(),this.serview.reset()}isBlocked(){return this.machine.isHalted()}advance(e){return this.isBlocked()?(this.internalFiles["serialout.dat"]=n(this.serial.outputBytes),c(),0):super.advance(e)}saveState(){var e=super.saveState();return e.serial=this.serial.saveState(),e.serview=this.serview.saveState(),e}loadState(e){super.loadState(e),this.serial.loadState(e.serial),this.serview.loadState(e.serview)}newMachine(){return new a}getPresets(){return S}getDefaultExtension(){return".dasm"}readAddress(e){return this.machine.readConst(e)}};l["devel-6502"]=x;export{v as SerialTestHarness};
|
||||
//# sourceMappingURL=devel-364UXGWH.js.map
|
@ -1,2 +1,2 @@
|
||||
import{b as w,c as x}from"./chunk-4PJ2B2TK.js";import{D as v,J as c,k as m,l as u,x as g,z as p}from"./chunk-ATS7PSQG.js";import{e as I}from"./chunk-5XVCUSSZ.js";var h=I(x()),i,a,l,y=function(e){if(!e||e.length==0)return{};for(var r={},t=0;t<e.length;++t){var o=e[t].split("=",2);o.length==1?r[o[0]]="":r[o[0]]=decodeURIComponent(o[1].replace(/\+/g," "))}return r}(window.location.search.substr(1).split("&"));function P(){typeof window.onerror=="object"&&(window.onerror=function(e,r,t,o,n){var s=e+" "+r+" "+t+":"+o+", "+n;$.get("/error?msg="+encodeURIComponent(s),"text")})}function M(){var e=!1;document.addEventListener("visibilitychange",function(r){document.visibilityState=="hidden"&&a.isRunning()?(a.pause(),e=!0):document.visibilityState=="visible"&&e&&(a.resume(),e=!1)}),$(window).on("focus",function(){e&&(a.resume(),e=!1)}),$(window).on("blur",function(){a.isRunning()&&(a.pause(),e=!0)})}async function k(e,r){if(!r){alert("No ROM found.");return}console.log(r.length+" bytes"),await a.loadROM(e,r),a.resume()}function R(){return $("#emulator").find("canvas")}function E(e,r,t){v("gif.js/dist/gif.js").then(()=>{var o=R()[0];if(!o){alert("Could not find canvas element to record video!");return}var n=0;o.style&&o.style.transform&&(o.style.transform.indexOf("rotate(-90deg)")>=0?n=-1:o.style.transform.indexOf("rotate(90deg)")>=0&&(n=1));var s=new GIF({workerScript:"gif.js/dist/gif.worker.js",workers:4,quality:10,rotate:n});s.on("finished",function(C){console.log("finished encoding GIF"),t(C)}),e=e||100+(Math.random()*256&3),r=r||100+(Math.random()*256&15);var f=0;console.log("Recording video",o);var d=()=>{f++>r?(console.log("Rendering video"),s.render()):(s.addFrame(o,{delay:e,copy:!0}),setTimeout(d,e))};d()})}async function S(e){if(!c[i])throw Error("Invalid platform '"+i+"'.");a=new c[i]($("#emuscreen")[0]),await a.start(),e.rec&&R().on("focus",()=>{a.resume()});var r=e.n||"Game",t,o=e.url,n=e.r;if(o)return console.log(o),g(o,f=>{k(r,f)},"arraybuffer"),!0;if(n){var s=u(atob(n));t=new m().decode(s)}return M(),k(r,t),!0}async function b(e){if(e.data&&(e=e.data),i=e.p,!i)throw new Error("No platform variable!");try{var r=await w(p(i));console.log("starting platform",i),await S(e)}catch(t){console.log(t),alert('Platform "'+i+'" not supported.')}}function F(){P(),y.p&&b(y)}window.addEventListener("message",O,!1);function O(e){if(e.data){var r=e.data.cmd;if(r=="start"&&!a)b(e);else if(r=="reset")a.reset(),l.reset();else if(r=="getReplay"){var t={frameCount:l.frameCount,checkpoints:l.checkpoints,framerecs:l.framerecs,checkpointInterval:l.checkpointInterval,maxCheckpoints:l.maxCheckpoints};e.source.postMessage({ack:r,replay:t},e.origin)}else if(r=="watchState"){var o=new Function("platform","state",e.data.fn);l.callbackNewCheckpoint=n=>{e.source.postMessage({ack:r,state:o(a,n)},e.origin)}}else r=="recordVideo"?E(e.data.intervalMsec,e.data.maxFrames,function(n){e.data.filename&&(0,h.saveAs)(n,e.data.filename),e.source.postMessage({ack:r,gif:n},e.origin)}):console.log("Unknown data.cmd: "+r)}}self===top&&(document.body.style.backgroundColor="#555");F();export{a as platform,i as platform_id,F as startEmbed,l as stateRecorder};
|
||||
import{b as w,c as x}from"./chunk-Z2IKIN54.js";import{D as v,J as c,k as m,l as u,x as g,z as p}from"./chunk-ATS7PSQG.js";import{e as I}from"./chunk-5XVCUSSZ.js";var h=I(x()),i,a,l,y=function(e){if(!e||e.length==0)return{};for(var r={},t=0;t<e.length;++t){var o=e[t].split("=",2);o.length==1?r[o[0]]="":r[o[0]]=decodeURIComponent(o[1].replace(/\+/g," "))}return r}(window.location.search.substr(1).split("&"));function P(){typeof window.onerror=="object"&&(window.onerror=function(e,r,t,o,n){var s=e+" "+r+" "+t+":"+o+", "+n;$.get("/error?msg="+encodeURIComponent(s),"text")})}function M(){var e=!1;document.addEventListener("visibilitychange",function(r){document.visibilityState=="hidden"&&a.isRunning()?(a.pause(),e=!0):document.visibilityState=="visible"&&e&&(a.resume(),e=!1)}),$(window).on("focus",function(){e&&(a.resume(),e=!1)}),$(window).on("blur",function(){a.isRunning()&&(a.pause(),e=!0)})}async function k(e,r){if(!r){alert("No ROM found.");return}console.log(r.length+" bytes"),await a.loadROM(e,r),a.resume()}function R(){return $("#emulator").find("canvas")}function E(e,r,t){v("gif.js/dist/gif.js").then(()=>{var o=R()[0];if(!o){alert("Could not find canvas element to record video!");return}var n=0;o.style&&o.style.transform&&(o.style.transform.indexOf("rotate(-90deg)")>=0?n=-1:o.style.transform.indexOf("rotate(90deg)")>=0&&(n=1));var s=new GIF({workerScript:"gif.js/dist/gif.worker.js",workers:4,quality:10,rotate:n});s.on("finished",function(C){console.log("finished encoding GIF"),t(C)}),e=e||100+(Math.random()*256&3),r=r||100+(Math.random()*256&15);var f=0;console.log("Recording video",o);var d=()=>{f++>r?(console.log("Rendering video"),s.render()):(s.addFrame(o,{delay:e,copy:!0}),setTimeout(d,e))};d()})}async function S(e){if(!c[i])throw Error("Invalid platform '"+i+"'.");a=new c[i]($("#emuscreen")[0]),await a.start(),e.rec&&R().on("focus",()=>{a.resume()});var r=e.n||"Game",t,o=e.url,n=e.r;if(o)return console.log(o),g(o,f=>{k(r,f)},"arraybuffer"),!0;if(n){var s=u(atob(n));t=new m().decode(s)}return M(),k(r,t),!0}async function b(e){if(e.data&&(e=e.data),i=e.p,!i)throw new Error("No platform variable!");try{var r=await w(p(i));console.log("starting platform",i),await S(e)}catch(t){console.log(t),alert('Platform "'+i+'" not supported.')}}function F(){P(),y.p&&b(y)}window.addEventListener("message",O,!1);function O(e){if(e.data){var r=e.data.cmd;if(r=="start"&&!a)b(e);else if(r=="reset")a.reset(),l.reset();else if(r=="getReplay"){var t={frameCount:l.frameCount,checkpoints:l.checkpoints,framerecs:l.framerecs,checkpointInterval:l.checkpointInterval,maxCheckpoints:l.maxCheckpoints};e.source.postMessage({ack:r,replay:t},e.origin)}else if(r=="watchState"){var o=new Function("platform","state",e.data.fn);l.callbackNewCheckpoint=n=>{e.source.postMessage({ack:r,state:o(a,n)},e.origin)}}else r=="recordVideo"?E(e.data.intervalMsec,e.data.maxFrames,function(n){e.data.filename&&(0,h.saveAs)(n,e.data.filename),e.source.postMessage({ack:r,gif:n},e.origin)}):console.log("Unknown data.cmd: "+r)}}self===top&&(document.body.style.backgroundColor="#555");F();export{a as platform,i as platform_id,F as startEmbed,l as stateRecorder};
|
||||
//# sourceMappingURL=embedui.js.map
|
||||
|
@ -118,8 +118,16 @@ class CodeProject {
|
||||
}
|
||||
this.callbackBuildResult(data);
|
||||
}
|
||||
getToolForFilename(path) {
|
||||
if (this.remoteTool) {
|
||||
return "remote:" + this.remoteTool;
|
||||
}
|
||||
else {
|
||||
return this.platform.getToolForFilename(path);
|
||||
}
|
||||
}
|
||||
preloadWorker(path) {
|
||||
var tool = this.platform.getToolForFilename(path);
|
||||
var tool = this.getToolForFilename(path);
|
||||
if (tool && !this.tools_preloaded[tool]) {
|
||||
this.worker.postMessage({ preload: tool, platform: this.platform_id });
|
||||
this.tools_preloaded[tool] = true;
|
||||
@ -256,7 +264,7 @@ class CodeProject {
|
||||
path: mainfilename,
|
||||
files: [mainfilename].concat(depfiles),
|
||||
platform: this.platform_id,
|
||||
tool: this.platform.getToolForFilename(this.mainPath),
|
||||
tool: this.getToolForFilename(this.mainPath),
|
||||
mainfile: true
|
||||
});
|
||||
for (var dep of depends) {
|
||||
@ -267,7 +275,7 @@ class CodeProject {
|
||||
path: dep.filename,
|
||||
files: [dep.filename].concat(depfiles),
|
||||
platform: this.platform_id,
|
||||
tool: this.platform.getToolForFilename(dep.path)
|
||||
tool: this.getToolForFilename(dep.path)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -217,6 +217,7 @@ async function newFilesystem() {
|
||||
async function initProject() {
|
||||
var filesystem = await newFilesystem();
|
||||
exports.current_project = new project_1.CodeProject(newWorker(), exports.platform_id, exports.platform, filesystem);
|
||||
exports.current_project.remoteTool = exports.qs.tool || null;
|
||||
exports.projectWindows = new windows_1.ProjectWindows($("#workspace")[0], exports.current_project);
|
||||
exports.current_project.callbackBuildResult = (result) => {
|
||||
setCompileOutput(result);
|
||||
|
File diff suppressed because one or more lines are too long
@ -31,23 +31,40 @@ class C64_WASMMachine extends wasmplatform_1.BaseWASMMachine {
|
||||
this.prgstart = this.romarr[0] + (this.romarr[1] << 8); // get load address
|
||||
// look for BASIC program start
|
||||
if (this.prgstart == 0x801) {
|
||||
this.prgstart = this.romarr[2] + (this.romarr[3] << 8) + 2; // point to after BASIC program
|
||||
console.log("prgstart", (0, util_1.hex)(this.prgstart));
|
||||
// decode SYS address from decimal?
|
||||
if (this.romarr[6] == 0x9e) {
|
||||
var addr = 0;
|
||||
for (var i = 0; i < 5; i++) {
|
||||
var ch = this.romarr[7 + i];
|
||||
if (ch == 0x9b || ch == 0)
|
||||
break;
|
||||
addr = addr * 10 + (ch & 0xf);
|
||||
}
|
||||
this.prgstart = addr;
|
||||
console.log("SYS", addr, (0, util_1.hex)(addr));
|
||||
}
|
||||
else {
|
||||
this.prgstart = this.romarr[2] + (this.romarr[3] << 8) + 2; // point to after BASIC program
|
||||
console.log("RUN", this.prgstart, (0, util_1.hex)(this.prgstart));
|
||||
}
|
||||
}
|
||||
// is program loaded into RAM?
|
||||
if (this.prgstart < 0x8000) {
|
||||
// advance BIOS a few frames
|
||||
this.exports.machine_exec(this.sys, 250000);
|
||||
// type in command (SYS 2061)
|
||||
var cmd = "\rSYS " + this.prgstart + "\r";
|
||||
var cmd = "\rSYS " + this.prgstart;
|
||||
for (var i = 0; i < cmd.length; i++) {
|
||||
var key = cmd.charCodeAt(i);
|
||||
this.exports.machine_exec(this.sys, 20000);
|
||||
this.exports.machine_exec(this.sys, 30000);
|
||||
this.exports.machine_key_down(this.sys, key);
|
||||
this.exports.machine_exec(this.sys, 5000);
|
||||
this.exports.machine_exec(this.sys, 30000);
|
||||
this.exports.machine_key_up(this.sys, key);
|
||||
this.exports.machine_exec(this.sys, 1); // chips/kbd.c has a "sticky counter"
|
||||
}
|
||||
// advance clock until program starts
|
||||
this.exports.machine_key_down(this.sys, 13);
|
||||
this.exports.machine_exec(this.sys, 1); // chips/kbd.c has a "sticky counter"
|
||||
for (var i = 0; i < 100000 && this.getPC() != this.prgstart; i++) {
|
||||
this.exports.machine_tick(this.sys);
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
||||
import{b as a,c as b,d as c,e as d,f as e,g as f,h as g,i as h,j as i,k as j,l as k,m as l,n as m,o as n,p as o,q as p,r as q,s as r,t as s,u as t,v as u,w as v,x as w}from"./chunk-4TWVHUDP.js";import"./chunk-SXEVG2WS.js";import"./chunk-5SHCNQ2O.js";import"./chunk-4PJ2B2TK.js";import"./chunk-HB3LWF25.js";import"./chunk-ATS7PSQG.js";import"./chunk-5XVCUSSZ.js";export{l as clearBreakpoint,h as compparams,f as current_project,u as emulationHalted,p as getPlatformAndRepo,t as getSaveState,s as getTestOutput,n as haltEmulation,w as highlightSearch,i as lastDebugState,e as platform,b as platform_id,g as projectWindows,a as qs,v as reloadWorkspaceFile,d as repo_id,k as runToPC,m as setFrameRateUI,r as setTestInput,j as setupBreakpoint,o as setupSplits,q as startUI,c as store_id};
|
||||
import{b as a,c as b,d as c,e as d,f as e,g as f,h as g,i as h,j as i,k as j,l as k,m as l,n as m,o as n,p as o,q as p,r as q,s as r,t as s,u as t,v as u,w as v,x as w}from"./chunk-R63KYPGV.js";import"./chunk-SXEVG2WS.js";import"./chunk-5SHCNQ2O.js";import"./chunk-Z2IKIN54.js";import"./chunk-HB3LWF25.js";import"./chunk-ATS7PSQG.js";import"./chunk-5XVCUSSZ.js";export{l as clearBreakpoint,h as compparams,f as current_project,u as emulationHalted,p as getPlatformAndRepo,t as getSaveState,s as getTestOutput,n as haltEmulation,w as highlightSearch,i as lastDebugState,e as platform,b as platform_id,g as projectWindows,a as qs,v as reloadWorkspaceFile,d as repo_id,k as runToPC,m as setFrameRateUI,r as setTestInput,j as setupBreakpoint,o as setupSplits,q as startUI,c as store_id};
|
||||
//# sourceMappingURL=ui.js.map
|
||||
|
@ -36,6 +36,24 @@
|
||||
return v + "";
|
||||
}
|
||||
}
|
||||
function stringToByteArray(s) {
|
||||
var a = new Uint8Array(s.length);
|
||||
for (var i = 0; i < s.length; i++)
|
||||
a[i] = s.charCodeAt(i);
|
||||
return a;
|
||||
}
|
||||
function byteArrayToString(data) {
|
||||
var str = "";
|
||||
if (data != null) {
|
||||
var charLUT = new Array();
|
||||
for (var i = 0; i < 256; ++i)
|
||||
charLUT[i] = String.fromCharCode(i);
|
||||
var len = data.length;
|
||||
for (var i = 0; i < len; i++)
|
||||
str += charLUT[data[i]];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
function getBasePlatform(platform) {
|
||||
return platform.split(".")[0];
|
||||
}
|
||||
@ -8733,6 +8751,54 @@ ${this.scopeSymbol(name)} = ${name}::__Start`;
|
||||
}
|
||||
}
|
||||
|
||||
// src/common/workertypes.ts
|
||||
function isUnchanged(result) {
|
||||
return "unchanged" in result;
|
||||
}
|
||||
function isErrorResult(result) {
|
||||
return "errors" in result;
|
||||
}
|
||||
function isOutputResult(result) {
|
||||
return "output" in result;
|
||||
}
|
||||
|
||||
// src/worker/tools/remote.ts
|
||||
var REMOTE_URL = "http://localhost:3009/build";
|
||||
var sessionID = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
||||
async function buildRemote(step) {
|
||||
gatherFiles(step);
|
||||
var binpath = "a.out";
|
||||
if (staleFiles(step, [binpath])) {
|
||||
let updates = [];
|
||||
for (var i = 0; i < step.files.length; i++) {
|
||||
let path = step.files[i];
|
||||
let entry = store.workfs[path];
|
||||
let data = typeof entry.data === "string" ? entry.data : btoa(byteArrayToString(entry.data));
|
||||
updates.push({ path, data });
|
||||
}
|
||||
let cmd = { buildStep: step, updates, sessionID };
|
||||
console.log("POST", cmd);
|
||||
let result = await fetch(REMOTE_URL, {
|
||||
method: "POST",
|
||||
mode: "cors",
|
||||
body: JSON.stringify(cmd),
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
let json = await result.json();
|
||||
if (isUnchanged(json))
|
||||
return json;
|
||||
if (isErrorResult(json))
|
||||
return json;
|
||||
if (isOutputResult(json)) {
|
||||
json.output = stringToByteArray(atob(json.output));
|
||||
return json;
|
||||
}
|
||||
throw new Error(`Unexpected result from remote build: ${JSON.stringify(json)}`);
|
||||
}
|
||||
}
|
||||
|
||||
// src/worker/workermain.ts
|
||||
var ENVIRONMENT_IS_WEB = typeof window === "object";
|
||||
var ENVIRONMENT_IS_WORKER = typeof importScripts === "function";
|
||||
@ -9181,9 +9247,14 @@ ${this.scopeSymbol(name)} = ${name}::__Start`;
|
||||
while (this.steps.length) {
|
||||
var step = this.steps.shift();
|
||||
var platform = step.platform;
|
||||
var toolfn = TOOLS[step.tool];
|
||||
if (!toolfn)
|
||||
throw Error("no tool named " + step.tool);
|
||||
var [tool, remoteTool] = step.tool.split(":", 2);
|
||||
var toolfn = TOOLS[tool];
|
||||
if (!toolfn) {
|
||||
throw Error(`no tool named "${tool}"`);
|
||||
}
|
||||
if (remoteTool) {
|
||||
step.tool = remoteTool;
|
||||
}
|
||||
step.params = PLATFORM_PARAMS[getBasePlatform(platform)];
|
||||
try {
|
||||
step.result = await toolfn(step);
|
||||
@ -9755,7 +9826,8 @@ ${this.scopeSymbol(name)} = ${name}::__Start`;
|
||||
"wiz": compileWiz,
|
||||
"armips": assembleARMIPS,
|
||||
"vasmarm": assembleVASMARM,
|
||||
"ecs": assembleECS
|
||||
"ecs": assembleECS,
|
||||
"remote": buildRemote
|
||||
};
|
||||
var TOOL_PRELOADFS = {
|
||||
"cc65-apple2": "65-apple2",
|
||||
|
File diff suppressed because one or more lines are too long
201
gen/worker/server/buildenv.js
Normal file
201
gen/worker/server/buildenv.js
Normal file
@ -0,0 +1,201 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ServerBuildEnv = exports.TOOLS = exports.findBestTool = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const path_1 = __importDefault(require("path"));
|
||||
const child_process_1 = require("child_process");
|
||||
const workertypes_1 = require("../../common/workertypes");
|
||||
const util_1 = require("../../common/util");
|
||||
const workermain_1 = require("../workermain");
|
||||
const clang_1 = require("./clang");
|
||||
const LLVM_MOS_TOOL = {
|
||||
name: 'llvm-mos',
|
||||
version: '',
|
||||
extensions: ['.c'],
|
||||
archs: ['6502'],
|
||||
platforms: ['atari8', 'c64', 'nes'],
|
||||
platform_configs: {
|
||||
default: {
|
||||
binpath: 'llvm-mos/bin',
|
||||
command: 'mos-clang',
|
||||
args: ['-Os', '-g', '-o', '$OUTFILE', '$INFILES'],
|
||||
},
|
||||
debug: {
|
||||
binpath: 'llvm-mos/bin',
|
||||
command: 'llvm-objdump',
|
||||
args: ['-l', '-t', '$WORKDIR/a.out.elf', '>$WORKDIR/debug.out']
|
||||
},
|
||||
c64: {
|
||||
command: 'mos-c64-clang',
|
||||
},
|
||||
atari8: {
|
||||
command: 'mos-atari8-clang',
|
||||
},
|
||||
nes: {
|
||||
command: 'mos-nes-nrom-clang',
|
||||
libargs: ['-lneslib']
|
||||
},
|
||||
}
|
||||
};
|
||||
function findBestTool(step) {
|
||||
if (!(step === null || step === void 0 ? void 0 : step.tool))
|
||||
throw new Error('No tool specified');
|
||||
const [name, version] = step.tool.split('@');
|
||||
for (let tool of exports.TOOLS) {
|
||||
if (tool.name === name && (!version || version === 'latest' || tool.version === version)) {
|
||||
return tool;
|
||||
}
|
||||
}
|
||||
throw new Error(`Tool not found: ${step.tool}`);
|
||||
}
|
||||
exports.findBestTool = findBestTool;
|
||||
exports.TOOLS = [
|
||||
Object.assign({}, LLVM_MOS_TOOL, { version: '0.13.2' }),
|
||||
];
|
||||
class ServerBuildEnv {
|
||||
constructor(rootdir, sessionID, tool) {
|
||||
this.rootdir = path_1.default.resolve(rootdir);
|
||||
this.sessionID = sessionID;
|
||||
this.tool = tool;
|
||||
// make sure sessionID is well-formed
|
||||
if (!sessionID.match(/^[a-zA-Z0-9_-]+$/)) {
|
||||
throw new Error(`Invalid sessionID: ${sessionID}`);
|
||||
}
|
||||
// create sessionID directory if it doesn't exist
|
||||
this.sessionDir = path_1.default.join(this.rootdir, 'sessions', sessionID);
|
||||
if (!fs_1.default.existsSync(this.sessionDir)) {
|
||||
fs_1.default.mkdirSync(this.sessionDir);
|
||||
}
|
||||
}
|
||||
async addFileUpdate(file) {
|
||||
// make sure file.path contains no path components
|
||||
if (file.path.match(/[\\\/]/)) {
|
||||
throw new Error(`Invalid file path: ${file.path}`);
|
||||
}
|
||||
await fs_1.default.promises.writeFile(path_1.default.join(this.sessionDir, file.path), file.data);
|
||||
}
|
||||
async build(step, platform) {
|
||||
// build config
|
||||
let platformID = platform || (0, util_1.getRootBasePlatform)(step.platform);
|
||||
let config = this.tool.platform_configs[platformID];
|
||||
if (!config) {
|
||||
throw new Error(`No config for platform ${platformID}`);
|
||||
}
|
||||
let defaultConfig = this.tool.platform_configs.default;
|
||||
if (!defaultConfig) {
|
||||
throw new Error(`No default config for tool ${this.tool.name}`);
|
||||
}
|
||||
config = Object.assign({}, defaultConfig, config); // combine configs
|
||||
// copy args
|
||||
let args = config.args.slice(0); //copy array
|
||||
let command = config.command;
|
||||
// replace $OUTFILE
|
||||
let outfile = path_1.default.join(this.sessionDir, 'a.out'); // TODO? a.out
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
args[i] = args[i].replace(/\$OUTFILE/g, outfile);
|
||||
args[i] = args[i].replace(/\$WORKDIR/g, this.sessionDir);
|
||||
}
|
||||
// replace $INFILES with the list of input files
|
||||
// TODO
|
||||
let infiles = [];
|
||||
for (let i = 0; i < step.files.length; i++) {
|
||||
let f = step.files[i];
|
||||
if (f.endsWith(this.tool.extensions[0])) {
|
||||
infiles.push(path_1.default.join(this.sessionDir, f));
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (args[i] === '$INFILES') {
|
||||
args = args.slice(0, i).concat(infiles).concat(args.slice(i + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (config.libargs) {
|
||||
args = args.concat(config.libargs);
|
||||
}
|
||||
console.log(`Running: ${command} ${args.join(' ')}`);
|
||||
// spawn after setting PATH env var
|
||||
// TODO
|
||||
let childProcess = (0, child_process_1.spawn)(command, args, {
|
||||
shell: true,
|
||||
cwd: this.rootdir,
|
||||
env: { PATH: path_1.default.join(this.rootdir, config.binpath)
|
||||
}
|
||||
});
|
||||
let outputData = '';
|
||||
let errorData = '';
|
||||
// TODO?
|
||||
childProcess.stdout.on('data', (data) => {
|
||||
outputData += data.toString();
|
||||
});
|
||||
childProcess.stderr.on('data', (data) => {
|
||||
errorData += data.toString();
|
||||
});
|
||||
return new Promise((resolve, reject) => {
|
||||
childProcess.on('close', async (code) => {
|
||||
if (code === 0) {
|
||||
if (platform === 'debug') {
|
||||
resolve(this.processDebugInfo(step));
|
||||
}
|
||||
else {
|
||||
resolve(this.processOutput(step));
|
||||
}
|
||||
}
|
||||
else {
|
||||
let errorResult = await this.processErrors(step, errorData);
|
||||
if (errorResult.errors.length === 0) {
|
||||
errorResult.errors.push({ line: 0, msg: `Build failed.\n\n${errorData}` });
|
||||
}
|
||||
resolve(errorResult);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
async processErrors(step, errorData) {
|
||||
let errors = [];
|
||||
// split errorData into lines
|
||||
let errorMatcher = (0, workermain_1.makeErrorMatcher)(errors, /([^:/]+):(\d+):(\d+):\s*(.+)/, 2, 4, step.path, 1);
|
||||
for (let line of errorData.split('\n')) {
|
||||
errorMatcher(line);
|
||||
}
|
||||
return { errors };
|
||||
}
|
||||
async processOutput(step) {
|
||||
let outfile = path_1.default.join(this.sessionDir, 'a.out');
|
||||
let output = await fs_1.default.promises.readFile(outfile, { encoding: 'base64' });
|
||||
return { output };
|
||||
}
|
||||
async processDebugInfo(step) {
|
||||
let dbgfile = path_1.default.join(this.sessionDir, 'debug.out');
|
||||
let dbglist = await fs_1.default.promises.readFile(dbgfile);
|
||||
let listings = (0, clang_1.parseObjDumpListing)(dbglist.toString());
|
||||
let symbolmap = (0, clang_1.parseObjDumpSymbolTable)(dbglist.toString());
|
||||
return { output: [], listings, symbolmap };
|
||||
}
|
||||
async compileAndLink(step, updates) {
|
||||
for (let file of updates) {
|
||||
await this.addFileUpdate(file);
|
||||
}
|
||||
try {
|
||||
let result = await this.build(step);
|
||||
// did we succeed?
|
||||
if ((0, workertypes_1.isOutputResult)(result)) {
|
||||
// do the debug info
|
||||
const debugInfo = await this.build(step, 'debug');
|
||||
if ((0, workertypes_1.isOutputResult)(debugInfo)) {
|
||||
result.listings = debugInfo.listings;
|
||||
result.symbolmap = debugInfo.symbolmap;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (err) {
|
||||
return { errors: [{ line: 0, msg: err.toString() }] };
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.ServerBuildEnv = ServerBuildEnv;
|
||||
//# sourceMappingURL=buildenv.js.map
|
1
gen/worker/server/buildenv.js.map
Normal file
1
gen/worker/server/buildenv.js.map
Normal file
File diff suppressed because one or more lines are too long
57
gen/worker/server/clang.js
Normal file
57
gen/worker/server/clang.js
Normal file
@ -0,0 +1,57 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.parseObjDumpListing = exports.parseObjDumpSymbolTable = void 0;
|
||||
const path_1 = __importDefault(require("path"));
|
||||
function parseObjDumpSymbolTable(symbolTable) {
|
||||
const lines = symbolTable.split('\n');
|
||||
const result = {};
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (line.startsWith('00')) {
|
||||
const parts = line.split(/\s+/);
|
||||
if (parts.length < 5)
|
||||
continue;
|
||||
const symbol = parts[parts.length - 1];
|
||||
const address = parseInt(parts[0], 16);
|
||||
result[symbol] = address;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
exports.parseObjDumpSymbolTable = parseObjDumpSymbolTable;
|
||||
function parseObjDumpListing(lst) {
|
||||
const lines = lst.split('\n');
|
||||
const result = {};
|
||||
var lastListing = null;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (line.startsWith(';')) {
|
||||
const fileInfoIndex = line.indexOf(':');
|
||||
if (fileInfoIndex !== -1) {
|
||||
const fileInfo = line.substring(1).trim();
|
||||
const fileParts = fileInfo.split(':');
|
||||
const file = path_1.default.basename(fileParts[0].trim()).split('.')[0] + '.lst';
|
||||
const lineNumber = parseInt(fileParts[1], 10);
|
||||
if (lineNumber > 0) {
|
||||
if (!result[file])
|
||||
result[file] = { lines: [], text: lst };
|
||||
lastListing = result[file];
|
||||
lastListing.lines.push({ line: lineNumber, offset: null });
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (lastListing && line.match(/^\s*[A-F0-9]+:.+/i)) {
|
||||
const offsetIndex = line.indexOf(':');
|
||||
if (offsetIndex !== -1) {
|
||||
const offset = parseInt(line.substring(0, offsetIndex).trim(), 16);
|
||||
lastListing.lines[lastListing.lines.length - 1].offset = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
exports.parseObjDumpListing = parseObjDumpListing;
|
||||
//# sourceMappingURL=clang.js.map
|
1
gen/worker/server/clang.js.map
Normal file
1
gen/worker/server/clang.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"clang.js","sourceRoot":"","sources":["../../../src/worker/server/clang.ts"],"names":[],"mappings":"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"}
|
65
gen/worker/server/server.js
Normal file
65
gen/worker/server/server.js
Normal file
@ -0,0 +1,65 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const path_1 = __importDefault(require("path"));
|
||||
const express_1 = __importDefault(require("express"));
|
||||
const cors_1 = __importDefault(require("cors"));
|
||||
const buildenv_1 = require("./buildenv");
|
||||
////////////////////
|
||||
const app = (0, express_1.default)();
|
||||
app.use((0, cors_1.default)());
|
||||
app.use(express_1.default.json({ limit: 1024 * 1024 })); // limit 1 MB
|
||||
app.get('/info', (req, res) => {
|
||||
// send a list of supported tools
|
||||
res.json({ tools: buildenv_1.TOOLS });
|
||||
});
|
||||
app.get('/test', async (req, res, next) => {
|
||||
// quick test of the build
|
||||
try {
|
||||
const updates = [{ path: 'test.c', data: 'int main() { return 0; }' }];
|
||||
const buildStep = { tool: 'llvm-mos', platform: 'c64', files: ['test.c'] };
|
||||
const env = new buildenv_1.ServerBuildEnv(SERVER_ROOT, 'test', buildenv_1.TOOLS[0]);
|
||||
const result = await env.compileAndLink(buildStep, updates);
|
||||
res.json(result);
|
||||
}
|
||||
catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
app.post('/build', async (req, res, next) => {
|
||||
try {
|
||||
const updates = req.body.updates;
|
||||
const buildStep = req.body.buildStep;
|
||||
const sessionID = req.body.sessionID;
|
||||
const bestTool = (0, buildenv_1.findBestTool)(buildStep);
|
||||
const env = new buildenv_1.ServerBuildEnv(SERVER_ROOT, sessionID, bestTool);
|
||||
const result = await env.compileAndLink(buildStep, updates);
|
||||
res.json(result);
|
||||
}
|
||||
catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// Catch errors
|
||||
app.use((err, req, res, next) => {
|
||||
console.error(err.stack);
|
||||
res.status(500).send('Something broke!');
|
||||
});
|
||||
// Start the server
|
||||
const port = 3009;
|
||||
/*{
|
||||
origin: [`http://localhost:${port}`, 'http://localhost:8000']
|
||||
}));*/
|
||||
const SERVER_ROOT = process.env['8BITWS_SERVER_ROOT'] || path_1.default.resolve('./server-root');
|
||||
const SESSION_ROOT = path_1.default.join(SERVER_ROOT, 'sessions');
|
||||
if (!fs_1.default.existsSync(SESSION_ROOT)) {
|
||||
fs_1.default.mkdirSync(SESSION_ROOT);
|
||||
}
|
||||
process.chdir(SESSION_ROOT);
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is listening on port ${port}`);
|
||||
});
|
||||
//# sourceMappingURL=server.js.map
|
1
gen/worker/server/server.js.map
Normal file
1
gen/worker/server/server.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/worker/server/server.ts"],"names":[],"mappings":"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"}
|
51
gen/worker/tools/remote.js
Normal file
51
gen/worker/tools/remote.js
Normal file
@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.buildRemote = void 0;
|
||||
const util_1 = require("../../common/util");
|
||||
const workertypes_1 = require("../../common/workertypes");
|
||||
const workermain_1 = require("../workermain");
|
||||
// TODO: are we running from 8bitworkshop.com in this worker?
|
||||
const REMOTE_URL = "http://localhost:3009/build";
|
||||
// create random UID
|
||||
const sessionID = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
||||
async function buildRemote(step) {
|
||||
(0, workermain_1.gatherFiles)(step); // TODO?
|
||||
var binpath = "a.out"; // TODO?
|
||||
if ((0, workermain_1.staleFiles)(step, [binpath])) {
|
||||
// grab files from store
|
||||
let updates = [];
|
||||
for (var i = 0; i < step.files.length; i++) {
|
||||
let path = step.files[i];
|
||||
let entry = workermain_1.store.workfs[path];
|
||||
// convert to base64
|
||||
let data = typeof entry.data === 'string' ? entry.data : btoa((0, util_1.byteArrayToString)(entry.data));
|
||||
updates.push({ path, data });
|
||||
}
|
||||
// build the command
|
||||
let cmd = { buildStep: step, updates, sessionID };
|
||||
// do a POST to the remote server, sending step as JSON
|
||||
console.log('POST', cmd);
|
||||
let result = await fetch(REMOTE_URL, {
|
||||
method: "POST",
|
||||
mode: "cors",
|
||||
body: JSON.stringify(cmd),
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
// return the result as JSON
|
||||
let json = await result.json();
|
||||
// parse the result as JSON
|
||||
if ((0, workertypes_1.isUnchanged)(json))
|
||||
return json;
|
||||
if ((0, workertypes_1.isErrorResult)(json))
|
||||
return json;
|
||||
if ((0, workertypes_1.isOutputResult)(json)) {
|
||||
json.output = (0, util_1.stringToByteArray)(atob(json.output));
|
||||
return json;
|
||||
}
|
||||
throw new Error(`Unexpected result from remote build: ${JSON.stringify(json)}`);
|
||||
}
|
||||
}
|
||||
exports.buildRemote = buildRemote;
|
||||
//# sourceMappingURL=remote.js.map
|
1
gen/worker/tools/remote.js.map
Normal file
1
gen/worker/tools/remote.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../../../src/worker/tools/remote.ts"],"names":[],"mappings":";;;AAAA,4CAAyE;AACzE,0DAAwG;AACxG,8CAA2F;AAE3F,6DAA6D;AAC7D,MAAM,UAAU,GAAG,6BAA6B,CAAC;AAEjD,oBAAoB;AACpB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAErG,KAAK,UAAU,WAAW,CAAC,IAAe;IAC7C,IAAA,wBAAW,EAAC,IAAI,CAAC,CAAC,CAAC,QAAQ;IAC3B,IAAI,OAAO,GAAG,OAAO,CAAC,CAAC,QAAQ;IAC/B,IAAI,IAAA,uBAAU,EAAC,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE;QAC7B,wBAAwB;QACxB,IAAI,OAAO,GAAwB,EAAE,CAAC;QACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACxC,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACzB,IAAI,KAAK,GAAG,kBAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC/B,oBAAoB;YACpB,IAAI,IAAI,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAA,wBAAiB,EAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAC7F,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;SAChC;QACD,oBAAoB;QACpB,IAAI,GAAG,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;QAClD,uDAAuD;QACvD,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACzB,IAAI,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE;YACjC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;YACzB,OAAO,EAAE;gBACL,cAAc,EAAE,kBAAkB;aACrC;SACJ,CAAC,CAAC;QACH,4BAA4B;QAC5B,IAAI,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAC/B,2BAA2B;QAC3B,IAAI,IAAA,yBAAW,EAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,IAAI,IAAA,2BAAa,EAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACrC,IAAI,IAAA,4BAAc,EAAC,IAAI,CAAC,EAAE;YACtB,IAAI,CAAC,MAAM,GAAG,IAAA,wBAAiB,EAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;SACf;QACD,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;KACnF;AACL,CAAC;AApCD,kCAoCC"}
|
@ -481,9 +481,14 @@ class Builder {
|
||||
while (this.steps.length) {
|
||||
var step = this.steps.shift(); // get top of array
|
||||
var platform = step.platform;
|
||||
var toolfn = TOOLS[step.tool];
|
||||
if (!toolfn)
|
||||
throw Error("no tool named " + step.tool);
|
||||
var [tool, remoteTool] = step.tool.split(':', 2);
|
||||
var toolfn = TOOLS[tool];
|
||||
if (!toolfn) {
|
||||
throw Error(`no tool named "${tool}"`);
|
||||
}
|
||||
if (remoteTool) {
|
||||
step.tool = remoteTool;
|
||||
}
|
||||
step.params = PLATFORM_PARAMS[(0, util_1.getBasePlatform)(platform)];
|
||||
try {
|
||||
step.result = await toolfn(step);
|
||||
@ -1108,6 +1113,7 @@ const z80 = __importStar(require("./tools/z80"));
|
||||
const x86 = __importStar(require("./tools/x86"));
|
||||
const arm = __importStar(require("./tools/arm"));
|
||||
const ecs = __importStar(require("./tools/ecs"));
|
||||
const remote = __importStar(require("./tools/remote"));
|
||||
var TOOLS = {
|
||||
'dasm': dasm.assembleDASM,
|
||||
//'acme': assembleACME,
|
||||
@ -1144,6 +1150,7 @@ var TOOLS = {
|
||||
'vasmarm': arm.assembleVASMARM,
|
||||
//'js': script.runJavascript,
|
||||
'ecs': ecs.assembleECS,
|
||||
'remote': remote.buildRemote
|
||||
};
|
||||
var TOOL_PRELOADFS = {
|
||||
'cc65-apple2': '65-apple2',
|
||||
|
File diff suppressed because one or more lines are too long
1207
package-lock.json
generated
1207
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
@ -30,6 +30,8 @@
|
||||
"octokat": "^0.10.0",
|
||||
"preact": "^10.5.14",
|
||||
"split.js": "^1.6.2",
|
||||
"atob": "^2.1.x",
|
||||
"btoa": "^1.2.x",
|
||||
"yufka": "^2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -40,11 +42,11 @@
|
||||
"@types/jquery": "^3.5.5",
|
||||
"@types/mocha": "^9.1.0",
|
||||
"@types/node": "^14.14.20",
|
||||
"atob": "^2.1.x",
|
||||
"bootstrap": "^3.4.1",
|
||||
"bootstrap-tourist": "^0.2.1",
|
||||
"btoa": "^1.2.x",
|
||||
"command-exists": "^1.2.9",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.2",
|
||||
"esbuild": "^0.12.29",
|
||||
"jsdom": "^21.1.0",
|
||||
"lzg": "^1.0.x",
|
||||
@ -62,14 +64,21 @@
|
||||
"rgbquant": "^1.1.2",
|
||||
"typedoc": "^0.22.11"
|
||||
},
|
||||
"overrides": {
|
||||
"fetch-vcr": {
|
||||
"node-fetch": "2.6.7"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "make prepare",
|
||||
"test": "npm run test-node",
|
||||
"tsbuild": "tsc --build tsconfig.json",
|
||||
"esbuild": "npm run esbuild-worker && npm run esbuild-ui",
|
||||
"esbuild-clean": "rm -f ./gen/*.*",
|
||||
"esbuild-server": "esbuild src/worker/server/server.ts --platform=node --bundle --sourcemap --target=es2020 --outfile=./gen/server/server.js",
|
||||
"esbuild-worker": "esbuild src/worker/workermain.ts --bundle --sourcemap --target=es2017 --outfile=./gen/worker/bundle.js",
|
||||
"esbuild-ui": "esbuild src/ide/ui.ts src/ide/embedui.ts --splitting --format=esm --bundle --minify --sourcemap --target=es2017 --outdir=./gen/ --external:path --external:fs",
|
||||
"server": "npm run esbuild-server && rm -fr ./server-root/sessions && node gen/server/server.js",
|
||||
"test-one": "NODE_PATH=$(pwd) mocha --recursive --timeout 60000",
|
||||
"test-node": "NODE_PATH=$(pwd) mocha --recursive --timeout 60000 test/cli gen/test",
|
||||
"test-profile": "NODE_PATH=$(pwd) mocha --recursive --timeout 60000 --prof test/cli gen/test",
|
||||
@ -97,7 +106,7 @@
|
||||
"build": {
|
||||
"appId": "com.8bitworkshop.ide",
|
||||
"icon": "meta/icons/8bitworkshop-icon-1024.png",
|
||||
"copyright": "Copyright (c) 2021 Puzzling Plans LLC",
|
||||
"copyright": "Copyright (c) 2023 Puzzling Plans LLC",
|
||||
"linux": {
|
||||
"category": "Development"
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ export class CodeProject {
|
||||
filename2path = {}; // map stripped paths to full paths
|
||||
filesystem : ProjectFilesystem;
|
||||
dataItems : WorkerItemUpdate[];
|
||||
remoteTool? : string;
|
||||
|
||||
callbackBuildResult : BuildResultCallback;
|
||||
callbackBuildStatus : BuildStatusCallback;
|
||||
@ -135,8 +136,16 @@ export class CodeProject {
|
||||
this.callbackBuildResult(data);
|
||||
}
|
||||
|
||||
getToolForFilename(path) {
|
||||
if (this.remoteTool) {
|
||||
return "remote:" + this.remoteTool;
|
||||
} else {
|
||||
return this.platform.getToolForFilename(path);
|
||||
}
|
||||
}
|
||||
|
||||
preloadWorker(path:string) {
|
||||
var tool = this.platform.getToolForFilename(path);
|
||||
var tool = this.getToolForFilename(path);
|
||||
if (tool && !this.tools_preloaded[tool]) {
|
||||
this.worker.postMessage({preload:tool, platform:this.platform_id});
|
||||
this.tools_preloaded[tool] = true;
|
||||
@ -277,7 +286,7 @@ export class CodeProject {
|
||||
path:mainfilename,
|
||||
files:[mainfilename].concat(depfiles),
|
||||
platform:this.platform_id,
|
||||
tool:this.platform.getToolForFilename(this.mainPath),
|
||||
tool:this.getToolForFilename(this.mainPath),
|
||||
mainfile:true});
|
||||
for (var dep of depends) {
|
||||
if (dep.data && dep.link) {
|
||||
@ -287,7 +296,7 @@ export class CodeProject {
|
||||
path:dep.filename,
|
||||
files:[dep.filename].concat(depfiles),
|
||||
platform:this.platform_id,
|
||||
tool:this.platform.getToolForFilename(dep.path)});
|
||||
tool:this.getToolForFilename(dep.path)});
|
||||
}
|
||||
}
|
||||
if (this.dataItems) msg.setitems = this.dataItems;
|
||||
|
@ -46,6 +46,7 @@ interface UIQueryString {
|
||||
file0_name? : string;
|
||||
file0_data? : string;
|
||||
file0_type? : string;
|
||||
tool?: string;
|
||||
}
|
||||
|
||||
export var qs : UIQueryString = decodeQueryString(window.location.search||'?') as UIQueryString;
|
||||
@ -252,6 +253,7 @@ async function newFilesystem() {
|
||||
async function initProject() {
|
||||
var filesystem = await newFilesystem();
|
||||
current_project = new CodeProject(newWorker(), platform_id, platform, filesystem);
|
||||
current_project.remoteTool = qs.tool || null;
|
||||
projectWindows = new ProjectWindows($("#workspace")[0] as HTMLElement, current_project);
|
||||
current_project.callbackBuildResult = (result:WorkerResult) => {
|
||||
setCompileOutput(result);
|
||||
|
@ -44,23 +44,38 @@ export class C64_WASMMachine extends BaseWASMMachine
|
||||
this.prgstart = this.romarr[0] + (this.romarr[1]<<8); // get load address
|
||||
// look for BASIC program start
|
||||
if (this.prgstart == 0x801) {
|
||||
this.prgstart = this.romarr[2] + (this.romarr[3]<<8) + 2; // point to after BASIC program
|
||||
console.log("prgstart", hex(this.prgstart));
|
||||
// decode SYS address from decimal?
|
||||
if (this.romarr[6] == 0x9e) {
|
||||
var addr = 0;
|
||||
for (var i=0; i<5; i++) {
|
||||
var ch = this.romarr[7+i];
|
||||
if (ch == 0x9b || ch == 0) break;
|
||||
addr = addr * 10 + (ch & 0xf);
|
||||
}
|
||||
this.prgstart = addr;
|
||||
console.log("SYS", addr, hex(addr));
|
||||
} else {
|
||||
this.prgstart = this.romarr[2] + (this.romarr[3]<<8) + 2; // point to after BASIC program
|
||||
console.log("RUN", this.prgstart, hex(this.prgstart));
|
||||
}
|
||||
}
|
||||
// is program loaded into RAM?
|
||||
if (this.prgstart < 0x8000) {
|
||||
// advance BIOS a few frames
|
||||
this.exports.machine_exec(this.sys, 250000);
|
||||
// type in command (SYS 2061)
|
||||
var cmd = "\rSYS "+this.prgstart+"\r";
|
||||
var cmd = "\rSYS "+this.prgstart;
|
||||
for (var i=0; i<cmd.length; i++) {
|
||||
var key = cmd.charCodeAt(i);
|
||||
this.exports.machine_exec(this.sys, 20000);
|
||||
this.exports.machine_exec(this.sys, 30000);
|
||||
this.exports.machine_key_down(this.sys, key);
|
||||
this.exports.machine_exec(this.sys, 5000);
|
||||
this.exports.machine_exec(this.sys, 30000);
|
||||
this.exports.machine_key_up(this.sys, key);
|
||||
this.exports.machine_exec(this.sys, 1); // chips/kbd.c has a "sticky counter"
|
||||
}
|
||||
// advance clock until program starts
|
||||
this.exports.machine_key_down(this.sys, 13);
|
||||
this.exports.machine_exec(this.sys, 1); // chips/kbd.c has a "sticky counter"
|
||||
for (var i=0; i<100000 && this.getPC() != this.prgstart; i++) {
|
||||
this.exports.machine_tick(this.sys);
|
||||
}
|
||||
|
224
src/worker/server/buildenv.ts
Normal file
224
src/worker/server/buildenv.ts
Normal file
@ -0,0 +1,224 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { spawn } from 'child_process';
|
||||
import { CodeListingMap, WorkerBuildStep, WorkerError, WorkerErrorResult, WorkerFileUpdate, WorkerResult, isOutputResult } from '../../common/workertypes';
|
||||
import { getBasePlatform, getRootBasePlatform } from '../../common/util';
|
||||
import { BuildStep, makeErrorMatcher } from '../workermain';
|
||||
import { parseObjDumpListing, parseObjDumpSymbolTable } from './clang';
|
||||
|
||||
|
||||
const LLVM_MOS_TOOL: ServerBuildTool = {
|
||||
name: 'llvm-mos',
|
||||
version: '',
|
||||
extensions: ['.c'],
|
||||
archs: ['6502'],
|
||||
platforms: ['atari8', 'c64', 'nes'],
|
||||
platform_configs: {
|
||||
default: {
|
||||
binpath: 'llvm-mos/bin',
|
||||
command: 'mos-clang',
|
||||
args: ['-Os', '-g', '-o', '$OUTFILE', '$INFILES'],
|
||||
},
|
||||
debug: { // TODO
|
||||
binpath: 'llvm-mos/bin',
|
||||
command: 'llvm-objdump',
|
||||
args: ['-l', '-t', '$WORKDIR/a.out.elf', '>$WORKDIR/debug.out']
|
||||
},
|
||||
c64: {
|
||||
command: 'mos-c64-clang',
|
||||
},
|
||||
atari8: {
|
||||
command: 'mos-atari8-clang',
|
||||
},
|
||||
nes: {
|
||||
command: 'mos-nes-nrom-clang', // TODO
|
||||
libargs: ['-lneslib']
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function findBestTool(step: BuildStep) {
|
||||
if (!step?.tool) throw new Error('No tool specified');
|
||||
const [name, version] = step.tool.split('@');
|
||||
for (let tool of TOOLS) {
|
||||
if (tool.name === name && (!version || version === 'latest' || tool.version === version)) {
|
||||
return tool;
|
||||
}
|
||||
}
|
||||
throw new Error(`Tool not found: ${step.tool}`);
|
||||
}
|
||||
|
||||
export const TOOLS: ServerBuildTool[] = [
|
||||
Object.assign({}, LLVM_MOS_TOOL, { version: '0.13.2' }),
|
||||
];
|
||||
|
||||
interface ServerBuildTool {
|
||||
name: string;
|
||||
version: string;
|
||||
extensions: string[];
|
||||
archs: string[];
|
||||
platforms: string[];
|
||||
platform_configs: { [platform: string]: ServerBuildToolPlatformConfig };
|
||||
}
|
||||
|
||||
interface ServerBuildToolPlatformConfig {
|
||||
binpath?: string;
|
||||
command?: string;
|
||||
args?: string[];
|
||||
libargs?: string[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class ServerBuildEnv {
|
||||
|
||||
rootdir: string;
|
||||
sessionID: string;
|
||||
tool: ServerBuildTool;
|
||||
sessionDir: string;
|
||||
|
||||
constructor(rootdir: string, sessionID: string, tool: ServerBuildTool) {
|
||||
this.rootdir = path.resolve(rootdir);
|
||||
this.sessionID = sessionID;
|
||||
this.tool = tool;
|
||||
// make sure sessionID is well-formed
|
||||
if (!sessionID.match(/^[a-zA-Z0-9_-]+$/)) {
|
||||
throw new Error(`Invalid sessionID: ${sessionID}`);
|
||||
}
|
||||
// create sessionID directory if it doesn't exist
|
||||
this.sessionDir = path.join(this.rootdir, 'sessions', sessionID);
|
||||
if (!fs.existsSync(this.sessionDir)) {
|
||||
fs.mkdirSync(this.sessionDir);
|
||||
}
|
||||
}
|
||||
|
||||
async addFileUpdate(file: WorkerFileUpdate) {
|
||||
// make sure file.path contains no path components
|
||||
if (file.path.match(/[\\\/]/)) {
|
||||
throw new Error(`Invalid file path: ${file.path}`);
|
||||
}
|
||||
await fs.promises.writeFile(path.join(this.sessionDir, file.path), file.data);
|
||||
}
|
||||
|
||||
async build(step: WorkerBuildStep, platform?: string): Promise<WorkerResult> {
|
||||
// build config
|
||||
let platformID = platform || getRootBasePlatform(step.platform);
|
||||
let config = this.tool.platform_configs[platformID];
|
||||
if (!config) {
|
||||
throw new Error(`No config for platform ${platformID}`);
|
||||
}
|
||||
let defaultConfig = this.tool.platform_configs.default;
|
||||
if (!defaultConfig) {
|
||||
throw new Error(`No default config for tool ${this.tool.name}`);
|
||||
}
|
||||
config = Object.assign({}, defaultConfig, config); // combine configs
|
||||
// copy args
|
||||
let args = config.args.slice(0); //copy array
|
||||
let command = config.command;
|
||||
// replace $OUTFILE
|
||||
let outfile = path.join(this.sessionDir, 'a.out'); // TODO? a.out
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
args[i] = args[i].replace(/\$OUTFILE/g, outfile);
|
||||
args[i] = args[i].replace(/\$WORKDIR/g, this.sessionDir);
|
||||
}
|
||||
// replace $INFILES with the list of input files
|
||||
// TODO
|
||||
let infiles = [];
|
||||
for (let i = 0; i < step.files.length; i++) {
|
||||
let f = step.files[i];
|
||||
if (f.endsWith(this.tool.extensions[0])) {
|
||||
infiles.push(path.join(this.sessionDir, f));
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (args[i] === '$INFILES') {
|
||||
args = args.slice(0, i).concat(infiles).concat(args.slice(i + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (config.libargs) {
|
||||
args = args.concat(config.libargs);
|
||||
}
|
||||
console.log(`Running: ${command} ${args.join(' ')}`);
|
||||
// spawn after setting PATH env var
|
||||
// TODO
|
||||
let childProcess = spawn(command, args, {
|
||||
shell: true,
|
||||
cwd: this.rootdir,
|
||||
env: { PATH: path.join(this.rootdir, config.binpath)
|
||||
} });
|
||||
let outputData = '';
|
||||
let errorData = '';
|
||||
// TODO?
|
||||
childProcess.stdout.on('data', (data) => {
|
||||
outputData += data.toString();
|
||||
});
|
||||
childProcess.stderr.on('data', (data) => {
|
||||
errorData += data.toString();
|
||||
});
|
||||
return new Promise((resolve, reject) => {
|
||||
childProcess.on('close', async (code) => {
|
||||
if (code === 0) {
|
||||
if (platform === 'debug') {
|
||||
resolve(this.processDebugInfo(step));
|
||||
} else {
|
||||
resolve(this.processOutput(step));
|
||||
}
|
||||
} else {
|
||||
let errorResult = await this.processErrors(step, errorData);
|
||||
if (errorResult.errors.length === 0) {
|
||||
errorResult.errors.push({ line: 0, msg: `Build failed.\n\n${errorData}` });
|
||||
}
|
||||
resolve(errorResult);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async processErrors(step: WorkerBuildStep, errorData: string): Promise<WorkerErrorResult> {
|
||||
let errors = [];
|
||||
// split errorData into lines
|
||||
let errorMatcher = makeErrorMatcher(errors, /([^:/]+):(\d+):(\d+):\s*(.+)/, 2, 4, step.path, 1);
|
||||
for (let line of errorData.split('\n')) {
|
||||
errorMatcher(line);
|
||||
}
|
||||
return { errors };
|
||||
}
|
||||
|
||||
async processOutput(step: WorkerBuildStep): Promise<WorkerResult> {
|
||||
let outfile = path.join(this.sessionDir, 'a.out');
|
||||
let output = await fs.promises.readFile(outfile, { encoding: 'base64' });
|
||||
return { output };
|
||||
}
|
||||
|
||||
async processDebugInfo(step: WorkerBuildStep): Promise<WorkerResult> {
|
||||
let dbgfile = path.join(this.sessionDir, 'debug.out');
|
||||
let dbglist = await fs.promises.readFile(dbgfile);
|
||||
let listings = parseObjDumpListing(dbglist.toString());
|
||||
let symbolmap = parseObjDumpSymbolTable(dbglist.toString());
|
||||
return { output: [], listings, symbolmap };
|
||||
}
|
||||
|
||||
async compileAndLink(step: WorkerBuildStep, updates: WorkerFileUpdate[]): Promise<WorkerResult> {
|
||||
for (let file of updates) {
|
||||
await this.addFileUpdate(file);
|
||||
}
|
||||
try {
|
||||
let result = await this.build(step);
|
||||
// did we succeed?
|
||||
if (isOutputResult(result)) {
|
||||
// do the debug info
|
||||
const debugInfo = await this.build(step, 'debug');
|
||||
if (isOutputResult(debugInfo)) {
|
||||
result.listings = debugInfo.listings;
|
||||
result.symbolmap = debugInfo.symbolmap;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (err) {
|
||||
return { errors: [{line:0, msg: err.toString()}] };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
49
src/worker/server/clang.ts
Normal file
49
src/worker/server/clang.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import path from 'path';
|
||||
import { CodeListing, CodeListingMap } from "../../common/workertypes";
|
||||
|
||||
export function parseObjDumpSymbolTable(symbolTable) {
|
||||
const lines = symbolTable.split('\n');
|
||||
const result = {};
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (line.startsWith('00')) {
|
||||
const parts = line.split(/\s+/);
|
||||
if (parts.length < 5) continue;
|
||||
const symbol = parts[parts.length-1];
|
||||
const address = parseInt(parts[0], 16);
|
||||
result[symbol] = address;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function parseObjDumpListing(lst: string): CodeListingMap {
|
||||
const lines = lst.split('\n');
|
||||
const result: CodeListingMap = {};
|
||||
var lastListing : CodeListing = null;
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (line.startsWith(';')) {
|
||||
const fileInfoIndex = line.indexOf(':');
|
||||
if (fileInfoIndex !== -1) {
|
||||
const fileInfo = line.substring(1).trim();
|
||||
const fileParts = fileInfo.split(':');
|
||||
const file = path.basename(fileParts[0].trim()).split('.')[0] + '.lst';
|
||||
const lineNumber = parseInt(fileParts[1], 10);
|
||||
if (lineNumber > 0) {
|
||||
if (!result[file]) result[file] = { lines: [], text: lst };
|
||||
lastListing = result[file];
|
||||
lastListing.lines.push({ line: lineNumber, offset: null });
|
||||
}
|
||||
}
|
||||
} else if (lastListing && line.match(/^\s*[A-F0-9]+:.+/i)) {
|
||||
const offsetIndex = line.indexOf(':');
|
||||
if (offsetIndex !== -1) {
|
||||
const offset = parseInt(line.substring(0, offsetIndex).trim(), 16);
|
||||
lastListing.lines[lastListing.lines.length - 1].offset = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
71
src/worker/server/server.ts
Normal file
71
src/worker/server/server.ts
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import express, { Request, Response } from 'express';
|
||||
import cors from 'cors';
|
||||
import { WorkerBuildStep, WorkerFileUpdate } from '../../common/workertypes';
|
||||
import { ServerBuildEnv, TOOLS, findBestTool } from './buildenv';
|
||||
|
||||
////////////////////
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(cors());
|
||||
|
||||
app.use(express.json({ limit: 1024*1024 })); // limit 1 MB
|
||||
|
||||
app.get('/info', (req: Request, res: Response) => {
|
||||
// send a list of supported tools
|
||||
res.json({ tools: TOOLS });
|
||||
});
|
||||
|
||||
app.get('/test', async (req: Request, res: Response, next) => {
|
||||
// quick test of the build
|
||||
try {
|
||||
const updates: WorkerFileUpdate[] = [{ path: 'test.c', data: 'int main() { return 0; }' }];
|
||||
const buildStep: WorkerBuildStep = { tool: 'llvm-mos', platform: 'c64', files: ['test.c'] };
|
||||
const env = new ServerBuildEnv(SERVER_ROOT, 'test', TOOLS[0]);
|
||||
const result = await env.compileAndLink(buildStep, updates);
|
||||
res.json(result);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/build', async (req: Request, res: Response, next) => {
|
||||
try {
|
||||
const updates: WorkerFileUpdate[] = req.body.updates;
|
||||
const buildStep: WorkerBuildStep = req.body.buildStep;
|
||||
const sessionID = req.body.sessionID;
|
||||
const bestTool = findBestTool(buildStep);
|
||||
const env = new ServerBuildEnv(SERVER_ROOT, sessionID, bestTool);
|
||||
const result = await env.compileAndLink(buildStep, updates);
|
||||
res.json(result);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// Catch errors
|
||||
app.use((err: Error, req: Request, res: Response, next: Function) => {
|
||||
console.error(err.stack);
|
||||
res.status(500).send('Something broke!');
|
||||
});
|
||||
|
||||
// Start the server
|
||||
const port = 3009;
|
||||
|
||||
/*{
|
||||
origin: [`http://localhost:${port}`, 'http://localhost:8000']
|
||||
}));*/
|
||||
|
||||
const SERVER_ROOT = process.env['8BITWS_SERVER_ROOT'] || path.resolve('./server-root');
|
||||
const SESSION_ROOT = path.join(SERVER_ROOT, 'sessions');
|
||||
if (!fs.existsSync(SESSION_ROOT)) {
|
||||
fs.mkdirSync(SESSION_ROOT);
|
||||
}
|
||||
process.chdir(SESSION_ROOT);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is listening on port ${port}`);
|
||||
});
|
47
src/worker/tools/remote.ts
Normal file
47
src/worker/tools/remote.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { byteArrayToString, stringToByteArray } from "../../common/util";
|
||||
import { WorkerFileUpdate, isErrorResult, isOutputResult, isUnchanged } from "../../common/workertypes";
|
||||
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, store } from "../workermain";
|
||||
|
||||
// TODO: are we running from 8bitworkshop.com in this worker?
|
||||
const REMOTE_URL = "http://localhost:3009/build";
|
||||
|
||||
// create random UID
|
||||
const sessionID = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
||||
|
||||
export async function buildRemote(step: BuildStep): Promise<BuildStepResult> {
|
||||
gatherFiles(step); // TODO?
|
||||
var binpath = "a.out"; // TODO?
|
||||
if (staleFiles(step, [binpath])) {
|
||||
// grab files from store
|
||||
let updates : WorkerFileUpdate[] = [];
|
||||
for (var i = 0; i < step.files.length; i++) {
|
||||
let path = step.files[i];
|
||||
let entry = store.workfs[path];
|
||||
// convert to base64
|
||||
let data = typeof entry.data === 'string' ? entry.data : btoa(byteArrayToString(entry.data));
|
||||
updates.push({ path, data });
|
||||
}
|
||||
// build the command
|
||||
let cmd = { buildStep: step, updates, sessionID };
|
||||
// do a POST to the remote server, sending step as JSON
|
||||
console.log('POST', cmd);
|
||||
let result = await fetch(REMOTE_URL, {
|
||||
method: "POST",
|
||||
mode: "cors",
|
||||
body: JSON.stringify(cmd),
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
// return the result as JSON
|
||||
let json = await result.json();
|
||||
// parse the result as JSON
|
||||
if (isUnchanged(json)) return json;
|
||||
if (isErrorResult(json)) return json;
|
||||
if (isOutputResult(json)) {
|
||||
json.output = stringToByteArray(atob(json.output));
|
||||
return json;
|
||||
}
|
||||
throw new Error(`Unexpected result from remote build: ${JSON.stringify(json)}`);
|
||||
}
|
||||
}
|
@ -516,8 +516,14 @@ class Builder {
|
||||
while (this.steps.length) {
|
||||
var step = this.steps.shift(); // get top of array
|
||||
var platform = step.platform;
|
||||
var toolfn = TOOLS[step.tool];
|
||||
if (!toolfn) throw Error("no tool named " + step.tool);
|
||||
var [tool, remoteTool] = step.tool.split(':', 2);
|
||||
var toolfn = TOOLS[tool];
|
||||
if (!toolfn) {
|
||||
throw Error(`no tool named "${tool}"`);
|
||||
}
|
||||
if (remoteTool) {
|
||||
step.tool = remoteTool;
|
||||
}
|
||||
step.params = PLATFORM_PARAMS[getBasePlatform(platform)];
|
||||
try {
|
||||
step.result = await toolfn(step);
|
||||
@ -1121,6 +1127,7 @@ import * as x86 from './tools/x86'
|
||||
import * as arm from './tools/arm'
|
||||
import * as script from './tools/script'
|
||||
import * as ecs from './tools/ecs'
|
||||
import * as remote from './tools/remote'
|
||||
|
||||
var TOOLS = {
|
||||
'dasm': dasm.assembleDASM,
|
||||
@ -1158,6 +1165,7 @@ var TOOLS = {
|
||||
'vasmarm': arm.assembleVASMARM,
|
||||
//'js': script.runJavascript,
|
||||
'ecs': ecs.assembleECS,
|
||||
'remote': remote.buildRemote
|
||||
}
|
||||
|
||||
var TOOL_PRELOADFS = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user