rk86 2.0.13 → 2.0.15

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/rk86.js +448 -20
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rk86",
3
- "version": "2.0.13",
3
+ "version": "2.0.15",
4
4
  "description": "Эмулятор Радио-86РК (Intel 8080) для терминала",
5
5
  "bin": {
6
6
  "rk86": "rk86.js"
package/rk86.js CHANGED
@@ -1588,12 +1588,400 @@ var init_catalog_data = __esm(() => {
1588
1588
  ];
1589
1589
  });
1590
1590
 
1591
+ // node_modules/asm8080/dist/asm8.js
1592
+ var REG8 = {
1593
+ B: 0,
1594
+ C: 1,
1595
+ D: 2,
1596
+ E: 3,
1597
+ H: 4,
1598
+ L: 5,
1599
+ M: 6,
1600
+ A: 7
1601
+ };
1602
+ var REG_PAIR = {
1603
+ B: 0,
1604
+ D: 1,
1605
+ H: 2,
1606
+ SP: 3
1607
+ };
1608
+ var REG_PAIR_PUSH = {
1609
+ B: 0,
1610
+ D: 1,
1611
+ H: 2,
1612
+ PSW: 3
1613
+ };
1614
+ var IMPLIED = {
1615
+ NOP: 0,
1616
+ HLT: 118,
1617
+ RET: 201,
1618
+ XCHG: 235,
1619
+ EI: 251,
1620
+ DI: 243,
1621
+ CMA: 47,
1622
+ STC: 55,
1623
+ CMC: 63,
1624
+ DAA: 39,
1625
+ RLC: 7,
1626
+ RRC: 15,
1627
+ RAL: 23,
1628
+ RAR: 31,
1629
+ PCHL: 233,
1630
+ SPHL: 249,
1631
+ XTHL: 227,
1632
+ RNZ: 192,
1633
+ RZ: 200,
1634
+ RNC: 208,
1635
+ RC: 216,
1636
+ RPO: 224,
1637
+ RPE: 232,
1638
+ RP: 240,
1639
+ RM: 248
1640
+ };
1641
+ var ALU_REG = {
1642
+ ADD: 128,
1643
+ ADC: 136,
1644
+ SUB: 144,
1645
+ SBB: 152,
1646
+ ANA: 160,
1647
+ XRA: 168,
1648
+ ORA: 176,
1649
+ CMP: 184
1650
+ };
1651
+ var ALU_IMM = {
1652
+ ADI: 198,
1653
+ ACI: 206,
1654
+ SUI: 214,
1655
+ SBI: 222,
1656
+ ANI: 230,
1657
+ XRI: 238,
1658
+ ORI: 246,
1659
+ CPI: 254
1660
+ };
1661
+ var ADDR16 = {
1662
+ JMP: 195,
1663
+ JNZ: 194,
1664
+ JZ: 202,
1665
+ JNC: 210,
1666
+ JC: 218,
1667
+ JPO: 226,
1668
+ JPE: 234,
1669
+ JP: 242,
1670
+ JM: 250,
1671
+ CALL: 205,
1672
+ CNZ: 196,
1673
+ CZ: 204,
1674
+ CNC: 212,
1675
+ CC: 220,
1676
+ CPO: 228,
1677
+ CPE: 236,
1678
+ CP: 244,
1679
+ CM: 252,
1680
+ LDA: 58,
1681
+ STA: 50,
1682
+ LHLD: 42,
1683
+ SHLD: 34
1684
+ };
1685
+ function instrSize(m) {
1686
+ if (m in IMPLIED)
1687
+ return 1;
1688
+ if (m in ALU_REG)
1689
+ return 1;
1690
+ if (m === "MOV" || m === "INR" || m === "DCR")
1691
+ return 1;
1692
+ if (m === "PUSH" || m === "POP")
1693
+ return 1;
1694
+ if (m === "DAD" || m === "INX" || m === "DCX")
1695
+ return 1;
1696
+ if (m === "LDAX" || m === "STAX")
1697
+ return 1;
1698
+ if (m === "RST")
1699
+ return 1;
1700
+ if (m === "MVI")
1701
+ return 2;
1702
+ if (m in ALU_IMM)
1703
+ return 2;
1704
+ if (m === "IN" || m === "OUT")
1705
+ return 2;
1706
+ if (m === "LXI")
1707
+ return 3;
1708
+ if (m in ADDR16)
1709
+ return 3;
1710
+ throw new Error(`unknown mnemonic: ${m}`);
1711
+ }
1712
+ function stripComment(line) {
1713
+ let inQ = false;
1714
+ let qc = "";
1715
+ for (let i = 0;i < line.length; i++) {
1716
+ const c = line[i];
1717
+ if (inQ) {
1718
+ if (c === qc)
1719
+ inQ = false;
1720
+ } else if (c === '"' || c === "'") {
1721
+ inQ = true;
1722
+ qc = c;
1723
+ } else if (c === ";")
1724
+ return line.slice(0, i);
1725
+ }
1726
+ return line;
1727
+ }
1728
+ function splitOperands(s) {
1729
+ const r = [];
1730
+ let current = "";
1731
+ let inQ = false;
1732
+ let qc = "";
1733
+ for (const c of s) {
1734
+ if (inQ) {
1735
+ current += c;
1736
+ if (c === qc)
1737
+ inQ = false;
1738
+ } else if (c === '"' || c === "'") {
1739
+ inQ = true;
1740
+ qc = c;
1741
+ current += c;
1742
+ } else if (c === ",") {
1743
+ r.push(current.trim());
1744
+ current = "";
1745
+ } else
1746
+ current += c;
1747
+ }
1748
+ if (current.trim())
1749
+ r.push(current.trim());
1750
+ return r;
1751
+ }
1752
+ function parseLine(line) {
1753
+ let s = stripComment(line).trim();
1754
+ if (!s)
1755
+ return { operands: [] };
1756
+ let label;
1757
+ const ci = s.indexOf(":");
1758
+ if (ci > 0 && /^[A-Za-z_]\w*$/.test(s.slice(0, ci).trim())) {
1759
+ label = s.slice(0, ci).trim();
1760
+ s = s.slice(ci + 1).trim();
1761
+ }
1762
+ if (!s)
1763
+ return { label, operands: [] };
1764
+ const si = s.search(/\s/);
1765
+ const first = si < 0 ? s : s.slice(0, si);
1766
+ const rest = si < 0 ? "" : s.slice(si).trim();
1767
+ if (!label && rest) {
1768
+ const parts = rest.split(/\s+/);
1769
+ if (parts[0].toUpperCase() === "EQU") {
1770
+ return {
1771
+ label: first,
1772
+ mnemonic: "EQU",
1773
+ operands: [parts.slice(1).join(" ")],
1774
+ isEqu: true
1775
+ };
1776
+ }
1777
+ }
1778
+ return { label, mnemonic: first, operands: rest ? splitOperands(rest) : [] };
1779
+ }
1780
+ function evalAtom(s, symbols) {
1781
+ s = s.trim();
1782
+ if (s.length === 3 && s[0] === "'" && s[2] === "'")
1783
+ return s.charCodeAt(1);
1784
+ if (/^[0-9][0-9A-Fa-f]*[hH]$/.test(s))
1785
+ return parseInt(s.slice(0, -1), 16);
1786
+ if (/^[0-9]+$/.test(s))
1787
+ return parseInt(s, 10);
1788
+ const k = s.toUpperCase();
1789
+ if (symbols.has(k))
1790
+ return symbols.get(k);
1791
+ throw new Error(`unknown symbol: ${s}`);
1792
+ }
1793
+ function evalExpr(expr, symbols) {
1794
+ expr = expr.trim();
1795
+ const tokens = [];
1796
+ const ops = ["+"];
1797
+ let current = "";
1798
+ for (const c of expr) {
1799
+ if ((c === "+" || c === "-") && current.trim()) {
1800
+ tokens.push(current.trim());
1801
+ ops.push(c);
1802
+ current = "";
1803
+ } else {
1804
+ current += c;
1805
+ }
1806
+ }
1807
+ if (current.trim())
1808
+ tokens.push(current.trim());
1809
+ let r = 0;
1810
+ for (let i = 0;i < tokens.length; i++) {
1811
+ const v = evalAtom(tokens[i], symbols);
1812
+ r = ops[i] === "+" ? r + v : r - v;
1813
+ }
1814
+ return r & 65535;
1815
+ }
1816
+ function encode(m, ops, symbols) {
1817
+ if (m in IMPLIED)
1818
+ return [IMPLIED[m]];
1819
+ if (m in ALU_REG)
1820
+ return [ALU_REG[m] | REG8[ops[0].toUpperCase()]];
1821
+ if (m in ALU_IMM)
1822
+ return [ALU_IMM[m], evalExpr(ops[0], symbols) & 255];
1823
+ if (m in ADDR16) {
1824
+ const v = evalExpr(ops[0], symbols);
1825
+ return [ADDR16[m], v & 255, v >> 8 & 255];
1826
+ }
1827
+ if (m === "MOV")
1828
+ return [64 | REG8[ops[0].toUpperCase()] << 3 | REG8[ops[1].toUpperCase()]];
1829
+ if (m === "MVI") {
1830
+ const v = evalExpr(ops[1], symbols);
1831
+ return [6 | REG8[ops[0].toUpperCase()] << 3, v & 255];
1832
+ }
1833
+ if (m === "INR")
1834
+ return [4 | REG8[ops[0].toUpperCase()] << 3];
1835
+ if (m === "DCR")
1836
+ return [5 | REG8[ops[0].toUpperCase()] << 3];
1837
+ if (m === "LXI") {
1838
+ const v = evalExpr(ops[1], symbols);
1839
+ return [1 | REG_PAIR[ops[0].toUpperCase()] << 4, v & 255, v >> 8 & 255];
1840
+ }
1841
+ if (m === "DAD")
1842
+ return [9 | REG_PAIR[ops[0].toUpperCase()] << 4];
1843
+ if (m === "INX")
1844
+ return [3 | REG_PAIR[ops[0].toUpperCase()] << 4];
1845
+ if (m === "DCX")
1846
+ return [11 | REG_PAIR[ops[0].toUpperCase()] << 4];
1847
+ if (m === "PUSH")
1848
+ return [197 | REG_PAIR_PUSH[ops[0].toUpperCase()] << 4];
1849
+ if (m === "POP")
1850
+ return [193 | REG_PAIR_PUSH[ops[0].toUpperCase()] << 4];
1851
+ if (m === "LDAX")
1852
+ return [10 | REG_PAIR[ops[0].toUpperCase()] << 4];
1853
+ if (m === "STAX")
1854
+ return [2 | REG_PAIR[ops[0].toUpperCase()] << 4];
1855
+ if (m === "IN")
1856
+ return [219, evalExpr(ops[0], symbols) & 255];
1857
+ if (m === "OUT")
1858
+ return [211, evalExpr(ops[0], symbols) & 255];
1859
+ if (m === "RST") {
1860
+ const n = evalExpr(ops[0], symbols);
1861
+ return [199 | n << 3];
1862
+ }
1863
+ throw new Error(`cannot encode: ${m} ${ops.join(", ")}`);
1864
+ }
1865
+ function dbBytes(operands, symbols) {
1866
+ const out = [];
1867
+ for (const op of operands) {
1868
+ if (op.startsWith('"') && op.endsWith('"') || op.startsWith("'") && op.endsWith("'")) {
1869
+ for (const ch of op.slice(1, -1))
1870
+ out.push(ch.charCodeAt(0));
1871
+ } else {
1872
+ out.push(evalExpr(op, symbols) & 255);
1873
+ }
1874
+ }
1875
+ return out;
1876
+ }
1877
+ function dwBytes(operands, symbols) {
1878
+ const out = [];
1879
+ for (const op of operands) {
1880
+ const v = evalExpr(op, symbols) & 65535;
1881
+ out.push(v & 255, v >> 8 & 255);
1882
+ }
1883
+ return out;
1884
+ }
1885
+ function countDb(operands) {
1886
+ let n = 0;
1887
+ for (const op of operands) {
1888
+ if (op.startsWith('"') && op.endsWith('"') || op.startsWith("'") && op.endsWith("'"))
1889
+ n += op.length - 2;
1890
+ else
1891
+ n++;
1892
+ }
1893
+ return n;
1894
+ }
1895
+ function asm(source) {
1896
+ const lines = source.split(`
1897
+ `);
1898
+ const symbols = new Map;
1899
+ let pc = 0;
1900
+ for (const line of lines) {
1901
+ const parts = parseLine(line);
1902
+ if (parts.label) {
1903
+ if (parts.isEqu) {
1904
+ symbols.set(parts.label.toUpperCase(), evalExpr(parts.operands[0], symbols));
1905
+ continue;
1906
+ }
1907
+ symbols.set(parts.label.toUpperCase(), pc);
1908
+ }
1909
+ if (!parts.mnemonic)
1910
+ continue;
1911
+ const m = parts.mnemonic.toUpperCase();
1912
+ if (m === "EQU")
1913
+ continue;
1914
+ if (m === "ORG") {
1915
+ pc = evalExpr(parts.operands[0], symbols);
1916
+ continue;
1917
+ }
1918
+ if (m === "SECTION")
1919
+ continue;
1920
+ if (m === "END")
1921
+ break;
1922
+ if (m === "DB") {
1923
+ pc += countDb(parts.operands);
1924
+ continue;
1925
+ }
1926
+ if (m === "DW") {
1927
+ pc += parts.operands.length * 2;
1928
+ continue;
1929
+ }
1930
+ pc += instrSize(m);
1931
+ }
1932
+ const sections = [];
1933
+ let current = null;
1934
+ const sectionNames = new Set;
1935
+ for (const line of lines) {
1936
+ const parts = parseLine(line);
1937
+ if (parts.isEqu || !parts.mnemonic)
1938
+ continue;
1939
+ const m = parts.mnemonic.toUpperCase();
1940
+ if (m === "EQU")
1941
+ continue;
1942
+ if (m === "ORG") {
1943
+ if (current && current.data.length) {
1944
+ current.end = current.start + current.data.length - 1;
1945
+ sections.push(current);
1946
+ }
1947
+ const addr = evalExpr(parts.operands[0], symbols);
1948
+ current = { start: addr, end: addr, data: [] };
1949
+ continue;
1950
+ }
1951
+ if (m === "SECTION") {
1952
+ if (!current)
1953
+ throw new Error("SECTION before ORG");
1954
+ const name = parts.operands[0];
1955
+ if (!name)
1956
+ throw new Error("SECTION requires a name");
1957
+ if (sectionNames.has(name.toUpperCase()))
1958
+ throw new Error(`duplicate section name: ${name}`);
1959
+ sectionNames.add(name.toUpperCase());
1960
+ current.name = name;
1961
+ continue;
1962
+ }
1963
+ if (m === "END")
1964
+ break;
1965
+ if (!current)
1966
+ throw new Error("code before ORG");
1967
+ const bytes = m === "DB" ? dbBytes(parts.operands, symbols) : m === "DW" ? dwBytes(parts.operands, symbols) : encode(m, parts.operands, symbols);
1968
+ current.data.push(...bytes);
1969
+ }
1970
+ if (current && current.data.length) {
1971
+ current.end = current.start + current.data.length - 1;
1972
+ sections.push(current);
1973
+ }
1974
+ return sections;
1975
+ }
1976
+ if (false) {}
1977
+
1591
1978
  // src/lib/terminal/rk86_terminal.ts
1592
1979
  import { existsSync } from "fs";
1980
+ import { readFile } from "fs/promises";
1593
1981
  // packages/rk86/package.json
1594
1982
  var package_default = {
1595
1983
  name: "rk86",
1596
- version: "2.0.12",
1984
+ version: "2.0.14",
1597
1985
  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",
1598
1986
  bin: {
1599
1987
  rk86: "rk86.js"
@@ -1615,9 +2003,6 @@ var package_default = {
1615
2003
  }
1616
2004
  };
1617
2005
 
1618
- // src/lib/terminal/rk86_terminal.ts
1619
- import { readFile } from "fs/promises";
1620
-
1621
2006
  // src/lib/core/hex.ts
1622
2007
  function hex(v, prefix) {
1623
2008
  return v.toString(16).toUpperCase();
@@ -3033,7 +3418,7 @@ class Runner {
3033
3418
  }
3034
3419
  }
3035
3420
  execute(options = {}) {
3036
- const { terminate_address, on_terminate, exit_on_halt } = options;
3421
+ const { terminate_address, on_terminate, exit_on_halt, armed } = options;
3037
3422
  clearTimeout(this.execute_timer);
3038
3423
  if (!this.paused) {
3039
3424
  let batch_ticks = 0;
@@ -3061,6 +3446,8 @@ class Runner {
3061
3446
  this.machine.ui.on_visualizer_hit(this.machine.memory.read_raw(this.machine.cpu.pc));
3062
3447
  }
3063
3448
  batch_instructions += 1;
3449
+ if (armed?.value === false)
3450
+ continue;
3064
3451
  if (terminate_address !== undefined && this.machine.cpu.pc === terminate_address) {
3065
3452
  on_terminate?.();
3066
3453
  return;
@@ -3655,6 +4042,7 @@ function printHelp() {
3655
4042
  -l \u0441\u043F\u0438\u0441\u043E\u043A \u0444\u0430\u0439\u043B\u043E\u0432 \u0438\u0437 \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430
3656
4043
  -m <\u0444\u0430\u0439\u043B> \u043C\u043E\u043D\u0438\u0442\u043E\u0440 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E: \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0439 mon32.bin)
3657
4044
  -p \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0444\u0430\u0439\u043B \u0431\u0435\u0437 \u0437\u0430\u043F\u0443\u0441\u043A\u0430
4045
+ -g <\u0430\u0434\u0440\u0435\u0441> \u0430\u0434\u0440\u0435\u0441 \u0437\u0430\u043F\u0443\u0441\u043A\u0430 (\u043D\u0435\u0441\u043E\u0432\u043C\u0435\u0441\u0442\u0438\u043C \u0441 -p)
3658
4046
  --exit-halt \u0432\u044B\u0445\u043E\u0434 \u043F\u0440\u0438 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0438 HLT
3659
4047
  --exit-address [\u0430\u0434\u0440\u0435\u0441] \u0432\u044B\u0445\u043E\u0434 \u043F\u0440\u0438 \u043F\u0435\u0440\u0435\u0445\u043E\u0434\u0435 \u043D\u0430 \u0430\u0434\u0440\u0435\u0441 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E: 0xFFFE)
3660
4048
 
@@ -3666,6 +4054,8 @@ function printHelp() {
3666
4054
  bunx rk86 --exit-halt prog.bin \u0432\u044B\u0445\u043E\u0434 \u043F\u0440\u0438 HLT
3667
4055
  bunx rk86 --exit-address prog.bin \u0432\u044B\u0445\u043E\u0434 \u043F\u0440\u0438 JMP FFFEh
3668
4056
  bunx rk86 -l \u0441\u043F\u0438\u0441\u043E\u043A \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0445 \u0444\u0430\u0439\u043B\u043E\u0432
4057
+ bunx rk86 --exit-halt prog.asm \u0441\u043E\u0431\u0440\u0430\u0442\u044C \u0438 \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C .asm \u0444\u0430\u0439\u043B
4058
+ bunx rk86 -g 0x100 prog.bin \u0437\u0430\u043F\u0443\u0441\u043A \u0441 \u0430\u0434\u0440\u0435\u0441\u0430 100h
3669
4059
 
3670
4060
  \u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435:
3671
4061
  Ctrl+C \u0432\u044B\u0445\u043E\u0434`);
@@ -3716,6 +4106,11 @@ async function main() {
3716
4106
  process.exit(0);
3717
4107
  }
3718
4108
  const loadOnly = flag(args, "-p");
4109
+ const goAddr = arg(args, "-g", undefined, /^0x[0-9a-fA-F]+$/i, (v) => parseInt(v, 16));
4110
+ if (loadOnly && goAddr !== undefined) {
4111
+ console.error("\u043E\u0448\u0438\u0431\u043A\u0430: -p \u0438 -g \u043D\u0435\u0441\u043E\u0432\u043C\u0435\u0441\u0442\u0438\u043C\u044B");
4112
+ process.exit(1);
4113
+ }
3719
4114
  const exitOnHalt = flag(args, "--exit-halt");
3720
4115
  const exitAddrValue = arg(args, "--exit-address", "0xFFFE", /^0x[0-9a-fA-F]+$/i, (v) => parseInt(v, 16));
3721
4116
  const exitAddr = exitAddrValue !== undefined;
@@ -3742,18 +4137,44 @@ async function main() {
3742
4137
  let entryPoint;
3743
4138
  let loadInfo = "";
3744
4139
  if (programFile) {
3745
- const content = await fetchFile(programFile);
3746
- const { ok, json } = parse(content);
3747
- if (ok) {
3748
- rk86_snapshot_restore(json, machine);
3749
- entryPoint = parseInt(json.cpu.pc);
3750
- loadInfo = `\u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043D: ${programFile} (PC=${hex16(entryPoint)})`;
4140
+ const ext = file_ext(programFile).toLowerCase();
4141
+ if (ext === "asm") {
4142
+ const source = await readFile(programFile, "utf-8");
4143
+ const sections = asm(source);
4144
+ if (sections.length === 0) {
4145
+ console.error("\u043E\u0448\u0438\u0431\u043A\u0430: \u0430\u0441\u0441\u0435\u043C\u0431\u043B\u0435\u0440 \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B \u0441\u0435\u043A\u0446\u0438\u0439");
4146
+ process.exit(1);
4147
+ }
4148
+ const lines = [];
4149
+ for (const section of sections) {
4150
+ const data = section.data;
4151
+ for (let i = 0;i < data.length; i++) {
4152
+ machine.memory.write(section.start + i, data[i]);
4153
+ }
4154
+ const name = section.name ? ` [${section.name}]` : "";
4155
+ lines.push(`${hex16(section.start)}-${hex16(section.end)}${name} (${data.length} \u0431\u0430\u0439\u0442)`);
4156
+ }
4157
+ entryPoint = goAddr ?? sections[0].start;
4158
+ loadInfo = `\u0441\u043E\u0431\u0440\u0430\u043D: ${programFile}
4159
+ ` + lines.join(`
4160
+ `) + `
4161
+ \u0437\u0430\u043F\u0443\u0441\u043A: G${hex16(entryPoint)}`;
3751
4162
  } else {
3752
- const file = parse_rk86_binary(programFile, content);
3753
- machine.memory.load_file(file);
3754
- entryPoint = file.entry;
3755
- loadInfo = `\u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043D: ${programFile} (${hex16(file.start)}-${hex16(file.end)}, G${hex16(file.entry)})`;
4163
+ const content = await fetchFile(programFile);
4164
+ const { ok, json } = parse(content);
4165
+ if (ok) {
4166
+ rk86_snapshot_restore(json, machine);
4167
+ entryPoint = parseInt(json.cpu.pc);
4168
+ loadInfo = `\u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043D: ${programFile} (PC=${hex16(entryPoint)})`;
4169
+ } else {
4170
+ const file = parse_rk86_binary(programFile, content);
4171
+ machine.memory.load_file(file);
4172
+ entryPoint = file.entry;
4173
+ loadInfo = `\u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043D: ${programFile} (${hex16(file.start)}-${hex16(file.end)}, G${hex16(file.entry)})`;
4174
+ }
3756
4175
  }
4176
+ if (goAddr !== undefined)
4177
+ entryPoint = goAddr;
3757
4178
  }
3758
4179
  process.stdout.write("\x1B[?25l");
3759
4180
  process.stdout.write("\x1B[2J");
@@ -3763,17 +4184,24 @@ async function main() {
3763
4184
  machine.screen.start(renderer);
3764
4185
  const onTerminate = exitOnHalt || exitAddr ? () => {
3765
4186
  renderer.update();
3766
- console.log();
3767
- console.log("\u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0430 \u0440\u0430\u0431\u043E\u0442\u0443 \u043D\u0430", hex16(machine.cpu.pc));
3768
- process.exit(0);
4187
+ setTimeout(() => {
4188
+ console.log();
4189
+ console.log("\u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0430 \u0440\u0430\u0431\u043E\u0442\u0443 \u043D\u0430", hex16(machine.cpu.pc));
4190
+ process.exit(0);
4191
+ }, 1000);
3769
4192
  } : undefined;
4193
+ const armed = { value: entryPoint === undefined };
3770
4194
  machine.runner.execute({
3771
4195
  terminate_address: exitAddr ? exitAddrValue : undefined,
3772
4196
  exit_on_halt: exitOnHalt,
3773
- on_terminate: onTerminate
4197
+ on_terminate: onTerminate,
4198
+ armed
3774
4199
  });
3775
4200
  if (entryPoint !== undefined && !loadOnly) {
3776
- setTimeout(() => machine.cpu.jump(entryPoint), 500);
4201
+ setTimeout(() => {
4202
+ machine.cpu.jump(entryPoint);
4203
+ armed.value = true;
4204
+ }, 500);
3777
4205
  }
3778
4206
  process.on("exit", () => {
3779
4207
  process.stdout.write("\x1B[?25h");