rk86 2.0.19 → 2.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/rk86.js +232 -53
package/package.json
CHANGED
package/rk86.js
CHANGED
|
@@ -1726,6 +1726,127 @@ var ALL_MNEMONICS = new Set([
|
|
|
1726
1726
|
"END",
|
|
1727
1727
|
"EQU"
|
|
1728
1728
|
]);
|
|
1729
|
+
var INVERT_JUMP = {
|
|
1730
|
+
Z: "JNZ",
|
|
1731
|
+
NZ: "JZ",
|
|
1732
|
+
C: "JNC",
|
|
1733
|
+
NC: "JC",
|
|
1734
|
+
PO: "JPE",
|
|
1735
|
+
PE: "JPO",
|
|
1736
|
+
P: "JM",
|
|
1737
|
+
M: "JP",
|
|
1738
|
+
"==": "JNZ",
|
|
1739
|
+
"<>": "JZ"
|
|
1740
|
+
};
|
|
1741
|
+
var VALID_PROC_REGS = new Set(["PSW", "B", "D", "H"]);
|
|
1742
|
+
function popsAndRet(regs, orig) {
|
|
1743
|
+
const out = [];
|
|
1744
|
+
for (let k = regs.length - 1;k >= 0; k--) {
|
|
1745
|
+
out.push({ text: ` POP ${regs[k]}`, orig });
|
|
1746
|
+
}
|
|
1747
|
+
out.push({ text: ` RET`, orig });
|
|
1748
|
+
return out;
|
|
1749
|
+
}
|
|
1750
|
+
function preprocess(source) {
|
|
1751
|
+
const lines = source.split(`
|
|
1752
|
+
`);
|
|
1753
|
+
const out = [];
|
|
1754
|
+
const stack = [];
|
|
1755
|
+
let counter = 0;
|
|
1756
|
+
let proc = null;
|
|
1757
|
+
for (let i = 0;i < lines.length; i++) {
|
|
1758
|
+
const line = lines[i];
|
|
1759
|
+
const orig = i + 1;
|
|
1760
|
+
const bare = stripComment(line).trim();
|
|
1761
|
+
const ifMatch = bare.match(/^\.?if\s+(\S+)\s*$/i);
|
|
1762
|
+
if (ifMatch) {
|
|
1763
|
+
const cond = ifMatch[1].toUpperCase();
|
|
1764
|
+
const jmp = INVERT_JUMP[cond];
|
|
1765
|
+
if (!jmp) {
|
|
1766
|
+
throw new AsmError(`unknown .if condition: ${ifMatch[1]}`, orig, line, firstNonSpaceCol(line));
|
|
1767
|
+
}
|
|
1768
|
+
const id = counter++;
|
|
1769
|
+
stack.push({ id, sawElse: false, line: orig, source: line });
|
|
1770
|
+
out.push({ text: ` ${jmp} @_if_${id}_else`, orig });
|
|
1771
|
+
continue;
|
|
1772
|
+
}
|
|
1773
|
+
if (/^\.?else\s*$/i.test(bare)) {
|
|
1774
|
+
const top = stack[stack.length - 1];
|
|
1775
|
+
if (!top) {
|
|
1776
|
+
throw new AsmError(".else without .if", orig, line, firstNonSpaceCol(line));
|
|
1777
|
+
}
|
|
1778
|
+
if (top.sawElse) {
|
|
1779
|
+
throw new AsmError("duplicate .else", orig, line, firstNonSpaceCol(line));
|
|
1780
|
+
}
|
|
1781
|
+
top.sawElse = true;
|
|
1782
|
+
out.push({ text: ` JMP @_if_${top.id}_exit`, orig });
|
|
1783
|
+
out.push({ text: `@_if_${top.id}_else:`, orig });
|
|
1784
|
+
continue;
|
|
1785
|
+
}
|
|
1786
|
+
if (/^\.?endif\s*$/i.test(bare)) {
|
|
1787
|
+
const top = stack.pop();
|
|
1788
|
+
if (!top) {
|
|
1789
|
+
throw new AsmError(".endif without .if", orig, line, firstNonSpaceCol(line));
|
|
1790
|
+
}
|
|
1791
|
+
const suffix = top.sawElse ? "exit" : "else";
|
|
1792
|
+
out.push({ text: `@_if_${top.id}_${suffix}:`, orig });
|
|
1793
|
+
continue;
|
|
1794
|
+
}
|
|
1795
|
+
const procMatch = bare.match(/^([A-Za-z_]\w*):?\s+\.?proc\b\s*(.*)$/i);
|
|
1796
|
+
if (procMatch && !ALL_MNEMONICS.has(procMatch[1].toUpperCase())) {
|
|
1797
|
+
if (proc) {
|
|
1798
|
+
throw new AsmError("nested .proc not allowed", orig, line, firstNonSpaceCol(line));
|
|
1799
|
+
}
|
|
1800
|
+
const name = procMatch[1];
|
|
1801
|
+
const regsRaw = procMatch[2].trim();
|
|
1802
|
+
const regs = [];
|
|
1803
|
+
if (regsRaw) {
|
|
1804
|
+
for (const r of regsRaw.split(/[,\s]+/)) {
|
|
1805
|
+
if (!r)
|
|
1806
|
+
continue;
|
|
1807
|
+
const up = r.toUpperCase();
|
|
1808
|
+
if (!VALID_PROC_REGS.has(up)) {
|
|
1809
|
+
throw new AsmError(`invalid .proc register: ${r} (expected PSW, B, D, or H)`, orig, line, firstNonSpaceCol(line));
|
|
1810
|
+
}
|
|
1811
|
+
regs.push(up);
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
proc = { regs, line: orig, source: line };
|
|
1815
|
+
out.push({ text: `${name}:`, orig });
|
|
1816
|
+
for (const r of regs) {
|
|
1817
|
+
out.push({ text: ` PUSH ${r}`, orig });
|
|
1818
|
+
}
|
|
1819
|
+
continue;
|
|
1820
|
+
}
|
|
1821
|
+
if (/^\.proc(\s|$)/i.test(bare) || /^proc\s+\S/i.test(bare)) {
|
|
1822
|
+
throw new AsmError(".proc requires a label", orig, line, firstNonSpaceCol(line));
|
|
1823
|
+
}
|
|
1824
|
+
if (/^\.?endp\s*$/i.test(bare)) {
|
|
1825
|
+
if (!proc) {
|
|
1826
|
+
throw new AsmError(".endp without .proc", orig, line, firstNonSpaceCol(line));
|
|
1827
|
+
}
|
|
1828
|
+
out.push(...popsAndRet(proc.regs, orig));
|
|
1829
|
+
proc = null;
|
|
1830
|
+
continue;
|
|
1831
|
+
}
|
|
1832
|
+
if (/^\.?return\s*$/i.test(bare)) {
|
|
1833
|
+
if (!proc) {
|
|
1834
|
+
throw new AsmError(".return outside .proc", orig, line, firstNonSpaceCol(line));
|
|
1835
|
+
}
|
|
1836
|
+
out.push(...popsAndRet(proc.regs, orig));
|
|
1837
|
+
continue;
|
|
1838
|
+
}
|
|
1839
|
+
out.push({ text: line, orig });
|
|
1840
|
+
}
|
|
1841
|
+
if (stack.length) {
|
|
1842
|
+
const top = stack[stack.length - 1];
|
|
1843
|
+
throw new AsmError(".if without .endif", top.line, top.source, firstNonSpaceCol(top.source));
|
|
1844
|
+
}
|
|
1845
|
+
if (proc) {
|
|
1846
|
+
throw new AsmError(".proc without .endp", proc.line, proc.source, firstNonSpaceCol(proc.source));
|
|
1847
|
+
}
|
|
1848
|
+
return out;
|
|
1849
|
+
}
|
|
1729
1850
|
var MAX_STATEMENTS_PER_LINE = 10;
|
|
1730
1851
|
function splitStatements(line) {
|
|
1731
1852
|
const src = stripComment(line);
|
|
@@ -1847,35 +1968,46 @@ function stripDirectiveDot(s) {
|
|
|
1847
1968
|
}
|
|
1848
1969
|
return s;
|
|
1849
1970
|
}
|
|
1971
|
+
var LABEL_RE = /^(?:[A-Za-z_]\w*|@\w+|\.\w+)$/;
|
|
1972
|
+
function isMnemonic(tok) {
|
|
1973
|
+
return ALL_MNEMONICS.has(stripDirectiveDot(tok).toUpperCase());
|
|
1974
|
+
}
|
|
1850
1975
|
function parseLine(line) {
|
|
1851
1976
|
let s = stripComment(line).trim();
|
|
1852
1977
|
if (!s)
|
|
1853
1978
|
return { operands: [] };
|
|
1854
1979
|
let label;
|
|
1855
1980
|
const ci = s.indexOf(":");
|
|
1856
|
-
if (ci > 0 &&
|
|
1981
|
+
if (ci > 0 && LABEL_RE.test(s.slice(0, ci).trim())) {
|
|
1857
1982
|
label = s.slice(0, ci).trim();
|
|
1858
1983
|
s = s.slice(ci + 1).trim();
|
|
1859
1984
|
}
|
|
1860
1985
|
if (!s)
|
|
1861
1986
|
return { label, operands: [] };
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
if (!label && rest) {
|
|
1866
|
-
const
|
|
1867
|
-
if (
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
isEqu: true
|
|
1873
|
-
};
|
|
1987
|
+
let si = s.search(/\s/);
|
|
1988
|
+
let first = si < 0 ? s : s.slice(0, si);
|
|
1989
|
+
let rest = si < 0 ? "" : s.slice(si).trim();
|
|
1990
|
+
if (!label && rest && LABEL_RE.test(first) && !isMnemonic(first)) {
|
|
1991
|
+
const nextTok = rest.match(/^\S+/)?.[0] ?? "";
|
|
1992
|
+
if (isMnemonic(nextTok)) {
|
|
1993
|
+
label = first;
|
|
1994
|
+
si = rest.search(/\s/);
|
|
1995
|
+
first = si < 0 ? rest : rest.slice(0, si);
|
|
1996
|
+
rest = si < 0 ? "" : rest.slice(si).trim();
|
|
1874
1997
|
}
|
|
1875
1998
|
}
|
|
1999
|
+
const mnemonic = stripDirectiveDot(first);
|
|
2000
|
+
if (label && mnemonic.toUpperCase() === "EQU") {
|
|
2001
|
+
return {
|
|
2002
|
+
label,
|
|
2003
|
+
mnemonic: "EQU",
|
|
2004
|
+
operands: [rest],
|
|
2005
|
+
isEqu: true
|
|
2006
|
+
};
|
|
2007
|
+
}
|
|
1876
2008
|
return {
|
|
1877
2009
|
label,
|
|
1878
|
-
mnemonic
|
|
2010
|
+
mnemonic,
|
|
1879
2011
|
operands: rest ? splitOperands(rest) : []
|
|
1880
2012
|
};
|
|
1881
2013
|
}
|
|
@@ -1893,6 +2025,31 @@ function tokenizeExpr(expr) {
|
|
|
1893
2025
|
i += 3;
|
|
1894
2026
|
continue;
|
|
1895
2027
|
}
|
|
2028
|
+
if (c === "$") {
|
|
2029
|
+
tokens.push({ kind: "id", val: "$" });
|
|
2030
|
+
i++;
|
|
2031
|
+
continue;
|
|
2032
|
+
}
|
|
2033
|
+
if (c === "@") {
|
|
2034
|
+
let j = i + 1;
|
|
2035
|
+
while (j < expr.length && /\w/.test(expr[j]))
|
|
2036
|
+
j++;
|
|
2037
|
+
if (j === i + 1)
|
|
2038
|
+
throw new Error("expected identifier after '@'");
|
|
2039
|
+
tokens.push({ kind: "id", val: expr.slice(i, j) });
|
|
2040
|
+
i = j;
|
|
2041
|
+
continue;
|
|
2042
|
+
}
|
|
2043
|
+
if (c === ".") {
|
|
2044
|
+
let j = i + 1;
|
|
2045
|
+
while (j < expr.length && /\w/.test(expr[j]))
|
|
2046
|
+
j++;
|
|
2047
|
+
if (j === i + 1)
|
|
2048
|
+
throw new Error("expected identifier after '.'");
|
|
2049
|
+
tokens.push({ kind: "id", val: expr.slice(i, j) });
|
|
2050
|
+
i = j;
|
|
2051
|
+
continue;
|
|
2052
|
+
}
|
|
1896
2053
|
if (/[0-9]/.test(c)) {
|
|
1897
2054
|
let j = i;
|
|
1898
2055
|
while (j < expr.length && /[0-9A-Fa-f]/.test(expr[j]))
|
|
@@ -1933,7 +2090,7 @@ function tokenizeExpr(expr) {
|
|
|
1933
2090
|
}
|
|
1934
2091
|
return tokens;
|
|
1935
2092
|
}
|
|
1936
|
-
function evalExpr(expr, symbols) {
|
|
2093
|
+
function evalExpr(expr, symbols, pc = 0, lastLabel = "") {
|
|
1937
2094
|
const tokens = tokenizeExpr(expr);
|
|
1938
2095
|
let pos = 0;
|
|
1939
2096
|
function peek() {
|
|
@@ -1956,20 +2113,30 @@ function evalExpr(expr, symbols) {
|
|
|
1956
2113
|
}
|
|
1957
2114
|
if (t.kind === "id") {
|
|
1958
2115
|
next();
|
|
1959
|
-
const
|
|
1960
|
-
if (
|
|
2116
|
+
const raw = t.val;
|
|
2117
|
+
if (raw === "$")
|
|
2118
|
+
return pc;
|
|
2119
|
+
const upper = raw.toUpperCase();
|
|
2120
|
+
if (upper === "LOW" || upper === "HIGH") {
|
|
1961
2121
|
if (!isOp("("))
|
|
1962
|
-
throw new Error(`${
|
|
2122
|
+
throw new Error(`${upper} requires parentheses`);
|
|
1963
2123
|
next();
|
|
1964
2124
|
const v = parseOr();
|
|
1965
2125
|
if (!isOp(")"))
|
|
1966
2126
|
throw new Error("expected ')'");
|
|
1967
2127
|
next();
|
|
1968
|
-
return
|
|
2128
|
+
return upper === "LOW" ? v & 255 : v >> 8 & 255;
|
|
1969
2129
|
}
|
|
2130
|
+
let name = raw;
|
|
2131
|
+
if (name.startsWith("@") || name.startsWith(".")) {
|
|
2132
|
+
if (!lastLabel)
|
|
2133
|
+
throw new Error(`local label without scope: ${raw}`);
|
|
2134
|
+
name = lastLabel + name;
|
|
2135
|
+
}
|
|
2136
|
+
const k = name.toUpperCase();
|
|
1970
2137
|
if (symbols.has(k))
|
|
1971
2138
|
return symbols.get(k);
|
|
1972
|
-
throw new Error(`unknown symbol: ${
|
|
2139
|
+
throw new Error(`unknown symbol: ${raw}`);
|
|
1973
2140
|
}
|
|
1974
2141
|
if (t.kind === "op" && t.val === "(") {
|
|
1975
2142
|
next();
|
|
@@ -2057,15 +2224,15 @@ function evalExpr(expr, symbols) {
|
|
|
2057
2224
|
throw new Error(`unexpected token: ${tokens[pos].val}`);
|
|
2058
2225
|
return result;
|
|
2059
2226
|
}
|
|
2060
|
-
function encode(m, ops, symbols) {
|
|
2227
|
+
function encode(m, ops, symbols, pc = 0, lastLabel = "") {
|
|
2061
2228
|
if (m in IMPLIED)
|
|
2062
2229
|
return [IMPLIED[m]];
|
|
2063
2230
|
if (m in ALU_REG)
|
|
2064
2231
|
return [ALU_REG[m] | REG8[ops[0].toUpperCase()]];
|
|
2065
2232
|
if (m in ALU_IMM)
|
|
2066
|
-
return [ALU_IMM[m], evalExpr(ops[0], symbols) & 255];
|
|
2233
|
+
return [ALU_IMM[m], evalExpr(ops[0], symbols, pc, lastLabel) & 255];
|
|
2067
2234
|
if (m in ADDR16) {
|
|
2068
|
-
const v = evalExpr(ops[0], symbols);
|
|
2235
|
+
const v = evalExpr(ops[0], symbols, pc, lastLabel);
|
|
2069
2236
|
return [ADDR16[m], v & 255, v >> 8 & 255];
|
|
2070
2237
|
}
|
|
2071
2238
|
if (m === "MOV")
|
|
@@ -2073,7 +2240,7 @@ function encode(m, ops, symbols) {
|
|
|
2073
2240
|
64 | REG8[ops[0].toUpperCase()] << 3 | REG8[ops[1].toUpperCase()]
|
|
2074
2241
|
];
|
|
2075
2242
|
if (m === "MVI") {
|
|
2076
|
-
const v = evalExpr(ops[1], symbols);
|
|
2243
|
+
const v = evalExpr(ops[1], symbols, pc, lastLabel);
|
|
2077
2244
|
return [6 | REG8[ops[0].toUpperCase()] << 3, v & 255];
|
|
2078
2245
|
}
|
|
2079
2246
|
if (m === "INR")
|
|
@@ -2081,7 +2248,7 @@ function encode(m, ops, symbols) {
|
|
|
2081
2248
|
if (m === "DCR")
|
|
2082
2249
|
return [5 | REG8[ops[0].toUpperCase()] << 3];
|
|
2083
2250
|
if (m === "LXI") {
|
|
2084
|
-
const v = evalExpr(ops[1], symbols);
|
|
2251
|
+
const v = evalExpr(ops[1], symbols, pc, lastLabel);
|
|
2085
2252
|
return [
|
|
2086
2253
|
1 | REG_PAIR[ops[0].toUpperCase()] << 4,
|
|
2087
2254
|
v & 255,
|
|
@@ -2103,31 +2270,31 @@ function encode(m, ops, symbols) {
|
|
|
2103
2270
|
if (m === "STAX")
|
|
2104
2271
|
return [2 | REG_PAIR[ops[0].toUpperCase()] << 4];
|
|
2105
2272
|
if (m === "IN")
|
|
2106
|
-
return [219, evalExpr(ops[0], symbols) & 255];
|
|
2273
|
+
return [219, evalExpr(ops[0], symbols, pc, lastLabel) & 255];
|
|
2107
2274
|
if (m === "OUT")
|
|
2108
|
-
return [211, evalExpr(ops[0], symbols) & 255];
|
|
2275
|
+
return [211, evalExpr(ops[0], symbols, pc, lastLabel) & 255];
|
|
2109
2276
|
if (m === "RST") {
|
|
2110
|
-
const n = evalExpr(ops[0], symbols);
|
|
2277
|
+
const n = evalExpr(ops[0], symbols, pc, lastLabel);
|
|
2111
2278
|
return [199 | n << 3];
|
|
2112
2279
|
}
|
|
2113
2280
|
throw new Error(`cannot encode: ${m} ${ops.join(", ")}`);
|
|
2114
2281
|
}
|
|
2115
|
-
function dbBytes(operands, symbols) {
|
|
2282
|
+
function dbBytes(operands, symbols, pc = 0, lastLabel = "") {
|
|
2116
2283
|
const out = [];
|
|
2117
2284
|
for (const op of operands) {
|
|
2118
2285
|
if (op.startsWith('"') && op.endsWith('"') || op.startsWith("'") && op.endsWith("'")) {
|
|
2119
2286
|
for (const ch of op.slice(1, -1))
|
|
2120
2287
|
out.push(ch.charCodeAt(0));
|
|
2121
2288
|
} else {
|
|
2122
|
-
out.push(evalExpr(op, symbols) & 255);
|
|
2289
|
+
out.push(evalExpr(op, symbols, pc, lastLabel) & 255);
|
|
2123
2290
|
}
|
|
2124
2291
|
}
|
|
2125
2292
|
return out;
|
|
2126
2293
|
}
|
|
2127
|
-
function dwBytes(operands, symbols) {
|
|
2294
|
+
function dwBytes(operands, symbols, pc = 0, lastLabel = "") {
|
|
2128
2295
|
const out = [];
|
|
2129
2296
|
for (const op of operands) {
|
|
2130
|
-
const v = evalExpr(op, symbols) & 65535;
|
|
2297
|
+
const v = evalExpr(op, symbols, pc, lastLabel) & 65535;
|
|
2131
2298
|
out.push(v & 255, v >> 8 & 255);
|
|
2132
2299
|
}
|
|
2133
2300
|
return out;
|
|
@@ -2140,15 +2307,15 @@ function parseDs(operands) {
|
|
|
2140
2307
|
return { count: m[1], fill: m[2] };
|
|
2141
2308
|
return { count: operands[0], fill: "0" };
|
|
2142
2309
|
}
|
|
2143
|
-
function dsBytes(operands, symbols) {
|
|
2310
|
+
function dsBytes(operands, symbols, pc = 0, lastLabel = "") {
|
|
2144
2311
|
const { count, fill } = parseDs(operands);
|
|
2145
|
-
const n = evalExpr(count, symbols);
|
|
2146
|
-
const f = evalExpr(fill, symbols) & 255;
|
|
2312
|
+
const n = evalExpr(count, symbols, pc, lastLabel);
|
|
2313
|
+
const f = evalExpr(fill, symbols, pc, lastLabel) & 255;
|
|
2147
2314
|
return new Array(n).fill(f);
|
|
2148
2315
|
}
|
|
2149
|
-
function countDs(operands, symbols) {
|
|
2316
|
+
function countDs(operands, symbols, pc = 0, lastLabel = "") {
|
|
2150
2317
|
const { count } = parseDs(operands);
|
|
2151
|
-
return evalExpr(count, symbols);
|
|
2318
|
+
return evalExpr(count, symbols, pc, lastLabel);
|
|
2152
2319
|
}
|
|
2153
2320
|
function countDb(operands) {
|
|
2154
2321
|
let n = 0;
|
|
@@ -2161,22 +2328,30 @@ function countDb(operands) {
|
|
|
2161
2328
|
return n;
|
|
2162
2329
|
}
|
|
2163
2330
|
function asm(source) {
|
|
2164
|
-
const
|
|
2165
|
-
`);
|
|
2331
|
+
const pp = preprocess(source);
|
|
2166
2332
|
const symbols = new Map;
|
|
2167
2333
|
let pc = 0;
|
|
2334
|
+
let lastLabel = "";
|
|
2168
2335
|
let ended = false;
|
|
2169
|
-
for (let idx = 0;idx <
|
|
2170
|
-
const line =
|
|
2336
|
+
for (let idx = 0;idx < pp.length && !ended; idx++) {
|
|
2337
|
+
const { text: line, orig } = pp[idx];
|
|
2171
2338
|
try {
|
|
2172
2339
|
for (const stmt of splitStatements(line)) {
|
|
2173
2340
|
const parts = parseLine(stmt);
|
|
2174
2341
|
if (parts.label) {
|
|
2342
|
+
let labelName = parts.label;
|
|
2343
|
+
if (labelName.startsWith("@") || labelName.startsWith(".")) {
|
|
2344
|
+
if (!lastLabel)
|
|
2345
|
+
throw new Error(`local label without preceding normal label: ${labelName}`);
|
|
2346
|
+
labelName = lastLabel + labelName;
|
|
2347
|
+
} else if (!parts.isEqu) {
|
|
2348
|
+
lastLabel = parts.label;
|
|
2349
|
+
}
|
|
2175
2350
|
if (parts.isEqu) {
|
|
2176
|
-
symbols.set(
|
|
2351
|
+
symbols.set(labelName.toUpperCase(), evalExpr(parts.operands[0], symbols, pc, lastLabel));
|
|
2177
2352
|
continue;
|
|
2178
2353
|
}
|
|
2179
|
-
symbols.set(
|
|
2354
|
+
symbols.set(labelName.toUpperCase(), pc);
|
|
2180
2355
|
}
|
|
2181
2356
|
if (!parts.mnemonic)
|
|
2182
2357
|
continue;
|
|
@@ -2184,7 +2359,7 @@ function asm(source) {
|
|
|
2184
2359
|
if (m === "EQU")
|
|
2185
2360
|
continue;
|
|
2186
2361
|
if (m === "ORG") {
|
|
2187
|
-
pc = evalExpr(parts.operands[0], symbols);
|
|
2362
|
+
pc = evalExpr(parts.operands[0], symbols, pc, lastLabel);
|
|
2188
2363
|
continue;
|
|
2189
2364
|
}
|
|
2190
2365
|
if (m === "SECTION")
|
|
@@ -2202,7 +2377,7 @@ function asm(source) {
|
|
|
2202
2377
|
continue;
|
|
2203
2378
|
}
|
|
2204
2379
|
if (m === "DS") {
|
|
2205
|
-
pc += countDs(parts.operands, symbols);
|
|
2380
|
+
pc += countDs(parts.operands, symbols, pc, lastLabel);
|
|
2206
2381
|
continue;
|
|
2207
2382
|
}
|
|
2208
2383
|
pc += instrSize(m);
|
|
@@ -2210,29 +2385,34 @@ function asm(source) {
|
|
|
2210
2385
|
} catch (e) {
|
|
2211
2386
|
if (e instanceof AsmError)
|
|
2212
2387
|
throw e;
|
|
2213
|
-
throw new AsmError(e.message,
|
|
2388
|
+
throw new AsmError(e.message, orig, line, firstNonSpaceCol(line));
|
|
2214
2389
|
}
|
|
2215
2390
|
}
|
|
2216
2391
|
const sections = [];
|
|
2217
2392
|
let current = null;
|
|
2218
2393
|
const sectionNames = new Set;
|
|
2394
|
+
let lastLabel2 = "";
|
|
2219
2395
|
let endedPass2 = false;
|
|
2220
|
-
for (let idx = 0;idx <
|
|
2221
|
-
const line =
|
|
2396
|
+
for (let idx = 0;idx < pp.length && !endedPass2; idx++) {
|
|
2397
|
+
const { text: line, orig } = pp[idx];
|
|
2222
2398
|
try {
|
|
2223
2399
|
for (const stmt of splitStatements(line)) {
|
|
2224
2400
|
const parts = parseLine(stmt);
|
|
2401
|
+
if (parts.label && !parts.label.startsWith("@") && !parts.label.startsWith(".") && !parts.isEqu) {
|
|
2402
|
+
lastLabel2 = parts.label;
|
|
2403
|
+
}
|
|
2225
2404
|
if (parts.isEqu || !parts.mnemonic)
|
|
2226
2405
|
continue;
|
|
2227
2406
|
const m = parts.mnemonic.toUpperCase();
|
|
2228
2407
|
if (m === "EQU")
|
|
2229
2408
|
continue;
|
|
2409
|
+
const curPc = current ? current.start + current.data.length : 0;
|
|
2230
2410
|
if (m === "ORG") {
|
|
2231
2411
|
if (current && current.data.length) {
|
|
2232
2412
|
current.end = current.start + current.data.length - 1;
|
|
2233
2413
|
sections.push(current);
|
|
2234
2414
|
}
|
|
2235
|
-
const addr = evalExpr(parts.operands[0], symbols);
|
|
2415
|
+
const addr = evalExpr(parts.operands[0], symbols, curPc, lastLabel2);
|
|
2236
2416
|
current = { start: addr, end: addr, data: [] };
|
|
2237
2417
|
continue;
|
|
2238
2418
|
}
|
|
@@ -2254,13 +2434,13 @@ function asm(source) {
|
|
|
2254
2434
|
}
|
|
2255
2435
|
if (!current)
|
|
2256
2436
|
throw new Error("code before ORG");
|
|
2257
|
-
const bytes = m === "DB" ? dbBytes(parts.operands, symbols) : m === "DW" ? dwBytes(parts.operands, symbols) : m === "DS" ? dsBytes(parts.operands, symbols) : encode(m, parts.operands, symbols);
|
|
2437
|
+
const bytes = m === "DB" ? dbBytes(parts.operands, symbols, curPc, lastLabel2) : m === "DW" ? dwBytes(parts.operands, symbols, curPc, lastLabel2) : m === "DS" ? dsBytes(parts.operands, symbols, curPc, lastLabel2) : encode(m, parts.operands, symbols, curPc, lastLabel2);
|
|
2258
2438
|
current.data.push(...bytes);
|
|
2259
2439
|
}
|
|
2260
2440
|
} catch (e) {
|
|
2261
2441
|
if (e instanceof AsmError)
|
|
2262
2442
|
throw e;
|
|
2263
|
-
throw new AsmError(e.message,
|
|
2443
|
+
throw new AsmError(e.message, orig, line, firstNonSpaceCol(line));
|
|
2264
2444
|
}
|
|
2265
2445
|
}
|
|
2266
2446
|
if (current && current.data.length) {
|
|
@@ -2277,7 +2457,7 @@ import { readFile, writeFile } from "fs/promises";
|
|
|
2277
2457
|
// packages/rk86/package.json
|
|
2278
2458
|
var package_default = {
|
|
2279
2459
|
name: "rk86",
|
|
2280
|
-
version: "2.0.
|
|
2460
|
+
version: "2.0.19",
|
|
2281
2461
|
description: "\u042D\u043C\u0443\u043B\u044F\u0442\u043E\u0440 \u0420\u0430\u0434\u0438\u043E-86\u0420\u041A (Intel 8080) \u0434\u043B\u044F \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u0430",
|
|
2282
2462
|
bin: {
|
|
2283
2463
|
rk86: "rk86.js"
|
|
@@ -4180,7 +4360,6 @@ class TerminalUI {
|
|
|
4180
4360
|
terminal = { put: () => {}, history: [] };
|
|
4181
4361
|
i8080disasm;
|
|
4182
4362
|
visualizer;
|
|
4183
|
-
toggle_assembler;
|
|
4184
4363
|
on_visualizer_hit;
|
|
4185
4364
|
on_pause_changed;
|
|
4186
4365
|
refreshDebugger;
|