@aptre/v86 0.5.0

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 (111) hide show
  1. package/LICENSE +22 -0
  2. package/LICENSE.MIT +22 -0
  3. package/Readme.md +237 -0
  4. package/dist/v86.browser.js +26666 -0
  5. package/dist/v86.browser.js.map +7 -0
  6. package/dist/v86.js +26632 -0
  7. package/dist/v86.js.map +7 -0
  8. package/gen/generate_analyzer.ts +512 -0
  9. package/gen/generate_interpreter.ts +522 -0
  10. package/gen/generate_jit.ts +624 -0
  11. package/gen/rust_ast.ts +107 -0
  12. package/gen/util.ts +35 -0
  13. package/gen/x86_table.ts +1836 -0
  14. package/lib/9p.ts +1547 -0
  15. package/lib/filesystem.ts +1879 -0
  16. package/lib/marshall.ts +168 -0
  17. package/lib/softfloat/softfloat.c +32501 -0
  18. package/lib/zstd/zstddeclib.c +13520 -0
  19. package/package.json +75 -0
  20. package/src/acpi.ts +267 -0
  21. package/src/browser/dummy_screen.ts +106 -0
  22. package/src/browser/fake_network.ts +1771 -0
  23. package/src/browser/fetch_network.ts +361 -0
  24. package/src/browser/filestorage.ts +124 -0
  25. package/src/browser/inbrowser_network.ts +57 -0
  26. package/src/browser/keyboard.ts +564 -0
  27. package/src/browser/main.ts +3415 -0
  28. package/src/browser/mouse.ts +255 -0
  29. package/src/browser/network.ts +142 -0
  30. package/src/browser/print_stats.ts +336 -0
  31. package/src/browser/screen.ts +978 -0
  32. package/src/browser/serial.ts +316 -0
  33. package/src/browser/speaker.ts +1223 -0
  34. package/src/browser/starter.ts +1688 -0
  35. package/src/browser/wisp_network.ts +332 -0
  36. package/src/browser/worker_bus.ts +64 -0
  37. package/src/buffer.ts +652 -0
  38. package/src/bus.ts +78 -0
  39. package/src/const.ts +128 -0
  40. package/src/cpu.ts +2891 -0
  41. package/src/dma.ts +474 -0
  42. package/src/elf.ts +251 -0
  43. package/src/floppy.ts +1778 -0
  44. package/src/ide.ts +3455 -0
  45. package/src/io.ts +504 -0
  46. package/src/iso9660.ts +317 -0
  47. package/src/kernel.ts +250 -0
  48. package/src/lib.ts +645 -0
  49. package/src/log.ts +149 -0
  50. package/src/main.ts +199 -0
  51. package/src/ne2k.ts +1589 -0
  52. package/src/pci.ts +815 -0
  53. package/src/pit.ts +406 -0
  54. package/src/ps2.ts +820 -0
  55. package/src/rtc.ts +537 -0
  56. package/src/rust/analysis.rs +101 -0
  57. package/src/rust/codegen.rs +2660 -0
  58. package/src/rust/config.rs +3 -0
  59. package/src/rust/control_flow.rs +425 -0
  60. package/src/rust/cpu/apic.rs +658 -0
  61. package/src/rust/cpu/arith.rs +1207 -0
  62. package/src/rust/cpu/call_indirect.rs +2 -0
  63. package/src/rust/cpu/cpu.rs +4501 -0
  64. package/src/rust/cpu/fpu.rs +923 -0
  65. package/src/rust/cpu/global_pointers.rs +112 -0
  66. package/src/rust/cpu/instructions.rs +2486 -0
  67. package/src/rust/cpu/instructions_0f.rs +5261 -0
  68. package/src/rust/cpu/ioapic.rs +316 -0
  69. package/src/rust/cpu/memory.rs +351 -0
  70. package/src/rust/cpu/misc_instr.rs +613 -0
  71. package/src/rust/cpu/mod.rs +16 -0
  72. package/src/rust/cpu/modrm.rs +133 -0
  73. package/src/rust/cpu/pic.rs +402 -0
  74. package/src/rust/cpu/sse_instr.rs +361 -0
  75. package/src/rust/cpu/string.rs +701 -0
  76. package/src/rust/cpu/vga.rs +175 -0
  77. package/src/rust/cpu_context.rs +69 -0
  78. package/src/rust/dbg.rs +98 -0
  79. package/src/rust/gen/analyzer.rs +3807 -0
  80. package/src/rust/gen/analyzer0f.rs +3992 -0
  81. package/src/rust/gen/interpreter.rs +4447 -0
  82. package/src/rust/gen/interpreter0f.rs +5404 -0
  83. package/src/rust/gen/jit.rs +5080 -0
  84. package/src/rust/gen/jit0f.rs +5547 -0
  85. package/src/rust/gen/mod.rs +14 -0
  86. package/src/rust/jit.rs +2443 -0
  87. package/src/rust/jit_instructions.rs +7881 -0
  88. package/src/rust/js_api.rs +6 -0
  89. package/src/rust/leb.rs +46 -0
  90. package/src/rust/lib.rs +29 -0
  91. package/src/rust/modrm.rs +330 -0
  92. package/src/rust/opstats.rs +249 -0
  93. package/src/rust/page.rs +15 -0
  94. package/src/rust/paging.rs +25 -0
  95. package/src/rust/prefix.rs +15 -0
  96. package/src/rust/profiler.rs +155 -0
  97. package/src/rust/regs.rs +38 -0
  98. package/src/rust/softfloat.rs +286 -0
  99. package/src/rust/state_flags.rs +27 -0
  100. package/src/rust/wasmgen/mod.rs +2 -0
  101. package/src/rust/wasmgen/wasm_builder.rs +1047 -0
  102. package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
  103. package/src/rust/zstd.rs +105 -0
  104. package/src/sb16.ts +1928 -0
  105. package/src/state.ts +359 -0
  106. package/src/uart.ts +472 -0
  107. package/src/vga.ts +2791 -0
  108. package/src/virtio.ts +1756 -0
  109. package/src/virtio_balloon.ts +273 -0
  110. package/src/virtio_console.ts +372 -0
  111. package/src/virtio_net.ts +326 -0
package/src/ps2.ts ADDED
@@ -0,0 +1,820 @@
1
+ import { LOG_PS2 } from './const.js'
2
+ import { h, ByteQueue } from './lib.js'
3
+ import { dbg_log } from './log.js'
4
+ import { IO } from './io.js'
5
+ import { BusConnector } from './bus.js'
6
+
7
+ const PS2_LOG_VERBOSE = false
8
+
9
+ // Minimal interface for CPU fields PS2 uses
10
+ interface PS2Cpu {
11
+ io: IO
12
+ device_raise_irq(irq: number): void
13
+ device_lower_irq(irq: number): void
14
+ reboot_internal(): void
15
+ }
16
+
17
+ type PS2State = [
18
+ boolean, // 0: enable_mouse_stream
19
+ boolean, // 1: use_mouse
20
+ boolean, // 2: have_mouse
21
+ number, // 3: mouse_delta_x
22
+ number, // 4: mouse_delta_y
23
+ number, // 5: mouse_clicks
24
+ boolean, // 6: have_keyboard
25
+ boolean, // 7: enable_keyboard_stream
26
+ boolean, // 8: next_is_mouse_command
27
+ boolean, // 9: next_read_sample
28
+ boolean, // 10: next_read_led
29
+ boolean, // 11: next_handle_scan_code_set
30
+ boolean, // 12: next_read_rate
31
+ boolean, // 13: next_read_resolution
32
+ undefined, // 14: kbd_buffer (unused)
33
+ number, // 15: last_port60_byte
34
+ number, // 16: sample_rate
35
+ number, // 17: resolution
36
+ boolean, // 18: scaling2
37
+ undefined, // 19: mouse_buffer (unused)
38
+ number, // 20: command_register
39
+ boolean, // 21: read_output_register
40
+ boolean, // 22: read_command_register
41
+ number, // 23: controller_output_port
42
+ boolean, // 24: read_controller_output_port
43
+ number, // 25: mouse_id
44
+ number, // 26: mouse_detect_state
45
+ boolean, // 27: mouse_reset_workaround
46
+ ]
47
+
48
+ /**
49
+ * PS2 controller for keyboard and mouse.
50
+ */
51
+ export class PS2 {
52
+ name: string
53
+ cpu: PS2Cpu
54
+ bus: BusConnector
55
+
56
+ enable_mouse_stream: boolean = false
57
+ use_mouse: boolean = false
58
+ have_mouse: boolean = true
59
+ mouse_delta_x: number = 0
60
+ mouse_delta_y: number = 0
61
+ mouse_clicks: number = 0
62
+ have_keyboard: boolean = true
63
+ enable_keyboard_stream: boolean = false
64
+ next_is_mouse_command: boolean = false
65
+ next_read_sample: boolean = false
66
+ next_read_led: boolean = false
67
+ next_handle_scan_code_set: boolean = false
68
+ next_read_rate: boolean = false
69
+ next_read_resolution: boolean = false
70
+ kbd_buffer: ByteQueue
71
+ last_port60_byte: number = 0
72
+ sample_rate: number = 100
73
+ mouse_detect_state: number = 0
74
+ mouse_id: number = 0x00
75
+ mouse_reset_workaround: boolean = false
76
+ wheel_movement: number = 0
77
+ resolution: number = 4
78
+ scaling2: boolean = false
79
+ last_mouse_packet: number = -1
80
+ mouse_buffer: ByteQueue
81
+ next_byte_is_ready: boolean = false
82
+ next_byte_is_aux: boolean = false
83
+ command_register: number = 0
84
+ controller_output_port: number = 0
85
+ read_output_register: boolean = false
86
+ read_command_register: boolean = false
87
+ read_controller_output_port: boolean = false
88
+
89
+ constructor(cpu: PS2Cpu, bus: BusConnector) {
90
+ this.name = 'ps2'
91
+ this.cpu = cpu
92
+ this.bus = bus
93
+
94
+ this.kbd_buffer = new ByteQueue(1024)
95
+ this.mouse_buffer = new ByteQueue(1024)
96
+
97
+ this.reset()
98
+
99
+ this.bus.register(
100
+ 'keyboard-code',
101
+ (code: number): void => {
102
+ this.kbd_send_code(code)
103
+ },
104
+ this,
105
+ )
106
+
107
+ this.bus.register(
108
+ 'mouse-click',
109
+ (data: [number, number, number]): void => {
110
+ this.mouse_send_click(data[0], data[1], data[2])
111
+ },
112
+ this,
113
+ )
114
+
115
+ this.bus.register(
116
+ 'mouse-delta',
117
+ (data: [number, number]): void => {
118
+ this.mouse_send_delta(data[0], data[1])
119
+ },
120
+ this,
121
+ )
122
+
123
+ this.bus.register(
124
+ 'mouse-wheel',
125
+ (data: [number, number]): void => {
126
+ this.wheel_movement -= data[0]
127
+ this.wheel_movement -= data[1] * 2 // X Wheel Movement
128
+ this.wheel_movement = Math.min(
129
+ 7,
130
+ Math.max(-8, this.wheel_movement),
131
+ )
132
+ this.send_mouse_packet(0, 0)
133
+ },
134
+ this,
135
+ )
136
+
137
+ cpu.io.register_read(0x60, this, this.port60_read.bind(this))
138
+ cpu.io.register_read(0x64, this, this.port64_read.bind(this))
139
+
140
+ cpu.io.register_write(0x60, this, this.port60_write.bind(this))
141
+ cpu.io.register_write(0x64, this, this.port64_write.bind(this))
142
+ }
143
+
144
+ reset(): void {
145
+ this.enable_mouse_stream = false
146
+ this.use_mouse = false
147
+ this.have_mouse = true
148
+ this.mouse_delta_x = 0
149
+ this.mouse_delta_y = 0
150
+ this.mouse_clicks = 0
151
+ this.have_keyboard = true
152
+ this.enable_keyboard_stream = false
153
+ this.next_is_mouse_command = false
154
+ this.next_read_sample = false
155
+ this.next_read_led = false
156
+ this.next_handle_scan_code_set = false
157
+ this.next_read_rate = false
158
+ this.next_read_resolution = false
159
+
160
+ this.kbd_buffer = new ByteQueue(1024)
161
+
162
+ this.last_port60_byte = 0
163
+
164
+ this.sample_rate = 100
165
+ this.mouse_detect_state = 0
166
+ this.mouse_id = 0x00
167
+ this.mouse_reset_workaround = false
168
+ this.wheel_movement = 0
169
+ this.resolution = 4
170
+ this.scaling2 = false
171
+ this.last_mouse_packet = -1
172
+
173
+ this.mouse_buffer = new ByteQueue(1024)
174
+
175
+ // Also known as DBBOUT OBF - Output Buffer Full flag
176
+ this.next_byte_is_ready = false
177
+ this.next_byte_is_aux = false
178
+
179
+ this.command_register = 1 | 4
180
+ // TODO: What should be the initial value?
181
+ this.controller_output_port = 0
182
+ this.read_output_register = false
183
+ this.read_command_register = false
184
+ this.read_controller_output_port = false
185
+ }
186
+
187
+ get_state(): PS2State {
188
+ const state: PS2State = [
189
+ this.enable_mouse_stream,
190
+ this.use_mouse,
191
+ this.have_mouse,
192
+ this.mouse_delta_x,
193
+ this.mouse_delta_y,
194
+ this.mouse_clicks,
195
+ this.have_keyboard,
196
+ this.enable_keyboard_stream,
197
+ this.next_is_mouse_command,
198
+ this.next_read_sample,
199
+ this.next_read_led,
200
+ this.next_handle_scan_code_set,
201
+ this.next_read_rate,
202
+ this.next_read_resolution,
203
+ undefined, //this.kbd_buffer;
204
+ this.last_port60_byte,
205
+ this.sample_rate,
206
+ this.resolution,
207
+ this.scaling2,
208
+ undefined, //this.mouse_buffer;
209
+ this.command_register,
210
+ this.read_output_register,
211
+ this.read_command_register,
212
+ this.controller_output_port,
213
+ this.read_controller_output_port,
214
+ this.mouse_id,
215
+ this.mouse_detect_state,
216
+ this.mouse_reset_workaround,
217
+ ]
218
+
219
+ return state
220
+ }
221
+
222
+ set_state(state: PS2State): void {
223
+ this.enable_mouse_stream = state[0]
224
+ this.use_mouse = state[1]
225
+ this.have_mouse = state[2]
226
+ this.mouse_delta_x = state[3]
227
+ this.mouse_delta_y = state[4]
228
+ this.mouse_clicks = state[5]
229
+ this.have_keyboard = state[6]
230
+ this.enable_keyboard_stream = state[7]
231
+ this.next_is_mouse_command = state[8]
232
+ this.next_read_sample = state[9]
233
+ this.next_read_led = state[10]
234
+ this.next_handle_scan_code_set = state[11]
235
+ this.next_read_rate = state[12]
236
+ this.next_read_resolution = state[13]
237
+ //this.kbd_buffer = state[14];
238
+ this.last_port60_byte = state[15]
239
+ this.sample_rate = state[16]
240
+ this.resolution = state[17]
241
+ this.scaling2 = state[18]
242
+ //this.mouse_buffer = state[19];
243
+ this.command_register = state[20]
244
+ this.read_output_register = state[21]
245
+ this.read_command_register = state[22]
246
+ this.controller_output_port = state[23]
247
+ this.read_controller_output_port = state[24]
248
+ this.mouse_id = state[25] || 0
249
+ this.mouse_detect_state = state[26] || 0
250
+ this.mouse_reset_workaround = state[27] || false
251
+
252
+ this.next_byte_is_ready = false
253
+ this.next_byte_is_aux = false
254
+ this.kbd_buffer.clear()
255
+ this.mouse_buffer.clear()
256
+
257
+ this.bus.send('mouse-enable', this.use_mouse)
258
+ }
259
+
260
+ raise_irq(): void {
261
+ if (this.next_byte_is_ready) {
262
+ // Wait until previous byte is read
263
+ // http://halicery.com/Hardware/8042/8042_1503033_TXT.htm
264
+ return
265
+ }
266
+
267
+ // Kbd has priority over aux
268
+ if (this.kbd_buffer.length) {
269
+ this.kbd_irq()
270
+ } else if (this.mouse_buffer.length) {
271
+ this.mouse_irq()
272
+ }
273
+ }
274
+
275
+ mouse_irq(): void {
276
+ this.next_byte_is_ready = true
277
+ this.next_byte_is_aux = true
278
+
279
+ if (this.command_register & 2) {
280
+ dbg_log('Mouse irq', LOG_PS2)
281
+
282
+ // Pulse the irq line
283
+ // Note: can't lower immediately after rising, so lower before rising
284
+ // http://www.os2museum.com/wp/ibm-ps2-model-50-keyboard-controller/
285
+ this.cpu.device_lower_irq(12)
286
+ this.cpu.device_raise_irq(12)
287
+ }
288
+ }
289
+
290
+ kbd_irq(): void {
291
+ this.next_byte_is_ready = true
292
+ this.next_byte_is_aux = false
293
+
294
+ if (this.command_register & 1) {
295
+ dbg_log('Keyboard irq', LOG_PS2)
296
+
297
+ // Pulse the irq line
298
+ // Note: can't lower immediately after rising, so lower before rising
299
+ // http://www.os2museum.com/wp/ibm-ps2-model-50-keyboard-controller/
300
+ this.cpu.device_lower_irq(1)
301
+ this.cpu.device_raise_irq(1)
302
+ }
303
+ }
304
+
305
+ kbd_send_code(code: number): void {
306
+ if (this.enable_keyboard_stream) {
307
+ dbg_log('adding kbd code: ' + h(code), LOG_PS2)
308
+ this.kbd_buffer.push(code)
309
+ this.raise_irq()
310
+ }
311
+ }
312
+
313
+ mouse_send_delta(delta_x: number, delta_y: number): void {
314
+ if (!this.have_mouse || !this.use_mouse) {
315
+ return
316
+ }
317
+
318
+ // note: delta_x or delta_y can be floating point numbers
319
+
320
+ //const factor = this.resolution * this.sample_rate / 80;
321
+ const factor = 1
322
+
323
+ this.mouse_delta_x += delta_x * factor
324
+ this.mouse_delta_y += delta_y * factor
325
+
326
+ if (this.enable_mouse_stream) {
327
+ const change_x = this.mouse_delta_x | 0,
328
+ change_y = this.mouse_delta_y | 0
329
+
330
+ if (change_x || change_y) {
331
+ //var now = Date.now();
332
+ //if(now - this.last_mouse_packet < 1000 / this.sample_rate)
333
+ //{
334
+ // // TODO: set timeout
335
+ // return;
336
+ //}
337
+
338
+ this.mouse_delta_x -= change_x
339
+ this.mouse_delta_y -= change_y
340
+
341
+ this.send_mouse_packet(change_x, change_y)
342
+ }
343
+ }
344
+ }
345
+
346
+ mouse_send_click(left: number, middle: number, right: number): void {
347
+ if (!this.have_mouse || !this.use_mouse) {
348
+ return
349
+ }
350
+
351
+ this.mouse_clicks = left | (right << 1) | (middle << 2)
352
+
353
+ if (this.enable_mouse_stream) {
354
+ this.send_mouse_packet(0, 0)
355
+ }
356
+ }
357
+
358
+ send_mouse_packet(dx: number, dy: number): void {
359
+ const info_byte =
360
+ ((dy < 0 ? 1 : 0) << 5) |
361
+ ((dx < 0 ? 1 : 0) << 4) |
362
+ (1 << 3) |
363
+ this.mouse_clicks,
364
+ delta_x = dx,
365
+ delta_y = dy
366
+
367
+ this.last_mouse_packet = Date.now()
368
+
369
+ //if(this.scaling2)
370
+ //{
371
+ // // only in automatic packets, not 0xEB requests
372
+ // delta_x = this.apply_scaling2(delta_x);
373
+ // delta_y = this.apply_scaling2(delta_y);
374
+ //}
375
+
376
+ this.mouse_buffer.push(info_byte)
377
+ this.mouse_buffer.push(delta_x)
378
+ this.mouse_buffer.push(delta_y)
379
+
380
+ if (this.mouse_id === 0x04) {
381
+ this.mouse_buffer.push(
382
+ (0 << 5) | // TODO: 5th button
383
+ (0 << 4) | // TODO: 4th button
384
+ (this.wheel_movement & 0x0f),
385
+ )
386
+ this.wheel_movement = 0
387
+ } else if (this.mouse_id === 0x03) {
388
+ this.mouse_buffer.push(this.wheel_movement & 0xff) // Byte 4 - Z Movement
389
+ this.wheel_movement = 0
390
+ }
391
+
392
+ if (PS2_LOG_VERBOSE) {
393
+ dbg_log('adding mouse packets: ' + [info_byte, dx, dy], LOG_PS2)
394
+ }
395
+
396
+ this.raise_irq()
397
+ }
398
+
399
+ apply_scaling2(n: number): number {
400
+ // http://www.computer-engineering.org/ps2mouse/#Inputs.2C_Resolution.2C_and_Scaling
401
+ const abs = Math.abs(n),
402
+ sign = n >> 31
403
+
404
+ switch (abs) {
405
+ case 0:
406
+ case 1:
407
+ case 3:
408
+ return n
409
+ case 2:
410
+ return sign
411
+ case 4:
412
+ return 6 * sign
413
+ case 5:
414
+ return 9 * sign
415
+ default:
416
+ return n << 1
417
+ }
418
+ }
419
+
420
+ port60_read(): number {
421
+ //dbg_log("port 60 read: " + (buffer[0] || "(none)"));
422
+
423
+ this.next_byte_is_ready = false
424
+
425
+ if (!this.kbd_buffer.length && !this.mouse_buffer.length) {
426
+ // should not happen
427
+ dbg_log('Port 60 read: Empty', LOG_PS2)
428
+ return this.last_port60_byte
429
+ }
430
+
431
+ if (this.next_byte_is_aux) {
432
+ this.cpu.device_lower_irq(12)
433
+ this.last_port60_byte = this.mouse_buffer.shift()
434
+ dbg_log(
435
+ 'Port 60 read (mouse): ' + h(this.last_port60_byte),
436
+ LOG_PS2,
437
+ )
438
+ } else {
439
+ this.cpu.device_lower_irq(1)
440
+ this.last_port60_byte = this.kbd_buffer.shift()
441
+ dbg_log(
442
+ 'Port 60 read (kbd) : ' + h(this.last_port60_byte),
443
+ LOG_PS2,
444
+ )
445
+ }
446
+
447
+ if (this.kbd_buffer.length || this.mouse_buffer.length) {
448
+ this.raise_irq()
449
+ }
450
+
451
+ return this.last_port60_byte
452
+ }
453
+
454
+ port64_read(): number {
455
+ // status port
456
+
457
+ let status_byte = 0x10
458
+
459
+ if (this.next_byte_is_ready) {
460
+ status_byte |= 0x1
461
+ }
462
+ if (this.next_byte_is_aux) {
463
+ status_byte |= 0x20
464
+ }
465
+
466
+ dbg_log('port 64 read: ' + h(status_byte), LOG_PS2)
467
+
468
+ return status_byte
469
+ }
470
+
471
+ port60_write(write_byte: number): void {
472
+ dbg_log('port 60 write: ' + h(write_byte), LOG_PS2)
473
+
474
+ if (this.read_command_register) {
475
+ this.command_register = write_byte
476
+ this.read_command_register = false
477
+
478
+ // not sure, causes "spurious ack" in Linux
479
+ //this.kbd_buffer.push(0xFA);
480
+ //this.kbd_irq();
481
+
482
+ dbg_log(
483
+ 'Keyboard command register = ' + h(this.command_register),
484
+ LOG_PS2,
485
+ )
486
+ } else if (this.read_output_register) {
487
+ this.read_output_register = false
488
+
489
+ this.mouse_buffer.clear()
490
+ this.mouse_buffer.push(write_byte)
491
+ this.mouse_irq()
492
+ } else if (this.next_read_sample) {
493
+ this.next_read_sample = false
494
+ this.mouse_buffer.clear()
495
+ this.mouse_buffer.push(0xfa)
496
+
497
+ this.sample_rate = write_byte
498
+
499
+ switch (this.mouse_detect_state) {
500
+ case -1:
501
+ if (write_byte === 60) {
502
+ // Detect Windows NT and turn on workaround the bug
503
+ // 200->100->80->60
504
+ this.mouse_reset_workaround = true
505
+ this.mouse_detect_state = 0
506
+ } else {
507
+ this.mouse_reset_workaround = false
508
+ this.mouse_detect_state = write_byte === 200 ? 1 : 0
509
+ }
510
+ break
511
+ case 0:
512
+ if (write_byte === 200) this.mouse_detect_state = 1
513
+ break
514
+ case 1:
515
+ if (write_byte === 100) this.mouse_detect_state = 2
516
+ else if (write_byte === 200) this.mouse_detect_state = 3
517
+ else this.mouse_detect_state = 0
518
+ break
519
+ case 2:
520
+ // Host sends sample rate 200->100->80 to activate Intellimouse wheel
521
+ if (write_byte === 80) this.mouse_id = 0x03
522
+ this.mouse_detect_state = -1
523
+ break
524
+ case 3:
525
+ // Host sends sample rate 200->200->80 to activate Intellimouse 4th, 5th buttons
526
+ if (write_byte === 80) this.mouse_id = 0x04
527
+ this.mouse_detect_state = -1
528
+ break
529
+ }
530
+
531
+ dbg_log(
532
+ 'mouse sample rate: ' +
533
+ h(write_byte) +
534
+ ', mouse id: ' +
535
+ h(this.mouse_id),
536
+ LOG_PS2,
537
+ )
538
+
539
+ if (!this.sample_rate) {
540
+ dbg_log('invalid sample rate, reset to 100', LOG_PS2)
541
+ this.sample_rate = 100
542
+ }
543
+
544
+ this.mouse_irq()
545
+ } else if (this.next_read_resolution) {
546
+ this.next_read_resolution = false
547
+ this.mouse_buffer.clear()
548
+ this.mouse_buffer.push(0xfa)
549
+
550
+ if (write_byte > 3) {
551
+ this.resolution = 4
552
+ dbg_log('invalid resolution, resetting to 4', LOG_PS2)
553
+ } else {
554
+ this.resolution = 1 << write_byte
555
+ dbg_log('resolution: ' + this.resolution, LOG_PS2)
556
+ }
557
+ this.mouse_irq()
558
+ } else if (this.next_read_led) {
559
+ // nope
560
+ this.next_read_led = false
561
+ this.kbd_buffer.push(0xfa)
562
+ this.kbd_irq()
563
+ } else if (this.next_handle_scan_code_set) {
564
+ this.next_handle_scan_code_set = false
565
+
566
+ this.kbd_buffer.push(0xfa)
567
+ this.kbd_irq()
568
+
569
+ if (write_byte) {
570
+ // set scan code set
571
+ } else {
572
+ this.kbd_buffer.push(1)
573
+ }
574
+ } else if (this.next_read_rate) {
575
+ // nope
576
+ this.next_read_rate = false
577
+ this.kbd_buffer.push(0xfa)
578
+ this.kbd_irq()
579
+ } else if (this.next_is_mouse_command) {
580
+ this.next_is_mouse_command = false
581
+ dbg_log('Port 60 data register write: ' + h(write_byte), LOG_PS2)
582
+
583
+ if (!this.have_mouse) {
584
+ return
585
+ }
586
+
587
+ // send ack
588
+ this.kbd_buffer.clear()
589
+ this.mouse_buffer.clear()
590
+ this.mouse_buffer.push(0xfa)
591
+
592
+ switch (write_byte) {
593
+ case 0xe6:
594
+ // set scaling to 1:1
595
+ dbg_log('Scaling 1:1', LOG_PS2)
596
+ this.scaling2 = false
597
+ break
598
+ case 0xe7:
599
+ // set scaling to 2:1
600
+ dbg_log('Scaling 2:1', LOG_PS2)
601
+ this.scaling2 = true
602
+ break
603
+ case 0xe8:
604
+ // set mouse resolution
605
+ this.next_read_resolution = true
606
+ break
607
+ case 0xe9:
608
+ // status request - send one packet
609
+ this.send_mouse_packet(0, 0)
610
+ break
611
+ case 0xeb:
612
+ // request single packet
613
+ dbg_log('unimplemented request single packet', LOG_PS2)
614
+ this.send_mouse_packet(0, 0)
615
+ break
616
+ case 0xf2:
617
+ // MouseID Byte
618
+ dbg_log('required id: ' + h(this.mouse_id), LOG_PS2)
619
+ this.mouse_buffer.push(this.mouse_id)
620
+
621
+ this.mouse_clicks =
622
+ this.mouse_delta_x =
623
+ this.mouse_delta_y =
624
+ 0
625
+ // this.send_mouse_packet(0, 0);
626
+ this.raise_irq()
627
+ break
628
+ case 0xf3:
629
+ // sample rate
630
+ this.next_read_sample = true
631
+ break
632
+ case 0xf4:
633
+ // enable streaming
634
+ this.enable_mouse_stream = true
635
+ this.use_mouse = true
636
+ this.bus.send('mouse-enable', true)
637
+
638
+ this.mouse_clicks =
639
+ this.mouse_delta_x =
640
+ this.mouse_delta_y =
641
+ 0
642
+ break
643
+ case 0xf5:
644
+ // disable streaming
645
+ this.enable_mouse_stream = false
646
+ break
647
+ case 0xf6:
648
+ // set defaults
649
+ this.enable_mouse_stream = false
650
+ this.sample_rate = 100
651
+ this.scaling2 = false
652
+ this.resolution = 4
653
+ break
654
+ case 0xff:
655
+ // reset, send completion code
656
+ dbg_log('Mouse reset', LOG_PS2)
657
+ this.mouse_buffer.push(0xaa)
658
+ this.mouse_buffer.push(0)
659
+
660
+ this.use_mouse = true
661
+ this.bus.send('mouse-enable', true)
662
+
663
+ this.enable_mouse_stream = false
664
+ this.sample_rate = 100
665
+ this.scaling2 = false
666
+ this.resolution = 4
667
+
668
+ if (!this.mouse_reset_workaround) {
669
+ this.mouse_id = 0x00
670
+ }
671
+
672
+ this.mouse_clicks =
673
+ this.mouse_delta_x =
674
+ this.mouse_delta_y =
675
+ 0
676
+ break
677
+
678
+ default:
679
+ dbg_log(
680
+ 'Unimplemented mouse command: ' + h(write_byte),
681
+ LOG_PS2,
682
+ )
683
+ }
684
+
685
+ this.mouse_irq()
686
+ } else if (this.read_controller_output_port) {
687
+ this.read_controller_output_port = false
688
+ this.controller_output_port = write_byte
689
+ // If we ever want to implement A20 masking, here is where
690
+ // we should turn the masking off if the second bit is on
691
+ } else {
692
+ dbg_log('Port 60 data register write: ' + h(write_byte), LOG_PS2)
693
+
694
+ // send ack
695
+ this.mouse_buffer.clear()
696
+ this.kbd_buffer.clear()
697
+ this.kbd_buffer.push(0xfa)
698
+
699
+ switch (write_byte) {
700
+ case 0xed:
701
+ this.next_read_led = true
702
+ break
703
+ case 0xf0:
704
+ // get/set scan code set
705
+ this.next_handle_scan_code_set = true
706
+ break
707
+ case 0xf2:
708
+ // identify
709
+ this.kbd_buffer.push(0xab)
710
+ this.kbd_buffer.push(0x83)
711
+ break
712
+ case 0xf3:
713
+ // Set typematic rate and delay
714
+ this.next_read_rate = true
715
+ break
716
+ case 0xf4:
717
+ // enable scanning
718
+ dbg_log('kbd enable scanning', LOG_PS2)
719
+ this.enable_keyboard_stream = true
720
+ break
721
+ case 0xf5:
722
+ // disable scanning
723
+ dbg_log('kbd disable scanning', LOG_PS2)
724
+ this.enable_keyboard_stream = false
725
+ break
726
+ case 0xf6:
727
+ // reset defaults
728
+ //this.enable_keyboard_stream = false;
729
+ break
730
+ case 0xff:
731
+ this.kbd_buffer.clear()
732
+ this.kbd_buffer.push(0xfa)
733
+ this.kbd_buffer.push(0xaa)
734
+ this.kbd_buffer.push(0)
735
+ break
736
+ default:
737
+ dbg_log(
738
+ 'Unimplemented keyboard command: ' + h(write_byte),
739
+ LOG_PS2,
740
+ )
741
+ }
742
+
743
+ this.kbd_irq()
744
+ }
745
+ }
746
+
747
+ port64_write(write_byte: number): void {
748
+ dbg_log('port 64 write: ' + h(write_byte), LOG_PS2)
749
+
750
+ switch (write_byte) {
751
+ case 0x20:
752
+ this.kbd_buffer.clear()
753
+ this.mouse_buffer.clear()
754
+ this.kbd_buffer.push(this.command_register)
755
+ this.kbd_irq()
756
+ break
757
+ case 0x60:
758
+ this.read_command_register = true
759
+ break
760
+ case 0xd1:
761
+ this.read_controller_output_port = true
762
+ break
763
+ case 0xd3:
764
+ this.read_output_register = true
765
+ break
766
+ case 0xd4:
767
+ this.next_is_mouse_command = true
768
+ break
769
+ case 0xa7:
770
+ // Disable second port
771
+ dbg_log('Disable second port', LOG_PS2)
772
+ this.command_register |= 0x20
773
+ break
774
+ case 0xa8:
775
+ // Enable second port
776
+ dbg_log('Enable second port', LOG_PS2)
777
+ this.command_register &= ~0x20
778
+ break
779
+ case 0xa9:
780
+ // test second ps/2 port
781
+ this.kbd_buffer.clear()
782
+ this.mouse_buffer.clear()
783
+ this.kbd_buffer.push(0)
784
+ this.kbd_irq()
785
+ break
786
+ case 0xaa:
787
+ this.kbd_buffer.clear()
788
+ this.mouse_buffer.clear()
789
+ this.kbd_buffer.push(0x55)
790
+ this.kbd_irq()
791
+ break
792
+ case 0xab:
793
+ // Test first PS/2 port
794
+ this.kbd_buffer.clear()
795
+ this.mouse_buffer.clear()
796
+ this.kbd_buffer.push(0)
797
+ this.kbd_irq()
798
+ break
799
+ case 0xad:
800
+ // Disable Keyboard
801
+ dbg_log('Disable Keyboard', LOG_PS2)
802
+ this.command_register |= 0x10
803
+ break
804
+ case 0xae:
805
+ // Enable Keyboard
806
+ dbg_log('Enable Keyboard', LOG_PS2)
807
+ this.command_register &= ~0x10
808
+ break
809
+ case 0xfe:
810
+ dbg_log('CPU reboot via PS2')
811
+ this.cpu.reboot_internal()
812
+ break
813
+ default:
814
+ dbg_log(
815
+ 'port 64: Unimplemented command byte: ' + h(write_byte),
816
+ LOG_PS2,
817
+ )
818
+ }
819
+ }
820
+ }