rk86 2.0.29 → 2.0.30
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/README.md +2 -0
- package/package.json +1 -1
- package/rk86.js +90 -19
package/README.md
CHANGED
|
@@ -31,6 +31,8 @@ bunx rk86 --online CHESS.GAM # открыть файл в онлайн-э
|
|
|
31
31
|
--memory-to <адрес> конец области дампа памяти включительно (по умолчанию: 0xFFFF)
|
|
32
32
|
--screen <файл> сохранить экран 78x30 как текст при выходе
|
|
33
33
|
--input <seq> инъекция клавиш (через запятую): KeyA,Digit1,Enter,...
|
|
34
|
+
--color <0|1|2|3> режим цвета: 0=ч/б (по умолчанию), 1=Толкалин,
|
|
35
|
+
2=Акименко, 3=Апогей
|
|
34
36
|
--online открыть в онлайн-эмуляторе rk86.ru
|
|
35
37
|
```
|
|
36
38
|
|
package/package.json
CHANGED
package/rk86.js
CHANGED
|
@@ -871,7 +871,7 @@ import { basename } from "path";
|
|
|
871
871
|
// packages/rk86/package.json
|
|
872
872
|
var package_default = {
|
|
873
873
|
name: "rk86",
|
|
874
|
-
version: "2.0.
|
|
874
|
+
version: "2.0.29",
|
|
875
875
|
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",
|
|
876
876
|
bin: {
|
|
877
877
|
rk86: "rk86.js"
|
|
@@ -893,6 +893,59 @@ var package_default = {
|
|
|
893
893
|
}
|
|
894
894
|
};
|
|
895
895
|
|
|
896
|
+
// src/lib/core/rk86_colors.ts
|
|
897
|
+
var COLOR_MODES = ["mono", "color1", "color2", "color3"];
|
|
898
|
+
var DEFAULT_COLOR_MODE = "color1";
|
|
899
|
+
function attrToRgb(mode, attrs) {
|
|
900
|
+
const hglt = (attrs & 1) !== 0;
|
|
901
|
+
const gpa0 = (attrs & 4) !== 0;
|
|
902
|
+
const gpa1 = (attrs & 8) !== 0;
|
|
903
|
+
switch (mode) {
|
|
904
|
+
case "color1": {
|
|
905
|
+
const rgb = (gpa1 ? 255 : 0) | (gpa0 ? 65280 : 0) | (hglt ? 16711680 : 0);
|
|
906
|
+
return rgb === 0 ? 12632256 : rgb;
|
|
907
|
+
}
|
|
908
|
+
case "color2":
|
|
909
|
+
return (gpa0 ? 0 : 16711680) | (gpa1 ? 0 : 65280) | (hglt ? 0 : 255);
|
|
910
|
+
case "color3":
|
|
911
|
+
return (gpa0 ? 0 : 255) | (gpa1 ? 0 : 65280) | (hglt ? 0 : 16711680);
|
|
912
|
+
case "mono":
|
|
913
|
+
default:
|
|
914
|
+
return 12632256;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
function hasCellOffset(mode) {
|
|
918
|
+
return mode !== "color3";
|
|
919
|
+
}
|
|
920
|
+
function rgbToAnsiBaseFg(rgb) {
|
|
921
|
+
const r = rgb >> 16 & 255;
|
|
922
|
+
const g = rgb >> 8 & 255;
|
|
923
|
+
const b = rgb & 255;
|
|
924
|
+
const palette = [
|
|
925
|
+
[30, 0, 0, 0],
|
|
926
|
+
[31, 255, 0, 0],
|
|
927
|
+
[32, 0, 255, 0],
|
|
928
|
+
[33, 255, 255, 0],
|
|
929
|
+
[34, 0, 0, 255],
|
|
930
|
+
[35, 255, 0, 255],
|
|
931
|
+
[36, 0, 255, 255],
|
|
932
|
+
[37, 255, 255, 255]
|
|
933
|
+
];
|
|
934
|
+
let best = 37;
|
|
935
|
+
let bestDist = Infinity;
|
|
936
|
+
for (const [code, pr, pg, pb] of palette) {
|
|
937
|
+
const dr = r - pr;
|
|
938
|
+
const dg = g - pg;
|
|
939
|
+
const db = b - pb;
|
|
940
|
+
const dist = dr * dr + dg * dg + db * db;
|
|
941
|
+
if (dist < bestDist) {
|
|
942
|
+
bestDist = dist;
|
|
943
|
+
best = code;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
return best;
|
|
947
|
+
}
|
|
948
|
+
|
|
896
949
|
// src/lib/core/hex.ts
|
|
897
950
|
function hex(v, prefix) {
|
|
898
951
|
return v.toString(16).toUpperCase();
|
|
@@ -2347,7 +2400,7 @@ class Runner {
|
|
|
2347
2400
|
}
|
|
2348
2401
|
}
|
|
2349
2402
|
execute(options = {}) {
|
|
2350
|
-
const { terminate_address, on_terminate, exit_on_halt, on_batch_complete, turbo } = options;
|
|
2403
|
+
const { terminate_address, on_terminate, exit_on_halt, on_halt, on_batch_complete, turbo } = options;
|
|
2351
2404
|
clearTimeout(this.execute_timer);
|
|
2352
2405
|
const bursts = turbo ? 100 : 1;
|
|
2353
2406
|
for (let burst = 0;burst < bursts; burst++) {
|
|
@@ -2382,9 +2435,13 @@ class Runner {
|
|
|
2382
2435
|
on_terminate?.();
|
|
2383
2436
|
return;
|
|
2384
2437
|
}
|
|
2385
|
-
if (
|
|
2386
|
-
|
|
2387
|
-
|
|
2438
|
+
if (this.machine.memory.read_raw(this.machine.cpu.pc) === 118) {
|
|
2439
|
+
if (exit_on_halt) {
|
|
2440
|
+
on_terminate?.();
|
|
2441
|
+
return;
|
|
2442
|
+
}
|
|
2443
|
+
if (on_halt && on_halt())
|
|
2444
|
+
return;
|
|
2388
2445
|
}
|
|
2389
2446
|
}
|
|
2390
2447
|
const now = performance.now();
|
|
@@ -2427,6 +2484,7 @@ class Screen {
|
|
|
2427
2484
|
video_memory_base = 0;
|
|
2428
2485
|
video_memory_size = 0;
|
|
2429
2486
|
transparent_attr = false;
|
|
2487
|
+
color_mode = DEFAULT_COLOR_MODE;
|
|
2430
2488
|
ready = false;
|
|
2431
2489
|
renderer;
|
|
2432
2490
|
constructor(machine) {
|
|
@@ -2848,16 +2906,17 @@ class TerminalRenderer {
|
|
|
2848
2906
|
const dim = "\x1B[2m";
|
|
2849
2907
|
const reset = "\x1B[0m";
|
|
2850
2908
|
const w = screen.width;
|
|
2851
|
-
const
|
|
2909
|
+
const mode = screen.color_mode;
|
|
2852
2910
|
let output = "\x1B[H";
|
|
2853
2911
|
output += `${dim}\u250C${"\u2500".repeat(w)}\u2510${reset}
|
|
2854
2912
|
`;
|
|
2855
2913
|
const transparent = screen.transparent_attr;
|
|
2914
|
+
const offset = hasCellOffset(mode) && !transparent;
|
|
2856
2915
|
const blinkOff = Math.floor(Date.now() / 320) % 2 === 1;
|
|
2857
2916
|
const FA_PENDING = -1;
|
|
2858
2917
|
let addr = screen.video_memory_base;
|
|
2859
2918
|
let frameStopped = false;
|
|
2860
|
-
let
|
|
2919
|
+
let latchedAttrs = 0;
|
|
2861
2920
|
let blink = false;
|
|
2862
2921
|
for (let y = 0;y < screen.height; y++) {
|
|
2863
2922
|
let line = `${dim}\u2502${reset}`;
|
|
@@ -2877,23 +2936,23 @@ class TerminalRenderer {
|
|
|
2877
2936
|
continue;
|
|
2878
2937
|
}
|
|
2879
2938
|
if (raw >= 240) {
|
|
2880
|
-
cells[cellCount++] = { ch: 0,
|
|
2939
|
+
cells[cellCount++] = { ch: 0, attrs: latchedAttrs, blink, isFA: false };
|
|
2881
2940
|
rowStopped = true;
|
|
2882
2941
|
if (raw >= 248)
|
|
2883
2942
|
frameStopped = true;
|
|
2884
2943
|
} else if (raw >= 192) {
|
|
2885
|
-
cells[cellCount++] = { ch: 0,
|
|
2944
|
+
cells[cellCount++] = { ch: 0, attrs: latchedAttrs, blink, isFA: false };
|
|
2886
2945
|
} else if (raw >= 128) {
|
|
2887
|
-
|
|
2946
|
+
latchedAttrs = raw;
|
|
2888
2947
|
blink = (raw & 2) !== 0;
|
|
2889
|
-
cells[cellCount++] = { ch: FA_PENDING,
|
|
2948
|
+
cells[cellCount++] = { ch: FA_PENDING, attrs: latchedAttrs, blink, isFA: true };
|
|
2890
2949
|
fifoFlag = true;
|
|
2891
2950
|
} else {
|
|
2892
|
-
cells[cellCount++] = { ch: raw,
|
|
2951
|
+
cells[cellCount++] = { ch: raw, attrs: latchedAttrs, blink, isFA: false };
|
|
2893
2952
|
}
|
|
2894
2953
|
}
|
|
2895
2954
|
while (cellCount < w)
|
|
2896
|
-
cells[cellCount++] = { ch: 0,
|
|
2955
|
+
cells[cellCount++] = { ch: 0, attrs: latchedAttrs, blink, isFA: false };
|
|
2897
2956
|
let fifoIdx = 0;
|
|
2898
2957
|
for (let x = 0;x < w; ++x) {
|
|
2899
2958
|
if (cells[x].ch === FA_PENDING) {
|
|
@@ -2910,6 +2969,7 @@ class TerminalRenderer {
|
|
|
2910
2969
|
for (let x = 0;x < w; x++) {
|
|
2911
2970
|
const raw = memory.read(addr + x);
|
|
2912
2971
|
let ch;
|
|
2972
|
+
let isFA = false;
|
|
2913
2973
|
if (rowStopped) {
|
|
2914
2974
|
ch = 0;
|
|
2915
2975
|
} else if (raw >= 240) {
|
|
@@ -2920,24 +2980,30 @@ class TerminalRenderer {
|
|
|
2920
2980
|
} else if (raw >= 192) {
|
|
2921
2981
|
ch = 0;
|
|
2922
2982
|
} else if (raw >= 128) {
|
|
2923
|
-
|
|
2983
|
+
latchedAttrs = raw;
|
|
2924
2984
|
blink = (raw & 2) !== 0;
|
|
2925
2985
|
ch = 0;
|
|
2986
|
+
isFA = true;
|
|
2926
2987
|
} else {
|
|
2927
2988
|
ch = raw;
|
|
2928
2989
|
}
|
|
2929
|
-
cells[x] = { ch,
|
|
2990
|
+
cells[x] = { ch, attrs: latchedAttrs, blink, isFA };
|
|
2930
2991
|
}
|
|
2931
2992
|
addr += w;
|
|
2932
2993
|
}
|
|
2933
|
-
let
|
|
2994
|
+
let prevAnsi = -1;
|
|
2934
2995
|
for (let x = 0;x < w; x++) {
|
|
2935
2996
|
const cell = cells[x];
|
|
2936
2997
|
const ch = cell.blink && blinkOff ? 0 : cell.ch;
|
|
2937
2998
|
const glyph = rk86char(ch);
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2999
|
+
let attrs = cell.attrs;
|
|
3000
|
+
if (offset && x + 1 < w && cells[x + 1].isFA) {
|
|
3001
|
+
attrs = cells[x + 1].attrs;
|
|
3002
|
+
}
|
|
3003
|
+
const ansi = rgbToAnsiBaseFg(attrToRgb(mode, attrs));
|
|
3004
|
+
if (ansi !== prevAnsi) {
|
|
3005
|
+
line += `\x1B[${ansi}m`;
|
|
3006
|
+
prevAnsi = ansi;
|
|
2941
3007
|
}
|
|
2942
3008
|
if (x === screen.cursor_x && y === screen.cursor_y) {
|
|
2943
3009
|
line += `\x1B[4m${glyph}\x1B[24m`;
|
|
@@ -3106,6 +3172,8 @@ function printHelp() {
|
|
|
3106
3172
|
--snapshot <\u0444\u0430\u0439\u043B> \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0441\u043D\u0438\u043C\u043E\u043A \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F (JSON) \u043F\u0440\u0438 \u0432\u044B\u0445\u043E\u0434\u0435
|
|
3107
3173
|
--input <seq> \u0438\u043D\u044A\u0435\u043A\u0446\u0438\u044F \u043A\u043B\u0430\u0432\u0438\u0448 (\u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043F\u044F\u0442\u0443\u044E): KeyA,Digit1,Enter,...
|
|
3108
3174
|
\u0442\u043E\u043A\u0435\u043D *N \u0437\u0430\u0434\u0430\u0451\u0442 \u043F\u0430\u0443\u0437\u0443 N \u043C\u0441 (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 *200)
|
|
3175
|
+
--color <0|1|2|3> \u0440\u0435\u0436\u0438\u043C \u0446\u0432\u0435\u0442\u0430: 0=\u0447/\u0431 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E), 1=\u0422\u043E\u043B\u043A\u0430\u043B\u0438\u043D,
|
|
3176
|
+
2=\u0410\u043A\u0438\u043C\u0435\u043D\u043A\u043E, 3=\u0410\u043F\u043E\u0433\u0435\u0439
|
|
3109
3177
|
--online \u043E\u0442\u043A\u0440\u044B\u0442\u044C \u0432 \u043E\u043D\u043B\u0430\u0439\u043D-\u044D\u043C\u0443\u043B\u044F\u0442\u043E\u0440\u0435 rk86.ru
|
|
3110
3178
|
|
|
3111
3179
|
\u041F\u0440\u0438\u043C\u0435\u0440\u044B:
|
|
@@ -3210,6 +3278,8 @@ async function main() {
|
|
|
3210
3278
|
const screenFile = arg(args, "--screen");
|
|
3211
3279
|
const snapshotFile = arg(args, "--snapshot");
|
|
3212
3280
|
const goViaMonitor = arg(args, "-G", undefined, addrRe, parseAddr);
|
|
3281
|
+
const colorIdx = arg(args, "--color", "0", /^[0-3]$/, (v) => parseInt(v, 10)) ?? 0;
|
|
3282
|
+
const colorMode = COLOR_MODES[colorIdx];
|
|
3213
3283
|
let inputSeq = arg(args, "--input");
|
|
3214
3284
|
if (goViaMonitor !== undefined) {
|
|
3215
3285
|
const hex2 = goViaMonitor.toString(16).toUpperCase();
|
|
@@ -3231,6 +3301,7 @@ async function main() {
|
|
|
3231
3301
|
machine.memory = new Memory(machine);
|
|
3232
3302
|
machine.cpu = new I8080(machine);
|
|
3233
3303
|
machine.screen = new Screen(machine);
|
|
3304
|
+
machine.screen.color_mode = colorMode;
|
|
3234
3305
|
machine.tape = new Tape(machine);
|
|
3235
3306
|
machine.runner = new Runner(machine);
|
|
3236
3307
|
machine.memory.update_ruslat = machine.ui.update_ruslat;
|