diff --git a/doc/compilers.txt b/doc/compilers.txt new file mode 100644 index 00000000..286e4283 --- /dev/null +++ b/doc/compilers.txt @@ -0,0 +1,56 @@ + +cc65 - A fairly mature C compiler + toolchain for the 6502 family with lots of target +platforms and an extensive library. The code generation is +not great, using the AX register pair and a parameter stack for local variables that has to be +indirect-indexed (you can make locals static with an option, but I found +this introduced compiler bugs.) + +LCC - A small retargetable C compiler released in 1994, most notoriously +used to compile bytecode for the QuakeC language. It doesn't generate 6502 +code, but it probably could -- although optimizations are weak. +There's an older port to the 65C816. + +ACK - This ancient compiler used for Minix has a lot of frontends and backends, and is designed +for small-register CISC CPUs. There's a 6500 backend but I couldn't get it +working. Looks like it could be resurrected though. There's an intermediate +file for each step of the pipeline. + +PCC - An early C compiler from the days of UNIX, now updated to C99. +There's a 16-bit target (x86) and the backends looks pretty simple. +http://pcc.ludd.ltu.se/internals/pass2/ + +SDCC - A mature compiler that supports lots of microcontrollers including +the Z80. This is probably the best candidate for porting to 6502, +but the backends are bespoke works of evil genius and there's precious little documentation. +(I wonder if you could post-process the HC08 output to 6502, since they're similar in some ways.) + +LLVM-6502 - Someone uploaded this to Github. I got it to build, but the code +generated wasn't comprehensible. + +osXdk - A fork of the Oric SDK. The C compiler has a weird design which +emits bytecode and then uses a C preprocessor to expand the macros +into 6502 assembler. + +PLASMA - Language + VM, sort of like SWEET16 meets +Java. Simple, concise code base. Pretty fast too, in the same ballpark as +CC65. Focused on the Apple I/II/III family. + +Atalan - Rule-based language/assembler with support for multiple 8-bit +platforms. Looks promising, but I had problems with it crashing, and it +lacks documentation/test cases. Atari-focused. + +Macross/Slinky - A macro cross-assembler developed by Chip Morningstar at +Lucasfilm Ltd. for use in the game Habitat. Billed as "An assembler for +people who hate assembly language." + +NESHLA - A high-level assembler in the same spirit as Macross, but with +NES-specific features. + +WLA-DX - Some other weird cross-assembler with lots of CPU targets. + +z88dk - A Small C-derived cross-compiler for the Z80, supporting 20 target +machines. + +SWEET16 - Woz's tiny bytecode interpreter on the Apple ][ integer BASIC ROM. +Still emcumbered by Apple's copyright for the foreseeable future. +http://6502.org/source/interpreters/sweet16.htm diff --git a/package.json b/package.json index f774b1b0..a19a8dba 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,30 @@ { - "name": "RetroConsole", + "name": "8bitworkshop", "version": "0.0.1", "author": "Steven Hugg", - "dependencies": { - }, + "dependencies": {}, "devDependencies": { - "browserify": "^13.0.0" - } + "mocha": "^3.2.0" + }, + "description": "8bitworkshop.com", + "main": "main.js", + "directories": { + "doc": "doc", + "test": "tests" + }, + "scripts": { + "test": "mocha" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/sehugg/8bitworkshop.git" + }, + "keywords": [ + "8bit" + ], + "license": "GPL-3.0", + "bugs": { + "url": "https://github.com/sehugg/8bitworkshop/issues" + }, + "homepage": "https://github.com/sehugg/8bitworkshop#readme" } diff --git a/src/emu.js b/src/emu.js index 96ffc034..a8d8aa79 100644 --- a/src/emu.js +++ b/src/emu.js @@ -319,7 +319,6 @@ var Base6502Platform = function() { var debugBreakState = null; var debugTargetClock = 0; var debugClock = 0; - var debugFrameStartClock = 0; this.setDebugCondition = function(debugCond) { if (debugSavedState) { @@ -331,6 +330,13 @@ var Base6502Platform = function() { debugCondition = debugCond; this.resume(); } + this.restartDebugState = function() { + if (debugCondition && !debugBreakState) { + debugSavedState = this.saveState(); + debugTargetClock -= debugClock; + debugClock = 0; + } + } this.getDebugCallback = function() { return debugCondition; } @@ -341,7 +347,6 @@ var Base6502Platform = function() { debugSavedState = null; debugTargetClock = 0; debugClock = 0; - debugFrameStartClock = 0; onBreakpointHit = null; debugCondition = null; } @@ -354,6 +359,7 @@ var Base6502Platform = function() { onBreakpointHit(debugBreakState); } } + // TODO: lower bound of clock value this.step = function() { var self = this; var previousPC = -1; diff --git a/src/platform/apple2.js b/src/platform/apple2.js index 4d038c1c..705d52f2 100644 --- a/src/platform/apple2.js +++ b/src/platform/apple2.js @@ -175,7 +175,7 @@ var Apple2Platform = function(mainElement) { ap2disp.updateScreen(); video.updateFrame(); soundstate = 0; // to prevent clicking - // TODO: reset debug state + self.restartDebugState(); // reset debug start state }); } diff --git a/src/platform/atarivec.js b/src/platform/atarivec.js index 26f90b74..61b70fbb 100644 --- a/src/platform/atarivec.js +++ b/src/platform/atarivec.js @@ -87,6 +87,7 @@ var AtariVectorPlatform = function(mainElement) { cpu.clockPulse(); //cpu.executeInstruction(); } + self.restartDebugState(); }); video.setKeyboardEvents(function(key,code,flags) { var KEY2ADDR = { diff --git a/src/worker/workermain.js b/src/worker/workermain.js index b46cf30c..1c89ccf8 100644 --- a/src/worker/workermain.js +++ b/src/worker/workermain.js @@ -36,7 +36,7 @@ var fsMeta, fsBlob; xhr.open("GET", "fs65.js.metadata", false); // synchronous request xhr.send(null); fsMeta = xhr.response; - console.log("Loaded filesystem", fsMeta.files.length, 'files', fsBlob.size, 'bytes'); + console.log("Loaded filesystem", fsMeta.files.length, 'files', fsBlob.size||fsBlob.length, 'bytes'); } // mount the filesystem at /share @@ -339,9 +339,10 @@ var tools = { onmessage = function(e) { var code = e.data.code; + var platform = e.data.platform; var toolfn = tools[e.data.tool]; if (!toolfn) throw "no tool named " + e.data.tool; - var result = toolfn(code); + var result = toolfn(code, platform); if (result) { postMessage(result); } diff --git a/test/worker.js b/test/worker.js new file mode 100644 index 00000000..d748454b --- /dev/null +++ b/test/worker.js @@ -0,0 +1,66 @@ + +var assert = require('assert'); +var fs = require('fs'); +var vm = require('vm'); +var worker = {}; + +var includeInThisContext = function(path) { + var code = fs.readFileSync(path); + vm.runInThisContext(code, path); +}; + +global.importScripts = function(path) { + includeInThisContext('src/worker/'+path); +} + +global.XMLHttpRequest = function() { + var txt; + this.open = function(a,b,c) { + txt = fs.readFileSync('src/worker/'+b); + if (this.responseType == 'json') { + this.response = JSON.parse(txt); + } else if (this.responseType == 'blob') { + this.response = txt; //new Uint8Array(txt); + //console.log(this.response.slice(0,100)); + } + } + this.send = function() { } +} + +global.FileReaderSync = function() { + this.readAsArrayBuffer = function(blob) { + return blob.slice(0); + } +} + +global.onmessage = null; +global.postMessage = null; + +includeInThisContext("src/worker/workermain.js"); + +function compile(tool, code, callback, outlen) { + global.postMessage = function(msg) { + //console.log(msg); + assert.ok(msg.listing.lines); + assert.equal(msg.listing.errors.length, msg.listing.errors); + assert.equal(msg.output.length, outlen); + callback(null, msg); + }; + global.onmessage({ + data:{code:code, tool:tool} + }); +} + +describe('Worker', function() { + it('should compile DASM', function(done) { + compile('dasm', '\tprocessor 6502\n\torg $f000\nfoo lda #0\n', done, 2); + }); + it('should compile PLASMA', function(done) { + compile('plasm', 'word x = 0', done, 5); + }); + /* + it('should compile CC65', function(done) { + compile('cc65', '#include \nint main() {\nint x=1;\nreturn x+2;\n}', done, 5); + }); + */ +});