diff --git a/presets/verilog/cpu_platform.v b/presets/verilog/cpu_platform.v index b4b0ec7f..0d8dda6c 100644 --- a/presets/verilog/cpu_platform.v +++ b/presets/verilog/cpu_platform.v @@ -116,7 +116,7 @@ module cpu_platform(clk, reset, hsync, vsync, rgb); wire [15:0] cpu_bus; assign cpu_bus = cpu_ram_addr[15] - ? rom[cpu_ram_addr[9:0]] + ? program_rom[cpu_ram_addr[9:0]] : ram_read; CPU16 cpu( @@ -129,11 +129,11 @@ module cpu_platform(clk, reset, hsync, vsync, rgb); .data_out(ram_write), .write(ram_writeenable)); - reg [15:0] rom[0:1023]; + reg [15:0] program_rom[0:1023]; `ifdef EXT_INLINE_ASM initial begin - rom = '{ + program_rom = '{ __asm .arch femto16 .org 0x8000 @@ -160,7 +160,7 @@ InitPTLoop: rts ClearTiles: mov bx,@$6000 - mov cx,@$390 + mov cx,@$3c0 ClearLoop: mov [bx],ax inc bx diff --git a/src/platform/verilog.js b/src/platform/verilog.js index cfd07198..4e993179 100644 --- a/src/platform/verilog.js +++ b/src/platform/verilog.js @@ -581,23 +581,40 @@ var VerilogPlatform = function(mainElement, options) { this.loadROM = function(title, output) { var mod; - try { - mod = new Function('base', output.code); - } catch (e) { - this.printErrorCodeContext(e, output.code); - throw e; + if (output.code) { + try { + mod = new Function('base', output.code); + } catch (e) { + this.printErrorCodeContext(e, output.code); + throw e; + } + // compile Verilog code + var base = new VerilatorBase(); + gen = new mod(base); + gen.__proto__ = base; + current_output = output; + module_name = output.name ? output.name.substr(1) : "top"; + trace_ports = current_output.ports; + trace_signals = current_output.ports.concat(current_output.signals); + trace_index = 0; + // power on module + this.poweron(); + } else { + // TODO: :^P + output = {program_rom_variable: title, program_rom: output}; } - // compile Verilog code - var base = new VerilatorBase(); - gen = new mod(base); - gen.__proto__ = base; - current_output = output; - module_name = output.name ? output.name.substr(1) : "top"; - trace_ports = current_output.ports; - trace_signals = current_output.ports.concat(current_output.signals); - trace_index = 0; - // power on module - this.poweron(); + // replace program ROM, if using the assembler + if (output.program_rom && output.program_rom_variable) { + if (gen[output.program_rom_variable]) { + if (gen[output.program_rom_variable].length != output.program_rom.length) + alert("ROM size mismatch -- expected " + gen[output.program_rom_variable].length + " got " + output.program_rom.length); + else + gen[output.program_rom_variable] = output.program_rom; + } else { + alert("No program_rom variable found (" + output.program_rom_variable + ")"); + } + } + // restart audio restartAudio(); } @@ -661,7 +678,7 @@ var VerilogPlatform = function(mainElement, options) { } this.getToolForFilename = function(fn) { if (fn.endsWith("asm")) - return "caspr"; + return "jsasm"; else return "verilator"; } diff --git a/src/ui.js b/src/ui.js index b56da0e8..78121e96 100644 --- a/src/ui.js +++ b/src/ui.js @@ -143,6 +143,7 @@ var TOOL_TO_SOURCE_STYLE = { 'sdasz80': 'z80', 'sdcc': 'text/x-csrc', 'verilator': 'verilog', + 'jsasm': 'z80' } var worker = new Worker("./src/worker/workermain.js"); @@ -180,7 +181,7 @@ function scrollProfileView(_ed) { } function newEditor(mode) { - var isAsm = mode=='6502' || mode =='z80' || mode=='verilog'; // TODO + var isAsm = mode=='6502' || mode =='z80' || mode=='verilog' || mode=='gas'; // TODO editor = CodeMirror(document.getElementById('editor'), { theme: 'mbo', lineNumbers: true, @@ -419,13 +420,13 @@ function updateSelector() { function loadFileDependencies(text) { var arr = []; if (platform_id == 'verilog') { - var re = /`include\s+"(.+?)"/g; + var re = /^(`include|[.]include)\s+"(.+?)"/gm; var m; while (m = re.exec(text)) { arr.push({ - filename:m[1], + filename:m[2], prefix:platform_id, - text:store.loadFile(m[1]) || store.loadFile('local/'+m[1]) // TODO?? + text:store.loadFile(m[2]) || store.loadFile('local/'+m[2]) // TODO?? }); } } @@ -524,6 +525,9 @@ function setCompileOutput(data) { addErrorMarker(0, e+""); current_output = null; } + } else if (rom.program_rom_variable) { //TODO: a little wonky... + platform.loadROM(rom.program_rom_variable, rom.program_rom); + rom_changed = true; } if (rom_changed || trace_pending_at_pc) { // update editor annotations diff --git a/src/worker/assembler.js b/src/worker/assembler.js index 7f181173..2ac8275b 100644 --- a/src/worker/assembler.js +++ b/src/worker/assembler.js @@ -84,6 +84,9 @@ var Assembler = function(spec) { warning(msg, line); aborted = true; } + function fatalIf(msg, line) { + if (msg) fatal(msg, line); + } function hex(v, nd) { try { if (!nd) nd = 2; @@ -160,7 +163,7 @@ var Assembler = function(spec) { return {opcode:opcode, nbits:oplen}; } - function loadArch(arch) { + self.loadArch = function(arch) { if (self.loadFile) { var json = self.loadFile(arch + ".json"); if (json && json.vars && json.rules) { @@ -182,7 +185,11 @@ var Assembler = function(spec) { else if (tokens[0] == '.width') width = parseInt(tokens[1]); else if (tokens[0] == '.arch') - loadArch(tokens[1]); + fatalIf(self.loadArch(tokens[1])); + else if (tokens[0] == '.include') + fatalIf(self.loadInclude(tokens[1])); + else if (tokens[0] == '.module') + fatalIf(self.loadModule(tokens[1])); else warning("Unrecognized directive: " + tokens); } @@ -274,7 +281,8 @@ var Assembler = function(spec) { self.state = function() { return {ip:ip, line:linenum, origin:origin, codelen:codelen, - output:outwords, asmlines:asmlines, errors:errors, fixups:fixups}; + intermediate:{}, // TODO: listing, symbols? + output:outwords, lines:asmlines, errors:errors, fixups:fixups}; } } diff --git a/src/worker/workermain.js b/src/worker/workermain.js index 45fc0177..8573ef1a 100644 --- a/src/worker/workermain.js +++ b/src/worker/workermain.js @@ -1065,7 +1065,7 @@ function writeDependencies(depends, FS, errors, callback) { } if (callback) text = callback(d, text); - if (text) + if (text && FS) FS.writeFile(d.filename, text, {encoding:'utf8'}); } } @@ -1118,9 +1118,10 @@ function compileCASPR(code, platform, options) { } } -function compileASM(asmcode, platform, options) { +function compileJSASM(asmcode, platform, options, is_inline) { load("assembler"); var asm = new Assembler(); + var includes = []; asm.loadFile = function(filename) { // TODO: what if it comes from dependencies? var path = '../../presets/' + platform + '/' + filename; @@ -1130,14 +1131,41 @@ function compileASM(asmcode, platform, options) { xhr.send(null); return xhr.response; }; + asm.loadInclude = function(filename) { + if (!filename.startsWith('"') || !filename.endsWith('"')) + return 'Expected filename in "double quotes"'; + filename = filename.substr(1, filename.length-2); + includes.push(filename); + }; + var module_top; + var module_output; + asm.loadModule = function(top_module) { + // TODO: cache module + // compile last file in list + module_top = top_module; + var main_filename = includes[includes.length-1]; + var code = '`include "' + main_filename + '"\n'; + code += "/* module " + top_module + " */\n"; + var voutput = compileVerilator(code, platform, options); + if (voutput.errors.length) + return voutput.errors[0].msg; + module_output = voutput; + } var result = asm.assembleFile(asmcode); + if (module_output) { + var asmout = result.output; + result.output = module_output.output; + result.output.program_rom = asmout; + // cpu_platform__DOT__program_rom + result.output.program_rom_variable = module_top + "__DOT__program_rom"; + } return result; } function compileInlineASM(code, platform, options, errors, asmlines) { code = code.replace(/__asm\b([\s\S]+?)\b__endasm\b/g, function(s,asmcode,index) { var firstline = code.substr(0,index).match(/\n/g).length; - var asmout = compileASM(asmcode, platform, options); + var asmout = compileJSASM(asmcode, platform, options, true); if (asmout.errors && asmout.errors.length) { for (var i=0; i