@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/pit.ts ADDED
@@ -0,0 +1,406 @@
1
+ import { v86 } from './main.js'
2
+ import { LOG_PIT } from './const.js'
3
+ import { h } from './lib.js'
4
+ import { dbg_log } from './log.js'
5
+ import { IO } from './io.js'
6
+ import { BusConnector } from './bus.js'
7
+
8
+ // In kHz
9
+ export const OSCILLATOR_FREQ = 1193.1816666 // 1.193182 MHz
10
+
11
+ interface PITCpu {
12
+ io: IO
13
+ device_raise_irq(irq: number): void
14
+ device_lower_irq(irq: number): void
15
+ }
16
+
17
+ type PITState = [
18
+ Uint8Array,
19
+ Uint8Array,
20
+ Uint8Array,
21
+ Uint8Array,
22
+ Uint8Array,
23
+ Uint16Array,
24
+ Uint16Array,
25
+ Float64Array,
26
+ Uint16Array,
27
+ ]
28
+
29
+ /**
30
+ * PIT is the Programmable Interval Timer.
31
+ */
32
+ export class PIT {
33
+ name: string
34
+ cpu: PITCpu
35
+ bus: BusConnector
36
+
37
+ counter_start_time: Float64Array
38
+ counter_start_value: Uint16Array
39
+
40
+ counter_next_low: Uint8Array
41
+ counter_enabled: Uint8Array
42
+ counter_mode: Uint8Array
43
+ counter_read_mode: Uint8Array
44
+
45
+ // 2 = latch low, 1 = latch high, 0 = no latch
46
+ counter_latch: Uint8Array
47
+ counter_latch_value: Uint16Array
48
+
49
+ counter_reload: Uint16Array
50
+
51
+ constructor(cpu: PITCpu, bus: BusConnector) {
52
+ this.name = 'pit'
53
+ this.cpu = cpu
54
+ this.bus = bus
55
+
56
+ this.counter_start_time = new Float64Array(3)
57
+ this.counter_start_value = new Uint16Array(3)
58
+
59
+ this.counter_next_low = new Uint8Array(4)
60
+ this.counter_enabled = new Uint8Array(4)
61
+ this.counter_mode = new Uint8Array(4)
62
+ this.counter_read_mode = new Uint8Array(4)
63
+
64
+ this.counter_latch = new Uint8Array(4)
65
+ this.counter_latch_value = new Uint16Array(3)
66
+
67
+ this.counter_reload = new Uint16Array(3)
68
+
69
+ // TODO:
70
+ // - counter2 can be controlled by an input
71
+
72
+ cpu.io.register_read(0x61, this, function (this: PIT): number {
73
+ const now = v86.microtick()
74
+
75
+ const ref_toggle = (now * ((1000 * 1000) / 15000)) & 1
76
+ const counter2_out = this.did_rollover(2, now)
77
+
78
+ return (ref_toggle << 4) | (counter2_out << 5)
79
+ })
80
+ cpu.io.register_write(
81
+ 0x61,
82
+ this,
83
+ function (this: PIT, data: number): void {
84
+ if (data & 1) {
85
+ this.bus.send('pcspeaker-enable')
86
+ } else {
87
+ this.bus.send('pcspeaker-disable')
88
+ }
89
+ },
90
+ )
91
+
92
+ cpu.io.register_read(0x40, this, function (this: PIT): number {
93
+ return this.counter_read(0)
94
+ })
95
+ cpu.io.register_read(0x41, this, function (this: PIT): number {
96
+ return this.counter_read(1)
97
+ })
98
+ cpu.io.register_read(0x42, this, function (this: PIT): number {
99
+ return this.counter_read(2)
100
+ })
101
+
102
+ cpu.io.register_write(
103
+ 0x40,
104
+ this,
105
+ function (this: PIT, data: number): void {
106
+ this.counter_write(0, data)
107
+ },
108
+ )
109
+ cpu.io.register_write(
110
+ 0x41,
111
+ this,
112
+ function (this: PIT, data: number): void {
113
+ this.counter_write(1, data)
114
+ },
115
+ )
116
+ cpu.io.register_write(
117
+ 0x42,
118
+ this,
119
+ function (this: PIT, data: number): void {
120
+ this.counter_write(2, data)
121
+ this.bus.send('pcspeaker-update', [
122
+ this.counter_mode[2],
123
+ this.counter_reload[2],
124
+ ])
125
+ },
126
+ )
127
+
128
+ cpu.io.register_write(0x43, this, this.port43_write)
129
+ }
130
+
131
+ get_state(): PITState {
132
+ const state: PITState = [
133
+ this.counter_next_low,
134
+ this.counter_enabled,
135
+ this.counter_mode,
136
+ this.counter_read_mode,
137
+ this.counter_latch,
138
+ this.counter_latch_value,
139
+ this.counter_reload,
140
+ this.counter_start_time,
141
+ this.counter_start_value,
142
+ ]
143
+
144
+ return state
145
+ }
146
+
147
+ set_state(state: PITState): void {
148
+ this.counter_next_low = state[0]
149
+ this.counter_enabled = state[1]
150
+ this.counter_mode = state[2]
151
+ this.counter_read_mode = state[3]
152
+ this.counter_latch = state[4]
153
+ this.counter_latch_value = state[5]
154
+ this.counter_reload = state[6]
155
+ this.counter_start_time = state[7]
156
+ this.counter_start_value = state[8]
157
+ }
158
+
159
+ timer(now: number, no_irq: boolean): number {
160
+ let time_to_next_interrupt = 100
161
+
162
+ // counter 0 produces interrupts
163
+ if (!no_irq) {
164
+ if (this.counter_enabled[0] && this.did_rollover(0, now)) {
165
+ this.counter_start_value[0] = this.get_counter_value(0, now)
166
+ this.counter_start_time[0] = now
167
+
168
+ dbg_log(
169
+ 'pit interrupt. new value: ' + this.counter_start_value[0],
170
+ LOG_PIT,
171
+ )
172
+
173
+ // This isn't strictly correct, but it's necessary since browsers
174
+ // may sleep longer than necessary to trigger the else branch below
175
+ // and clear the irq
176
+ this.cpu.device_lower_irq(0)
177
+
178
+ this.cpu.device_raise_irq(0)
179
+ const mode = this.counter_mode[0]
180
+
181
+ if (mode === 0) {
182
+ this.counter_enabled[0] = 0
183
+ }
184
+ } else {
185
+ this.cpu.device_lower_irq(0)
186
+ }
187
+
188
+ if (this.counter_enabled[0]) {
189
+ const diff = now - this.counter_start_time[0]
190
+ const diff_in_ticks = Math.floor(diff * OSCILLATOR_FREQ)
191
+ const ticks_missing =
192
+ this.counter_start_value[0] - diff_in_ticks // XXX: to simplify
193
+ time_to_next_interrupt = ticks_missing / OSCILLATOR_FREQ
194
+ }
195
+ }
196
+
197
+ return time_to_next_interrupt
198
+ }
199
+
200
+ get_counter_value(i: number, now: number): number {
201
+ if (!this.counter_enabled[i]) {
202
+ return 0
203
+ }
204
+
205
+ const diff = now - this.counter_start_time[i]
206
+ const diff_in_ticks = Math.floor(diff * OSCILLATOR_FREQ)
207
+
208
+ let value = this.counter_start_value[i] - diff_in_ticks
209
+
210
+ dbg_log(
211
+ 'diff=' +
212
+ diff +
213
+ ' dticks=' +
214
+ diff_in_ticks +
215
+ ' value=' +
216
+ value +
217
+ ' reload=' +
218
+ this.counter_reload[i],
219
+ LOG_PIT,
220
+ )
221
+
222
+ const reload = this.counter_reload[i]
223
+
224
+ if (value >= reload) {
225
+ dbg_log(
226
+ 'Warning: Counter' +
227
+ i +
228
+ ' value ' +
229
+ value +
230
+ ' is larger than reload ' +
231
+ reload,
232
+ LOG_PIT,
233
+ )
234
+ value %= reload
235
+ } else if (value < 0) {
236
+ value = (value % reload) + reload
237
+ }
238
+
239
+ return value
240
+ }
241
+
242
+ did_rollover(i: number, now: number): number {
243
+ const diff = now - this.counter_start_time[i]
244
+
245
+ if (diff < 0) {
246
+ // should only happen after restore_state
247
+ dbg_log(
248
+ 'Warning: PIT timer difference is negative, resetting (timer ' +
249
+ i +
250
+ ')',
251
+ )
252
+ return 1
253
+ }
254
+ const diff_in_ticks = Math.floor(diff * OSCILLATOR_FREQ)
255
+
256
+ return this.counter_start_value[i] < diff_in_ticks ? 1 : 0
257
+ }
258
+
259
+ counter_read(i: number): number {
260
+ const latch = this.counter_latch[i]
261
+
262
+ if (latch) {
263
+ this.counter_latch[i]--
264
+
265
+ if (latch === 2) {
266
+ return this.counter_latch_value[i] & 0xff
267
+ } else {
268
+ return this.counter_latch_value[i] >> 8
269
+ }
270
+ } else {
271
+ const next_low = this.counter_next_low[i]
272
+
273
+ if (this.counter_mode[i] === 3) {
274
+ this.counter_next_low[i] ^= 1
275
+ }
276
+
277
+ const value = this.get_counter_value(i, v86.microtick())
278
+
279
+ if (next_low) {
280
+ return value & 0xff
281
+ } else {
282
+ return value >> 8
283
+ }
284
+ }
285
+ }
286
+
287
+ counter_write(i: number, value: number): void {
288
+ if (this.counter_next_low[i]) {
289
+ this.counter_reload[i] = (this.counter_reload[i] & ~0xff) | value
290
+ } else {
291
+ this.counter_reload[i] =
292
+ (this.counter_reload[i] & 0xff) | (value << 8)
293
+ }
294
+
295
+ if (this.counter_read_mode[i] !== 3 || !this.counter_next_low[i]) {
296
+ if (!this.counter_reload[i]) {
297
+ this.counter_reload[i] = 0xffff
298
+ }
299
+
300
+ // depends on the mode, should actually
301
+ // happen on the first tick
302
+ this.counter_start_value[i] = this.counter_reload[i]
303
+
304
+ this.counter_enabled[i] = 1
305
+
306
+ this.counter_start_time[i] = v86.microtick()
307
+
308
+ dbg_log(
309
+ 'counter' +
310
+ i +
311
+ ' reload=' +
312
+ h(this.counter_reload[i]) +
313
+ ' tick=' +
314
+ (this.counter_reload[i] || 0x10000) / OSCILLATOR_FREQ +
315
+ 'ms',
316
+ LOG_PIT,
317
+ )
318
+ }
319
+
320
+ if (this.counter_read_mode[i] === 3) {
321
+ this.counter_next_low[i] ^= 1
322
+ }
323
+ }
324
+
325
+ port43_write(reg_byte: number): void {
326
+ let mode = (reg_byte >> 1) & 7
327
+ const binary_mode = reg_byte & 1,
328
+ i = (reg_byte >> 6) & 3,
329
+ read_mode = (reg_byte >> 4) & 3
330
+
331
+ if (i === 1) {
332
+ dbg_log('Unimplemented timer1', LOG_PIT)
333
+ }
334
+
335
+ if (i === 3) {
336
+ dbg_log('Unimplemented read back', LOG_PIT)
337
+ return
338
+ }
339
+
340
+ if (read_mode === 0) {
341
+ // latch
342
+ this.counter_latch[i] = 2
343
+ const value = this.get_counter_value(i, v86.microtick())
344
+ dbg_log('latch: ' + value, LOG_PIT)
345
+ this.counter_latch_value[i] = value ? value - 1 : 0
346
+
347
+ return
348
+ }
349
+
350
+ if (mode >= 6) {
351
+ // 6 and 7 are aliased to 2 and 3
352
+ mode &= ~4
353
+ }
354
+
355
+ dbg_log(
356
+ 'Control: mode=' +
357
+ mode +
358
+ ' ctr=' +
359
+ i +
360
+ ' read_mode=' +
361
+ read_mode +
362
+ ' bcd=' +
363
+ binary_mode,
364
+ LOG_PIT,
365
+ )
366
+
367
+ if (read_mode === 1) {
368
+ // lsb
369
+ this.counter_next_low[i] = 1
370
+ } else if (read_mode === 2) {
371
+ // msb
372
+ this.counter_next_low[i] = 0
373
+ } else {
374
+ // first lsb then msb
375
+ this.counter_next_low[i] = 1
376
+ }
377
+
378
+ if (i === 0) {
379
+ this.cpu.device_lower_irq(0)
380
+ }
381
+
382
+ if (mode === 0) {
383
+ // intentionally empty
384
+ } else if (mode === 3 || mode === 2) {
385
+ // what is the difference
386
+ } else {
387
+ dbg_log('Unimplemented counter mode: ' + h(mode), LOG_PIT)
388
+ }
389
+
390
+ this.counter_mode[i] = mode
391
+ this.counter_read_mode[i] = read_mode
392
+
393
+ if (i === 2) {
394
+ this.bus.send('pcspeaker-update', [
395
+ this.counter_mode[2],
396
+ this.counter_reload[2],
397
+ ])
398
+ }
399
+ }
400
+
401
+ dump(): void {
402
+ const reload = this.counter_reload[0]
403
+ const time = (reload || 0x10000) / OSCILLATOR_FREQ
404
+ dbg_log('counter0 ticks every ' + time + 'ms (reload=' + reload + ')')
405
+ }
406
+ }