diff --git a/doc/notes.txt b/doc/notes.txt index eb3459c6..9bfd6e1f 100644 --- a/doc/notes.txt +++ b/doc/notes.txt @@ -196,6 +196,7 @@ TODO: - BIOS symbols - show current tool for file - download non-text incbin source file +- show hidden header files that only exist in Emscripten FS Probing - probe log doesn't start @ reset diff --git a/index.html b/index.html index e0fab422..a8f0c0fd 100644 --- a/index.html +++ b/index.html @@ -539,6 +539,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) { + diff --git a/presets/msx/hello.wiz b/presets/msx/hello.wiz new file mode 100644 index 00000000..ca1351ac --- /dev/null +++ b/presets/msx/hello.wiz @@ -0,0 +1,144 @@ +import "msx"; + +bank rom1 @ 0x4000 : [constdata; 0x4000]; +bank rom2 @ 0x8000 : [constdata; 0x4000]; +bank ram @ 0xE000 : [vardata; 0x2000]; + +in ram { + struct Word { + low : u8, + high : u8, + } + + struct Enemy { + hp : Word + } + + var enemy_data : [Enemy; 32]; +} + +in rom1 { + namespace header { + const id = "AB"; + const init_handler = main; + const statement_handler = 0u16; + const expansion_handler = 0u16; + const basic_start = 0u16; + const padding = [0u8; 6]; + } + + #[fallthrough] func main() { + interrupt = false; + + io_write(msx.io.ppi.primary_slot, a = 0b11_01_01_00); + msx.ppi.secondary_slot = a = 0b11_11_11_11; + + // Init VDP. + c = msx.io.vdp.control; + hl = &vdp_init_data as u16; + b = vdp_init_data.len; + do { io_write_inc_repeat(c, hl, b); } while !zero; + + { + var enemy_ptr : *Enemy in ix; + enemy_ptr.hp.low = 1; + enemy_ptr.hp.high = 1; + + bc = sizeof(Enemy); + <>:enemy_ptr += bc; + } + + // Clear VRAM. + io_write(msx.io.vdp.control, a = <:0x0000); + io_write(msx.io.vdp.control, a = >:0x0000 | msx.io.vdp.CONTROL_ACCESS_VRAM_WRITE); + bc = 0x4000; + do { + io_write(msx.io.vdp.data, a = 0); + bc--; + a = b | c; + } while !zero; + + // Load background colormap. + io_write(msx.io.vdp.control, a = <:0x2000); + io_write(msx.io.vdp.control, a = >:0x2000 | msx.io.vdp.CONTROL_ACCESS_VRAM_WRITE); + bc = 0x1800; + do { + io_write(msx.io.vdp.data, a = (msx.vdp.color.WHITE << 4) | msx.vdp.color.LIGHT_BLUE); + bc--; + a = b | c; + } while !zero; + + // Load background tileset. + io_write(msx.io.vdp.control, a = <:0x0000); + io_write(msx.io.vdp.control, a = >:0x0000 | msx.io.vdp.CONTROL_ACCESS_VRAM_WRITE); + hl = &bkg_tileset as u16; + bc = sizeof(typeof(bkg_tileset)); + do { + io_write(msx.io.vdp.data, a = *(hl as *u8)); + hl++; + bc--; + a = b | c; + } while !zero; + + io_write(msx.io.vdp.control, a = <:0x0800); + io_write(msx.io.vdp.control, a = >:0x0800 | msx.io.vdp.CONTROL_ACCESS_VRAM_WRITE); + hl = &bkg_tileset as u16; + bc = sizeof(typeof(bkg_tileset)); + do { + io_write(msx.io.vdp.data, a = *(hl as *u8)); + hl++; + bc--; + a = b | c; + } while !zero; + + io_write(msx.io.vdp.control, a = <:0x1000); + io_write(msx.io.vdp.control, a = >:0x1000 | msx.io.vdp.CONTROL_ACCESS_VRAM_WRITE); + hl = &bkg_tileset as u16; + bc = sizeof(typeof(bkg_tileset)); + do { + io_write(msx.io.vdp.data, a = *(hl as *u8)); + hl++; + bc--; + a = b | c; + } while !zero; + + // Write text to nametable. + io_write(msx.io.vdp.control, a = <:0x190A); + io_write(msx.io.vdp.control, a = >:0x190A | msx.io.vdp.CONTROL_ACCESS_VRAM_WRITE); + hl = &message as u16; + bc = message.len; + do { + io_write(msx.io.vdp.data, a = *(hl as *u8)); + hl++; + bc--; + a = b | c; + } while !zero; + + // Turn screen on + io_write(msx.io.vdp.control, a = msx.vdp.MODE_CONTROL_1_ENABLE); + io_write(msx.io.vdp.control, a = msx.vdp.mode_control_1 | msx.io.vdp.CONTROL_ACCESS_REGISTER); + + interrupt = true; + + while true { + halt(); + } + } + + const vdp_init_data : [u8] = [ + msx.vdp.MODE_CONTROL_0_M4, msx.vdp.mode_control_0 | msx.io.vdp.CONTROL_ACCESS_REGISTER, + 0, msx.vdp.mode_control_1 | msx.io.vdp.CONTROL_ACCESS_REGISTER, + 0x1800 >> msx.vdp.NAMETABLE_ADDRESS_SHIFT, msx.vdp.nametable_address | msx.io.vdp.CONTROL_ACCESS_REGISTER, + 0x2000 >> msx.vdp.COLORTABLE_ADDRESS_SHIFT, msx.vdp.colortable_address | msx.io.vdp.CONTROL_ACCESS_REGISTER, + 0x0000 >> msx.vdp.TILE_PATTERN_ADDRESS_SHIFT, msx.vdp.tile_pattern_address | msx.io.vdp.CONTROL_ACCESS_REGISTER, + 0x1B00 >> msx.vdp.SPRITE_ATTRIBUTE_ADDRESS_SHIFT, msx.vdp.sprite_attribute_address | msx.io.vdp.CONTROL_ACCESS_REGISTER, + 0x3800 >> msx.vdp.SPRITE_PATTERN_ADDRESS_SHIFT, msx.vdp.sprite_pattern_address | msx.io.vdp.CONTROL_ACCESS_REGISTER, + msx.vdp.color.BLACK, msx.vdp.overscan_color | msx.io.vdp.CONTROL_ACCESS_REGISTER, + ]; + + const message = "HELLO WORLD"; +} + +in rom2 { + const bkg_tileset = embed "hello_tiles.chr"; +} diff --git a/src/codemirror/wiz.js b/src/codemirror/wiz.js new file mode 100644 index 00000000..8a7378e3 --- /dev/null +++ b/src/codemirror/wiz.js @@ -0,0 +1,447 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +function Context(indented, column, type, info, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.info = info; + this.align = align; + this.prev = prev; +} +function pushContext(state, col, type, info) { + var indent = state.indented; + if (state.context && state.context.type == "statement" && type != "statement") + indent = state.context.indented; + return state.context = new Context(indent, col, type, info, null, state.context); +} +function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; +} + +function typeBefore(stream, state, pos) { + if (state.prevToken == "variable" || state.prevToken == "type") return true; + if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, pos))) return true; + if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true; +} + +function isTopScope(context) { + for (;;) { + if (!context || context.type == "top") return true; + if (context.type == "}" && context.prev.info != "namespace") return false; + context = context.prev; + } +} + +CodeMirror.defineMode("clike", function(config, parserConfig) { + var indentUnit = config.indentUnit, + statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, + dontAlignCalls = parserConfig.dontAlignCalls, + keywords = parserConfig.keywords || {}, + types = parserConfig.types || {}, + builtin = parserConfig.builtin || {}, + blockKeywords = parserConfig.blockKeywords || {}, + defKeywords = parserConfig.defKeywords || {}, + atoms = parserConfig.atoms || {}, + hooks = parserConfig.hooks || {}, + multiLineStrings = parserConfig.multiLineStrings, + indentStatements = parserConfig.indentStatements !== false, + indentSwitch = parserConfig.indentSwitch !== false, + namespaceSeparator = parserConfig.namespaceSeparator, + isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/, + numberStart = parserConfig.numberStart || /[\d\.]/, + number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i, + isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/, + isIdentifierChar = parserConfig.isIdentifierChar || /[\w\$_\xa1-\uffff]/, + // An optional function that takes a {string} token and returns true if it + // should be treated as a builtin. + isReservedIdentifier = parserConfig.isReservedIdentifier || false; + + var curPunc, isDefKeyword; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (isPunctuationChar.test(ch)) { + curPunc = ch; + return null; + } + if (numberStart.test(ch)) { + stream.backUp(1) + if (stream.match(number)) return "number" + stream.next() + } + if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {} + return "operator"; + } + stream.eatWhile(isIdentifierChar); + if (namespaceSeparator) while (stream.match(namespaceSeparator)) + stream.eatWhile(isIdentifierChar); + + var cur = stream.current(); + if (contains(keywords, cur)) { + if (contains(blockKeywords, cur)) curPunc = "newstatement"; + if (contains(defKeywords, cur)) isDefKeyword = true; + return "keyword"; + } + if (contains(types, cur)) return "type"; + if (contains(builtin, cur) + || (isReservedIdentifier && isReservedIdentifier(cur))) { + if (contains(blockKeywords, cur)) curPunc = "newstatement"; + return "builtin"; + } + if (contains(atoms, cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = null; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function maybeEOL(stream, state) { + if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context)) + state.typeAtEndOfLine = typeBefore(stream, state, stream.pos) + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", null, false), + indented: 0, + startOfLine: true, + prevToken: null + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) { maybeEOL(stream, state); return null; } + curPunc = isDefKeyword = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + if (ctx.align == null) ctx.align = true; + + if (curPunc == ";" || curPunc == ":" || (curPunc == "," && stream.match(/^\s*(?:\/\/.*)?$/, false))) + while (state.context.type == "statement") popContext(state); + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (indentStatements && + (((ctx.type == "}" || ctx.type == "top") && curPunc != ";") || + (ctx.type == "statement" && curPunc == "newstatement"))) { + pushContext(state, stream.column(), "statement", stream.current()); + } + + if (style == "variable" && + ((state.prevToken == "def" || + (parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) && + isTopScope(state.context) && stream.match(/^\s*\(/, false))))) + style = "def"; + + if (hooks.token) { + var result = hooks.token(stream, state, style); + if (result !== undefined) style = result; + } + + if (style == "def" && parserConfig.styleDefs === false) style = "variable"; + + state.startOfLine = false; + state.prevToken = isDefKeyword ? "def" : style || curPunc; + maybeEOL(stream, state); + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass; + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + var closing = firstChar == ctx.type; + if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; + if (parserConfig.dontIndentStatements) + while (ctx.type == "statement" && parserConfig.dontIndentStatements.test(ctx.info)) + ctx = ctx.prev + if (hooks.indent) { + var hook = hooks.indent(state, ctx, textAfter, indentUnit); + if (typeof hook == "number") return hook + } + var switchBlock = ctx.prev && ctx.prev.info == "switch"; + if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) { + while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev + return ctx.indented + } + if (ctx.type == "statement") + return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); + if (ctx.align && (!dontAlignCalls || ctx.type != ")")) + return ctx.column + (closing ? 0 : 1); + if (ctx.type == ")" && !closing) + return ctx.indented + statementIndentUnit; + + return ctx.indented + (closing ? 0 : indentUnit) + + (!closing && switchBlock && !/^(?:case|default)\b/.test(textAfter) ? indentUnit : 0); + }, + + electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/, + blockCommentStart: "/*", + blockCommentEnd: "*/", + blockCommentContinue: " * ", + lineComment: "//", + fold: "brace" + }; +}); + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + function contains(words, word) { + if (typeof words === "function") { + return words(word); + } else { + return words.propertyIsEnumerable(word); + } + } + var cKeywords = "auto if break case register continue return default do sizeof " + + "static else struct switch extern typedef union for goto while enum const " + + "volatile inline restrict asm fortran"; + + // Keywords from https://en.cppreference.com/w/cpp/keyword includes C++20. + var cppKeywords = "alignas alignof and and_eq audit axiom bitand bitor catch " + + "class compl concept constexpr const_cast decltype delete dynamic_cast " + + "explicit export final friend import module mutable namespace new noexcept " + + "not not_eq operator or or_eq override private protected public " + + "reinterpret_cast requires static_assert static_cast template this " + + "thread_local throw try typeid typename using virtual xor xor_eq"; + + var objCKeywords = "bycopy byref in inout oneway out self super atomic nonatomic retain copy " + + "readwrite readonly strong weak assign typeof nullable nonnull null_resettable _cmd " + + "@interface @implementation @end @protocol @encode @property @synthesize @dynamic @class " + + "@public @package @private @protected @required @optional @try @catch @finally @import " + + "@selector @encode @defs @synchronized @autoreleasepool @compatibility_alias @available"; + + var objCBuiltins = "FOUNDATION_EXPORT FOUNDATION_EXTERN NS_INLINE NS_FORMAT_FUNCTION " + + " NS_RETURNS_RETAINEDNS_ERROR_ENUM NS_RETURNS_NOT_RETAINED NS_RETURNS_INNER_POINTER " + + "NS_DESIGNATED_INITIALIZER NS_ENUM NS_OPTIONS NS_REQUIRES_NIL_TERMINATION " + + "NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_SWIFT_NAME NS_REFINED_FOR_SWIFT" + + // Do not use this. Use the cTypes function below. This is global just to avoid + // excessive calls when cTypes is being called multiple times during a parse. + var basicCTypes = words("int long char short double float unsigned signed " + + "void bool"); + + // Do not use this. Use the objCTypes function below. This is global just to avoid + // excessive calls when objCTypes is being called multiple times during a parse. + var basicObjCTypes = words("SEL instancetype id Class Protocol BOOL"); + + // Returns true if identifier is a "C" type. + // C type is defined as those that are reserved by the compiler (basicTypes), + // and those that end in _t (Reserved by POSIX for types) + // http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html + function cTypes(identifier) { + return contains(basicCTypes, identifier) || /.+_t$/.test(identifier); + } + + // Returns true if identifier is a "Objective C" type. + function objCTypes(identifier) { + return cTypes(identifier) || contains(basicObjCTypes, identifier); + } + + var cBlockKeywords = "case do else for if switch while struct enum union"; + var cDefKeywords = "struct enum union"; + + function cppHook(stream, state) { + if (!state.startOfLine) return false + for (var ch, next = null; ch = stream.peek();) { + if (ch == "\\" && stream.match(/^.$/)) { + next = cppHook + break + } else if (ch == "/" && stream.match(/^\/[\/\*]/, false)) { + break + } + stream.next() + } + state.tokenize = next + return "meta" + } + + function pointerHook(_stream, state) { + if (state.prevToken == "type") return "type"; + return false; + } + + // For C and C++ (and ObjC): identifiers starting with __ + // or _ followed by a capital letter are reserved for the compiler. + function cIsReservedIdentifier(token) { + if (!token || token.length < 2) return false; + if (token[0] != '_') return false; + return (token[1] == '_') || (token[1] !== token[1].toLowerCase()); + } + + function cpp14Literal(stream) { + stream.eatWhile(/[\w\.']/); + return "number"; + } + + function cpp11StringHook(stream, state) { + stream.backUp(1); + // Raw strings. + if (stream.match(/(R|u8R|uR|UR|LR)/)) { + var match = stream.match(/"([^\s\\()]{0,16})\(/); + if (!match) { + return false; + } + state.cpp11RawStringDelim = match[1]; + state.tokenize = tokenRawString; + return tokenRawString(stream, state); + } + // Unicode strings/chars. + if (stream.match(/(u8|u|U|L)/)) { + if (stream.match(/["']/, /* eat */ false)) { + return "string"; + } + return false; + } + // Ignore this hook. + stream.next(); + return false; + } + + function cppLooksLikeConstructor(word) { + var lastTwo = /(\w+)::~?(\w+)$/.exec(word); + return lastTwo && lastTwo[1] == lastTwo[2]; + } + + // C#-style strings where "" escapes a quote. + function tokenAtString(stream, state) { + var next; + while ((next = stream.next()) != null) { + if (next == '"' && !stream.eat('"')) { + state.tokenize = null; + break; + } + } + return "string"; + } + + // C++11 raw string literal is "( anything )", where + // can be a string up to 16 characters long. + function tokenRawString(stream, state) { + // Escape characters that have special regex meanings. + var delim = state.cpp11RawStringDelim.replace(/[^\w\s]/g, '\\$&'); + var match = stream.match(new RegExp(".*?\\)" + delim + '"')); + if (match) + state.tokenize = null; + else + stream.skipToEnd(); + return "string"; + } + + function def(mimes, mode) { + if (typeof mimes == "string") mimes = [mimes]; + var words = []; + function add(obj) { + if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop)) + words.push(prop); + } + add(mode.keywords); + add(mode.types); + add(mode.builtin); + add(mode.atoms); + if (words.length) { + mode.helperType = mimes[0]; + CodeMirror.registerHelper("hintWords", mimes[0], words); + } + + for (var i = 0; i < mimes.length; ++i) + CodeMirror.defineMIME(mimes[i], mode); + } + + def("text/x-wiz", { + name: "clike", + keywords: words("u8 u16 u24 u32 u64 i8 i16 i24 i32 i64 bool iexpr " + + "vardata prgdata constdata chrdata varinitdata " + + "do else for if switch while in import embed bank config goto return by break continue " + + "zero carry negative overflow decimal nointerrupt push pop nop halt stop bit cmp " + + "var let const namespace func inline struct union enum typealias " + + "sizeof as compile_if"), + types: words("u8 u16 u24 u32 u64 i8 i16 i24 i32 i64 bool iexpr"), + blockKeywords: words("do else for if switch while"), + defKeywords: words("bank func namespace in const struct union enum typealias"), + typeFirstDefinitions: true, + atoms: words("true false null"), + number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i, + hooks: { + "#": function(stream) { + stream.eatWhile(/\S/); + return "meta"; + } + }, + modeProps: {fold: ["brace", "import"]} + }); + +}); diff --git a/src/common/baseplatform.ts b/src/common/baseplatform.ts index d05f43e4..995d99c3 100644 --- a/src/common/baseplatform.ts +++ b/src/common/baseplatform.ts @@ -587,7 +587,7 @@ export abstract class BaseZ80Platform extends BaseDebugPlatform { } } -export function getToolForFilename_z80(fn) : string { +export function getToolForFilename_z80(fn:string) : string { if (fn.endsWith(".c")) return "sdcc"; if (fn.endsWith(".h")) return "sdcc"; if (fn.endsWith(".s")) return "sdasz80"; diff --git a/src/ide/project.ts b/src/ide/project.ts index 4a103684..e24c54fd 100644 --- a/src/ide/project.ts +++ b/src/ide/project.ts @@ -120,9 +120,9 @@ export class CodeProject { this.pushAllFiles(files, m[2]); } // for wiz - let re5 = /^\s*import\s+"(.+?)";/gmi; + let re5 = /^\s*(import|embed)\s+"(.+?)";/gmi; while (m = re5.exec(text)) { - this.pushAllFiles(files, m[1] + ".wiz"); + this.pushAllFiles(files, m[2] + ".wiz"); } } return files; diff --git a/src/ide/ui.ts b/src/ide/ui.ts index 6ada7d11..ff163c05 100644 --- a/src/ide/ui.ts +++ b/src/ide/ui.ts @@ -83,7 +83,7 @@ var TOOL_TO_SOURCE_STYLE = { 'fastbasic': 'fastbasic', 'basic': 'basic', 'silice': 'verilog', - 'wiz': 'text/x-csrc', + 'wiz': 'text/x-wiz', } function gaEvent(category:string, action:string, label?:string, value?:string) { diff --git a/src/platform/msx.ts b/src/platform/msx.ts index 7229eb34..abadb7ff 100644 --- a/src/platform/msx.ts +++ b/src/platform/msx.ts @@ -16,6 +16,7 @@ var MSX_BIOS_PRESETS = [ {id:'redbook_kbd.asm', name:'Redbook Keyboard Scanner (ASM)'}, {id:'siegegame.c', name:'Siege Game'}, {id:'eliza.c', name:'Eliza'}, + {id:'hello.wiz', name:'Hello (Wiz)'}, ]; // TODO: share with coleco, sms diff --git a/src/platform/vcs.ts b/src/platform/vcs.ts index 79f59485..53ddc8be 100644 --- a/src/platform/vcs.ts +++ b/src/platform/vcs.ts @@ -324,6 +324,8 @@ class VCSPlatform extends BasePlatform { showHelp(tool:string, ident:string) { if (tool == 'bataribasic') window.open("help/bataribasic/manual.html", "_help"); + else if (tool == 'wiz') + window.open("https://github.com/wiz-lang/wiz/blob/master/readme.md#wiz", "_help"); else window.open("https://8bitworkshop.com/blog/platforms/vcs/", "_help"); // TODO } diff --git a/src/worker/workermain.ts b/src/worker/workermain.ts index 704b45bb..6e495584 100644 --- a/src/worker/workermain.ts +++ b/src/worker/workermain.ts @@ -54,6 +54,7 @@ function getRootBasePlatform(platform : string) : string { var PLATFORM_PARAMS = { 'vcs': { + arch: '6502', code_start: 0x1000, code_size: 0xf000, data_start: 0x80, @@ -62,6 +63,7 @@ var PLATFORM_PARAMS = { wiz_inc_dir: '2600' }, 'mw8080bw': { + arch: 'z80', code_start: 0x0, rom_size: 0x2000, data_start: 0x2000, @@ -69,6 +71,7 @@ var PLATFORM_PARAMS = { stack_end: 0x2400, }, 'vicdual': { + arch: 'z80', code_start: 0x0, rom_size: 0x4020, data_start: 0xe400, @@ -76,6 +79,7 @@ var PLATFORM_PARAMS = { stack_end: 0xe800, }, 'galaxian': { + arch: 'z80', code_start: 0x0, rom_size: 0x4000, data_start: 0x4000, @@ -83,6 +87,7 @@ var PLATFORM_PARAMS = { stack_end: 0x4800, }, 'galaxian-scramble': { + arch: 'z80', code_start: 0x0, rom_size: 0x5020, data_start: 0x4000, @@ -90,6 +95,7 @@ var PLATFORM_PARAMS = { stack_end: 0x4800, }, 'williams': { + arch: '6809', code_start: 0x0, rom_size: 0xc000, data_start: 0x9800, @@ -100,6 +106,7 @@ var PLATFORM_PARAMS = { extra_link_args: ['-swilliams.scr', '-lcmoc-crt-vec', '-lcmoc-std-vec'], }, 'williams-z80': { + arch: 'z80', code_start: 0x0, rom_size: 0x9800, data_start: 0x9800, @@ -107,6 +114,7 @@ var PLATFORM_PARAMS = { stack_end: 0xc000, }, 'vector-z80color': { + arch: 'z80', code_start: 0x0, rom_size: 0x8000, data_start: 0xe000, @@ -114,12 +122,14 @@ var PLATFORM_PARAMS = { stack_end: 0x0, }, 'vector-ataricolor': { //TODO + arch: '6502', define: ['__VECTOR__'], cfgfile: 'vector-color.cfg', libargs: ['crt0.o', 'sim6502.lib'], extra_link_files: ['crt0.o', 'vector-color.cfg'], }, 'sound_williams-z80': { + arch: 'z80', code_start: 0x0, rom_size: 0x4000, data_start: 0x4000, @@ -127,6 +137,7 @@ var PLATFORM_PARAMS = { stack_end: 0x8000, }, 'base_z80': { + arch: 'z80', code_start: 0x0, rom_size: 0x8000, data_start: 0x8000, @@ -134,6 +145,7 @@ var PLATFORM_PARAMS = { stack_end: 0x0, }, 'coleco': { + arch: 'z80', rom_start: 0x8000, code_start: 0x8100, rom_size: 0x8000, @@ -144,6 +156,7 @@ var PLATFORM_PARAMS = { extra_link_args: ['-k', '/share/lib/coleco', '-l', 'libcv', '-l', 'libcvu', 'crt0.rel'], }, 'msx': { + arch: 'z80', rom_start: 0x4000, code_start: 0x4000, rom_size: 0x8000, @@ -152,8 +165,11 @@ var PLATFORM_PARAMS = { stack_end: 0xffff, extra_link_args: ['crt0-msx.rel'], extra_link_files: ['crt0-msx.rel', 'crt0-msx.lst'], + wiz_sys_type: 'z80', + wiz_inc_dir: 'msx', }, 'msx-libcv': { + arch: 'z80', rom_start: 0x4000, code_start: 0x4000, rom_size: 0x8000, @@ -166,6 +182,7 @@ var PLATFORM_PARAMS = { extra_compile_files: ['cv.h','cv_graphics.h','cv_input.h','cv_sound.h','cv_support.h','cvu.h','cvu_c.h','cvu_compression.h','cvu_f.h','cvu_graphics.h','cvu_input.h','cvu_sound.h'], }, 'sms-sg1000-libcv': { + arch: 'z80', rom_start: 0x0000, code_start: 0x0100, rom_size: 0xc000, @@ -178,6 +195,7 @@ var PLATFORM_PARAMS = { extra_compile_files: ['cv.h','cv_graphics.h','cv_input.h','cv_sound.h','cv_support.h','cvu.h','cvu_c.h','cvu_compression.h','cvu_f.h','cvu_graphics.h','cvu_input.h','cvu_sound.h'], }, 'nes': { //TODO + arch: '6502', define: ['__NES__'], cfgfile: 'neslib2.cfg', libargs: ['crt0.o', 'nes.lib', 'neslib2.lib', @@ -190,6 +208,7 @@ var PLATFORM_PARAMS = { wiz_rom_ext: '.nes', }, 'apple2': { + arch: '6502', define: ['__APPLE2__'], cfgfile: 'apple2-hgr.cfg', libargs: [ '--lib-path', '/share/target/apple2/drv', '-D', '__EXEHDR__=0', 'apple2.lib'], @@ -197,24 +216,29 @@ var PLATFORM_PARAMS = { code_start: 0x803, }, 'apple2-e': { + arch: '6502', define: ['__APPLE2__'], cfgfile: 'apple2.cfg', libargs: ['apple2.lib'], }, 'atari8-800xl': { + arch: '6502', define: ['__ATARI__'], cfgfile: 'atari-cart.cfg', libargs: ['atari.lib', '-D', '__CARTFLAGS__=4'], }, 'atari8-5200': { + arch: '6502', define: ['__ATARI5200__'], cfgfile: 'atari5200.cfg', libargs: ['atari5200.lib', '-D', '__CARTFLAGS__=255'], }, 'verilog': { + arch: 'verilog', extra_compile_files: ['8bitworkshop.v'], }, 'astrocade': { + arch: 'z80', code_start: 0x2000, rom_size: 0x2000, data_start: 0x4e10, @@ -222,6 +246,7 @@ var PLATFORM_PARAMS = { stack_end: 0x5000, }, 'astrocade-arcade': { + arch: 'z80', code_start: 0x0000, rom_size: 0x4000, data_start: 0x7de0, @@ -229,6 +254,7 @@ var PLATFORM_PARAMS = { stack_end: 0x8000, }, 'astrocade-bios': { + arch: 'z80', code_start: 0x0000, rom_size: 0x2000, data_start: 0x4fce, @@ -236,20 +262,24 @@ var PLATFORM_PARAMS = { stack_end: 0x4fce, }, 'atari7800': { + arch: '6502', define: ['__ATARI7800__'], cfgfile: 'atari7800.cfg', libargs: ['crt0.o', 'sim6502.lib'], extra_link_files: ['crt0.o', 'atari7800.cfg'], }, 'c64': { + arch: '6502', define: ['__CBM__', '__C64__'], cfgfile: 'c64.cfg', // SYS 2061 libargs: ['c64.lib'], //extra_link_files: ['c64-cart.cfg'], }, 'kim1': { + arch: '6502', }, 'vectrex': { + arch: '6809', code_start: 0x0, rom_size: 0x8000, data_start: 0xc880, @@ -261,8 +291,10 @@ var PLATFORM_PARAMS = { extra_link_args: ['-svectrex.scr', '-lcmoc-crt-vec', '-lcmoc-std-vec'], }, 'x86': { + arch: 'x86', }, 'zx': { + arch: 'z80', code_start: 0x5ccb, rom_size: 0xff58-0x5ccb, data_start: 0xf000, @@ -270,12 +302,13 @@ var PLATFORM_PARAMS = { stack_end: 0xff58, extra_link_args: ['crt0-zx.rel'], extra_link_files: ['crt0-zx.rel', 'crt0-zx.lst'], - }, - 'devel-6502': { + }, + 'devel-6502': { + arch: '6502', cfgfile: 'devel-6502.cfg', libargs: ['crt0.o', 'sim6502.lib'], extra_link_files: ['crt0.o', 'devel-6502.cfg'], - }, + }, }; PLATFORM_PARAMS['sms-sms-libcv'] = PLATFORM_PARAMS['sms-sg1000-libcv']; @@ -2734,7 +2767,7 @@ function compileWiz(step:BuildStep) { loadNative("wiz"); var params = step.params; gatherFiles(step, {mainFilePath:"main.wiz"}); - var destpath = step.prefix + params.wiz_rom_ext; + var destpath = step.prefix + (params.wiz_rom_ext || ".bin"); var errors : WorkerError[] = []; if (staleFiles(step, [destpath])) { var wiz = emglobal.wiz({ @@ -2751,23 +2784,25 @@ function compileWiz(step:BuildStep) { const FWDIR = '/share/common'; var args = [ '-o', destpath, - '-I' + FWDIR + '/' + (params.wiz_inc_dir || step.platform), - '-s', 'mlb', + '-I', FWDIR + '/' + (params.wiz_inc_dir || step.platform), + '-s', 'wla', + '--color=none', step.path]; + args.push('--system', params.wiz_sys_type || params.arch); execMain(step, wiz, args); if (errors.length) return {errors:errors}; var binout = FS.readFile(destpath, {encoding:'binary'}); putWorkFile(destpath, binout); - var dbgout = FS.readFile(step.prefix + '.mlb', {encoding:'utf8'}); + var dbgout = FS.readFile(step.prefix + '.sym', {encoding:'utf8'}); var symbolmap = {}; for (var s of dbgout.split("\n")) { - var toks = s.split(/:/); - // P:A00-A4F:graphic_digits - if (toks && toks.length >= 3) { - var tokrange = toks[1].split('-'); - var start = parseInt(tokrange[0], 16); - var sym = toks[2]; + var toks = s.split(/ /); + // 00:4008 header.basic_start + if (toks && toks.length >= 2) { + var tokrange = toks[0].split(':'); + var start = parseInt(tokrange[1], 16); + var sym = toks[1]; symbolmap[sym] = start; } }