rk86 2.0.6 → 2.0.7

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 +21 -143
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rk86",
3
- "version": "2.0.6",
3
+ "version": "2.0.7",
4
4
  "description": "Эмулятор Радио-86РК (Intel 8080) для терминала",
5
5
  "bin": {
6
6
  "rk86": "rk86.js"
package/rk86.js CHANGED
@@ -3103,11 +3103,6 @@ class Screen {
3103
3103
  static #update_rate = 25;
3104
3104
  machine;
3105
3105
  cursor_rate;
3106
- char_width;
3107
- char_height;
3108
- char_height_gap;
3109
- cursor_width;
3110
- cursor_height;
3111
3106
  scale_x;
3112
3107
  scale_y;
3113
3108
  width;
@@ -3115,22 +3110,15 @@ class Screen {
3115
3110
  cursor_state;
3116
3111
  cursor_x;
3117
3112
  cursor_y;
3118
- last_cursor_state;
3119
- last_cursor_x;
3120
- last_cursor_y;
3121
- font;
3122
3113
  light_pen_x;
3123
3114
  light_pen_y;
3124
3115
  light_pen_active;
3125
- ctx;
3116
+ video_memory_base = 0;
3117
+ video_memory_size = 0;
3118
+ renderer;
3126
3119
  constructor(machine) {
3127
3120
  this.machine = machine;
3128
3121
  this.cursor_rate = 500;
3129
- this.char_width = 6;
3130
- this.char_height = 8;
3131
- this.char_height_gap = 2;
3132
- this.cursor_width = this.char_width;
3133
- this.cursor_height = 1;
3134
3122
  this.scale_x = 1;
3135
3123
  this.scale_y = 1;
3136
3124
  this.width = 78;
@@ -3138,11 +3126,6 @@ class Screen {
3138
3126
  this.cursor_state = false;
3139
3127
  this.cursor_x = 0;
3140
3128
  this.cursor_y = 0;
3141
- this.last_cursor_state = false;
3142
- this.last_cursor_x = 0;
3143
- this.last_cursor_y = 0;
3144
- this.font = new Image;
3145
- this.font.src = this.machine.font;
3146
3129
  this.light_pen_x = 0;
3147
3130
  this.light_pen_y = 0;
3148
3131
  this.light_pen_active = 0;
@@ -3183,73 +3166,32 @@ class Screen {
3183
3166
  this.set_geometry(this.width, this.height);
3184
3167
  this.set_video_memory(this.video_memory_base);
3185
3168
  }
3186
- start() {
3187
- this.init();
3188
- this.draw_screen();
3169
+ start(renderer) {
3170
+ this.renderer = renderer;
3171
+ this.renderer.connect(this.machine);
3189
3172
  this.flip_cursor();
3190
- this.machine.ui.canvas.onmousemove = this.handle_mousemove.bind(this);
3191
- this.machine.ui.canvas.onmouseup = () => this.light_pen_active = 0;
3192
- this.machine.ui.canvas.onmousedown = () => this.light_pen_active = 1;
3193
- }
3194
- cache = [];
3195
- init_cache(sz) {
3196
- for (let i = 0;i < sz; ++i)
3197
- this.cache[i] = -1;
3198
- }
3199
- draw_char(x, y, ch) {
3200
- this.ctx.drawImage(this.font, 2, this.char_height * ch, this.char_width, this.char_height, x * this.char_width * this.scale_x, y * (this.char_height + this.char_height_gap) * this.scale_y, this.char_width * this.scale_x, this.char_height * this.scale_y);
3201
- }
3202
- draw_cursor(x, y, visible) {
3203
- const cy = (y2) => (y2 * (this.char_height + this.char_height_gap) + this.char_height) * this.scale_y;
3204
- if (this.last_cursor_x !== x || this.last_cursor_y !== y) {
3205
- if (this.last_cursor_state) {
3206
- this.ctx.fillStyle = "#000000";
3207
- this.ctx.fillRect(this.last_cursor_x * this.char_width * this.scale_x, cy(this.last_cursor_y), this.cursor_width * this.scale_x, this.cursor_height * this.scale_y);
3208
- }
3209
- this.last_cursor_state = this.cursor_state;
3210
- this.last_cursor_x = x;
3211
- this.last_cursor_y = y;
3212
- }
3213
- const cx = x * this.char_width * this.scale_x;
3214
- this.ctx.fillStyle = visible ? "#ffffff" : "#000000";
3215
- this.ctx.fillRect(cx, cy(y), this.cursor_width * this.scale_x, this.cursor_height * this.scale_y);
3216
- }
3217
- flip_cursor() {
3218
- this.draw_cursor(this.cursor_x, this.cursor_y, this.cursor_state);
3219
- this.cursor_state = !this.cursor_state;
3220
- setTimeout(() => this.flip_cursor(), this.cursor_rate);
3221
- }
3222
- init() {
3223
- this.ctx = this.machine.ui.canvas.getContext("2d");
3173
+ this.render_loop();
3224
3174
  }
3225
- disable_smoothing() {
3226
- this.ctx.imageSmoothingEnabled = false;
3175
+ render_loop() {
3176
+ this.renderer.update();
3177
+ setTimeout(() => this.render_loop(), Screen.#update_rate);
3227
3178
  }
3228
3179
  last_width = 0;
3229
3180
  last_height = 0;
3230
- video_memory_size = 0;
3231
3181
  set_geometry(width, height) {
3232
3182
  this.width = width;
3233
3183
  this.height = height;
3234
3184
  this.video_memory_size = width * height;
3235
3185
  this.machine.ui.update_screen_geometry(this.width, this.height);
3236
- const canvas_width = this.width * this.char_width * this.scale_x;
3237
- const canvas_height = this.height * (this.char_height + this.char_height_gap) * this.scale_y;
3238
- this.machine.ui.resize_canvas(canvas_width, canvas_height);
3239
- this.disable_smoothing();
3240
- this.ctx.fillStyle = "#000000";
3241
- this.ctx.fillRect(0, 0, canvas_width, canvas_height);
3242
3186
  if (this.last_width === this.width && this.last_height === this.height)
3243
3187
  return;
3244
3188
  console.log(`\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D \u0440\u0430\u0437\u043C\u0435\u0440 \u044D\u043A\u0440\u0430\u043D\u0430: ${width} x ${height}`);
3245
3189
  this.last_width = this.width;
3246
3190
  this.last_height = this.height;
3247
3191
  }
3248
- video_memory_base = 0;
3249
3192
  last_video_memory_base = 0;
3250
3193
  set_video_memory(base) {
3251
3194
  this.video_memory_base = base;
3252
- this.init_cache(this.video_memory_size);
3253
3195
  this.machine.ui.update_video_memory_address(this.video_memory_base);
3254
3196
  if (this.last_video_memory_base === this.video_memory_base)
3255
3197
  return;
@@ -3257,37 +3199,12 @@ class Screen {
3257
3199
  this.last_video_memory_base = this.video_memory_base;
3258
3200
  }
3259
3201
  set_cursor(x, y) {
3260
- this.draw_cursor(this.cursor_x, this.cursor_y, false);
3261
3202
  this.cursor_x = x;
3262
3203
  this.cursor_y = y;
3263
3204
  }
3264
- draw_screen() {
3265
- const memory = this.machine.memory;
3266
- let i = this.video_memory_base;
3267
- for (let y = 0;y < this.height; ++y) {
3268
- for (let x = 0;x < this.width; ++x) {
3269
- const cache_i = i - this.video_memory_base;
3270
- const ch = memory.read(i);
3271
- if (this.cache[cache_i] !== ch) {
3272
- this.draw_char(x, y, ch);
3273
- this.cache[cache_i] = ch;
3274
- }
3275
- i += 1;
3276
- }
3277
- }
3278
- setTimeout(() => this.draw_screen(), Screen.#update_rate);
3279
- }
3280
- handle_mousemove(event) {
3281
- const canvas = this.machine.ui.canvas;
3282
- const box = canvas.getBoundingClientRect();
3283
- const scaleX = canvas.width / box.width;
3284
- const scaleY = canvas.height / box.height;
3285
- const mouseX = (event.clientX - box.left) * scaleX;
3286
- const mouseY = (event.clientY - box.top) * scaleY;
3287
- const x = Math.floor(mouseX / (this.char_width * this.scale_x));
3288
- const y = Math.floor(mouseY / ((this.char_height + this.char_height_gap) * this.scale_y));
3289
- this.light_pen_x = x;
3290
- this.light_pen_y = y;
3205
+ flip_cursor() {
3206
+ this.cursor_state = !this.cursor_state;
3207
+ setTimeout(() => this.flip_cursor(), this.cursor_rate);
3291
3208
  }
3292
3209
  }
3293
3210
 
@@ -3393,8 +3310,6 @@ class Tape {
3393
3310
  }
3394
3311
 
3395
3312
  // src/lib/rk86_terminal.ts
3396
- globalThis.Image = class {
3397
- };
3398
3313
  var charMap = {
3399
3314
  0: " ",
3400
3315
  1: "\u2598",
@@ -3560,35 +3475,25 @@ class IO {
3560
3475
  interrupt = (_iff) => {};
3561
3476
  }
3562
3477
 
3563
- class TerminalScreen {
3478
+ class TerminalRenderer {
3564
3479
  machine;
3565
- width = 78;
3566
- height = 30;
3567
- video_memory_base = 0;
3568
- timer;
3569
- constructor(machine) {
3480
+ connect(machine) {
3570
3481
  this.machine = machine;
3571
3482
  }
3572
- start() {
3573
- this.render();
3574
- }
3575
- render() {
3483
+ update() {
3576
3484
  const { memory, screen } = this.machine;
3577
- const cursorX = screen.cursor_x;
3578
- const cursorY = screen.cursor_y;
3579
- const cursorVisible = screen.cursor_state;
3580
3485
  const dim = "\x1B[2m";
3581
3486
  const reset = "\x1B[0m";
3582
- const w = this.width;
3487
+ const w = screen.width;
3583
3488
  let output = "\x1B[H";
3584
3489
  output += `${dim}\u250C${"\u2500".repeat(w)}\u2510${reset}
3585
3490
  `;
3586
- let addr = this.video_memory_base;
3587
- for (let y = 0;y < this.height; y++) {
3491
+ let addr = screen.video_memory_base;
3492
+ for (let y = 0;y < screen.height; y++) {
3588
3493
  let line = `${dim}\u2502${reset}`;
3589
3494
  for (let x = 0;x < w; x++) {
3590
3495
  const ch = rk86char(memory.read(addr));
3591
- if (x === cursorX && y === cursorY) {
3496
+ if (x === screen.cursor_x && y === screen.cursor_y) {
3592
3497
  line += `\x1B[4m${ch}${reset}`;
3593
3498
  } else {
3594
3499
  line += ch;
@@ -3602,7 +3507,6 @@ class TerminalScreen {
3602
3507
  output += `${dim}\u2514${"\u2500".repeat(w)}\u2518${reset}
3603
3508
  `;
3604
3509
  process.stdout.write(output);
3605
- this.timer = setTimeout(() => this.render(), 40);
3606
3510
  }
3607
3511
  }
3608
3512
  var KEY_MAP = {
@@ -3788,34 +3692,8 @@ async function main() {
3788
3692
  process.stdout.write("\x1B[?25l");
3789
3693
  process.stdout.write("\x1B[2J");
3790
3694
  setupKeyboard(keyboard);
3791
- const termScreen = new TerminalScreen(machine);
3792
- const origSetGeometry = machine.screen.set_geometry.bind(machine.screen);
3793
- machine.screen.set_geometry = (width, height) => {
3794
- origSetGeometry(width, height);
3795
- termScreen.width = width;
3796
- termScreen.height = height;
3797
- };
3798
- const origSetVideoMemory = machine.screen.set_video_memory.bind(machine.screen);
3799
- machine.screen.set_video_memory = (base) => {
3800
- origSetVideoMemory(base);
3801
- termScreen.video_memory_base = base;
3802
- };
3803
- const noopCtx = {
3804
- imageSmoothingEnabled: false,
3805
- fillStyle: "",
3806
- fillRect() {},
3807
- drawImage() {},
3808
- clearRect() {}
3809
- };
3810
- machine.screen.ctx = noopCtx;
3811
- machine.screen.init = () => {
3812
- machine.screen.ctx = noopCtx;
3813
- };
3814
- machine.screen.draw_screen = () => {};
3815
- machine.screen.draw_cursor = () => {};
3816
- machine.screen.start();
3695
+ machine.screen.start(new TerminalRenderer);
3817
3696
  machine.runner.execute();
3818
- termScreen.start();
3819
3697
  if (entryPoint !== undefined && !loadOnly) {
3820
3698
  setTimeout(() => machine.cpu.jump(entryPoint), 500);
3821
3699
  }