@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
@@ -0,0 +1,255 @@
1
+ import { dbg_log } from '../log.js'
2
+ import { BusConnector } from '../bus.js'
3
+
4
+ export class MouseAdapter {
5
+ enabled = false
6
+ emu_enabled = true
7
+ bus: BusConnector
8
+ is_running = false
9
+
10
+ private left_down = false
11
+ private right_down = false
12
+ private middle_down = false
13
+ private last_x = 0
14
+ private last_y = 0
15
+ private screen_container: HTMLElement | undefined
16
+
17
+ private SPEED_FACTOR = 1
18
+
19
+ private touch_start_handler: (e: TouchEvent) => void
20
+ private touch_end_handler: (e: TouchEvent) => void
21
+ private mousemove_handler: (e: MouseEvent | TouchEvent) => void
22
+ private mousedown_handler: (e: MouseEvent) => void
23
+ private mouseup_handler: (e: MouseEvent) => void
24
+ private mousewheel_handler: (e: WheelEvent) => void
25
+
26
+ constructor(bus: BusConnector, screen_container?: HTMLElement) {
27
+ this.bus = bus
28
+ this.screen_container = screen_container
29
+
30
+ this.touch_start_handler = (e: TouchEvent) => {
31
+ if (this.may_handle(e)) {
32
+ const touches = e.changedTouches
33
+
34
+ if (touches && touches.length) {
35
+ const touch = touches[touches.length - 1]
36
+ this.last_x = touch.clientX
37
+ this.last_y = touch.clientY
38
+ }
39
+ }
40
+ }
41
+
42
+ this.touch_end_handler = (_e: TouchEvent) => {
43
+ if (this.left_down || this.middle_down || this.right_down) {
44
+ this.bus.send('mouse-click', [false, false, false])
45
+ this.left_down = this.middle_down = this.right_down = false
46
+ }
47
+ }
48
+
49
+ this.mousemove_handler = (e: MouseEvent | TouchEvent) => {
50
+ if (!this.bus) {
51
+ return
52
+ }
53
+
54
+ if (!this.may_handle(e)) {
55
+ return
56
+ }
57
+
58
+ if (!this.is_running) {
59
+ return
60
+ }
61
+
62
+ let delta_x = 0
63
+ let delta_y = 0
64
+
65
+ if ('changedTouches' in e) {
66
+ const touches = e.changedTouches
67
+ if (touches.length) {
68
+ const touch = touches[touches.length - 1]
69
+ delta_x = touch.clientX - this.last_x
70
+ delta_y = touch.clientY - this.last_y
71
+
72
+ this.last_x = touch.clientX
73
+ this.last_y = touch.clientY
74
+
75
+ e.preventDefault()
76
+ }
77
+ } else {
78
+ if (typeof e.movementX === 'number') {
79
+ delta_x = e.movementX
80
+ delta_y = e.movementY
81
+ } else {
82
+ delta_x = e.clientX - this.last_x
83
+ delta_y = e.clientY - this.last_y
84
+
85
+ this.last_x = e.clientX
86
+ this.last_y = e.clientY
87
+ }
88
+ }
89
+
90
+ delta_x *= this.SPEED_FACTOR
91
+ delta_y *= this.SPEED_FACTOR
92
+
93
+ delta_y = -delta_y
94
+
95
+ this.bus.send('mouse-delta', [delta_x, delta_y])
96
+
97
+ if (this.screen_container) {
98
+ const me = e instanceof MouseEvent ? e : e.changedTouches[0]
99
+ const absolute_x = me.pageX - this.screen_container.offsetLeft
100
+ const absolute_y = me.pageY - this.screen_container.offsetTop
101
+ this.bus.send('mouse-absolute', [
102
+ absolute_x,
103
+ absolute_y,
104
+ this.screen_container.offsetWidth,
105
+ this.screen_container.offsetHeight,
106
+ ])
107
+ }
108
+ }
109
+
110
+ this.mousedown_handler = (e: MouseEvent) => {
111
+ if (this.may_handle(e)) {
112
+ this.click_event(e, true)
113
+ }
114
+ }
115
+
116
+ this.mouseup_handler = (e: MouseEvent) => {
117
+ if (this.may_handle(e)) {
118
+ this.click_event(e, false)
119
+ }
120
+ }
121
+
122
+ this.mousewheel_handler = (e: WheelEvent) => {
123
+ if (!this.may_handle(e)) {
124
+ return
125
+ }
126
+
127
+ let delta_x = -e.deltaY
128
+ const delta_y = 0
129
+
130
+ if (delta_x < 0) {
131
+ delta_x = -1
132
+ } else if (delta_x > 0) {
133
+ delta_x = 1
134
+ }
135
+
136
+ this.bus.send('mouse-wheel', [delta_x, delta_y])
137
+ e.preventDefault()
138
+ }
139
+
140
+ this.bus.register(
141
+ 'mouse-enable',
142
+ function (this: MouseAdapter, enabled: boolean) {
143
+ this.enabled = enabled
144
+ },
145
+ this,
146
+ )
147
+
148
+ this.bus.register(
149
+ 'emulator-stopped',
150
+ function (this: MouseAdapter) {
151
+ this.is_running = false
152
+ },
153
+ this,
154
+ )
155
+ this.bus.register(
156
+ 'emulator-started',
157
+ function (this: MouseAdapter) {
158
+ this.is_running = true
159
+ },
160
+ this,
161
+ )
162
+
163
+ this.init()
164
+ }
165
+
166
+ destroy(): void {
167
+ if (typeof window === 'undefined') {
168
+ return
169
+ }
170
+ window.removeEventListener(
171
+ 'touchstart',
172
+ this.touch_start_handler,
173
+ false,
174
+ )
175
+ window.removeEventListener('touchend', this.touch_end_handler, false)
176
+ window.removeEventListener('touchmove', this.mousemove_handler, false)
177
+ window.removeEventListener('mousemove', this.mousemove_handler, false)
178
+ window.removeEventListener('mousedown', this.mousedown_handler, false)
179
+ window.removeEventListener('mouseup', this.mouseup_handler, false)
180
+ window.removeEventListener('wheel', this.mousewheel_handler)
181
+ }
182
+
183
+ init(): void {
184
+ if (typeof window === 'undefined') {
185
+ return
186
+ }
187
+ this.destroy()
188
+
189
+ window.addEventListener('touchstart', this.touch_start_handler, false)
190
+ window.addEventListener('touchend', this.touch_end_handler, false)
191
+ window.addEventListener('touchmove', this.mousemove_handler, false)
192
+ window.addEventListener('mousemove', this.mousemove_handler, false)
193
+ window.addEventListener('mousedown', this.mousedown_handler, false)
194
+ window.addEventListener('mouseup', this.mouseup_handler, false)
195
+ window.addEventListener('wheel', this.mousewheel_handler, {
196
+ passive: false,
197
+ })
198
+ }
199
+
200
+ private is_child(child: Node, parent: Node): boolean {
201
+ let node: Node | null = child
202
+ while (node && node.parentNode) {
203
+ if (node === parent) {
204
+ return true
205
+ }
206
+ node = node.parentNode
207
+ }
208
+
209
+ return false
210
+ }
211
+
212
+ private may_handle(e: Event): boolean {
213
+ if (!this.enabled || !this.emu_enabled) {
214
+ return false
215
+ }
216
+
217
+ const MOVE_MOUSE_WHEN_OVER_SCREEN_ONLY = true
218
+
219
+ if (MOVE_MOUSE_WHEN_OVER_SCREEN_ONLY) {
220
+ const parent = this.screen_container || document.body
221
+ const target = e.target
222
+ if (!target) {
223
+ return false
224
+ }
225
+ return (
226
+ !!document.pointerLockElement ||
227
+ this.is_child(target as Node, parent)
228
+ )
229
+ }
230
+
231
+ return true
232
+ }
233
+
234
+ private click_event(e: MouseEvent, down: boolean): void {
235
+ if (!this.bus) {
236
+ return
237
+ }
238
+
239
+ if (e.button === 0) {
240
+ this.left_down = down
241
+ } else if (e.button === 1) {
242
+ this.middle_down = down
243
+ } else if (e.button === 2) {
244
+ this.right_down = down
245
+ } else {
246
+ dbg_log('Unknown event.button: ' + e.button)
247
+ }
248
+ this.bus.send('mouse-click', [
249
+ this.left_down,
250
+ this.middle_down,
251
+ this.right_down,
252
+ ])
253
+ e.preventDefault()
254
+ }
255
+ }
@@ -0,0 +1,142 @@
1
+ import { BusConnector } from '../bus.js'
2
+
3
+ /**
4
+ * An ethernet-through-websocket adapter, to be used with
5
+ * https://github.com/benjamincburns/websockproxy
6
+ *
7
+ * emulated ethernet card <--> this <--> websocket proxy <--> network
8
+ */
9
+ export class NetworkAdapter {
10
+ bus: BusConnector
11
+ socket: WebSocket | undefined
12
+ id: number
13
+ send_queue: Uint8Array[]
14
+ url: string
15
+ reconnect_interval: number
16
+ last_connect_attempt: number
17
+ send_queue_limit: number
18
+ destroyed: boolean
19
+
20
+ constructor(url: string, bus: BusConnector, id?: number) {
21
+ this.bus = bus
22
+ this.socket = undefined
23
+ this.id = id || 0
24
+
25
+ // TODO: circular buffer?
26
+ this.send_queue = []
27
+ this.url = url
28
+
29
+ this.reconnect_interval = 10000
30
+ this.last_connect_attempt = Date.now() - this.reconnect_interval
31
+ this.send_queue_limit = 64
32
+ this.destroyed = false
33
+
34
+ this.bus.register(
35
+ 'net' + this.id + '-send',
36
+ function (this: NetworkAdapter, data: Uint8Array) {
37
+ this.send(data)
38
+ },
39
+ this,
40
+ )
41
+ }
42
+
43
+ handle_message(e: MessageEvent): void {
44
+ if (this.bus) {
45
+ this.bus.send('net' + this.id + '-receive', new Uint8Array(e.data))
46
+ }
47
+ }
48
+
49
+ handle_close(_e: CloseEvent): void {
50
+ //console.log("onclose", e);
51
+
52
+ if (!this.destroyed) {
53
+ this.connect()
54
+ setTimeout(this.connect.bind(this), this.reconnect_interval)
55
+ }
56
+ }
57
+
58
+ handle_open(_e: Event): void {
59
+ //console.log("open", e);
60
+
61
+ for (let i = 0; i < this.send_queue.length; i++) {
62
+ this.send(this.send_queue[i])
63
+ }
64
+
65
+ this.send_queue = []
66
+ }
67
+
68
+ handle_error(_e: Event): void {
69
+ //console.log("onerror", e);
70
+ }
71
+
72
+ destroy(): void {
73
+ this.destroyed = true
74
+ if (this.socket) {
75
+ this.socket.close()
76
+ }
77
+ }
78
+
79
+ connect(): void {
80
+ if (typeof WebSocket === 'undefined') {
81
+ return
82
+ }
83
+
84
+ if (this.socket) {
85
+ const state = this.socket.readyState
86
+
87
+ if (state === 0 || state === 1) {
88
+ // already or almost there
89
+ return
90
+ }
91
+ }
92
+
93
+ const now = Date.now()
94
+
95
+ if (this.last_connect_attempt + this.reconnect_interval > now) {
96
+ return
97
+ }
98
+
99
+ this.last_connect_attempt = Date.now()
100
+
101
+ try {
102
+ this.socket = new WebSocket(this.url)
103
+ } catch (e) {
104
+ console.error(e)
105
+ return
106
+ }
107
+
108
+ this.socket.binaryType = 'arraybuffer'
109
+
110
+ this.socket.onopen = this.handle_open.bind(this)
111
+ this.socket.onmessage = this.handle_message.bind(this)
112
+ this.socket.onclose = this.handle_close.bind(this)
113
+ this.socket.onerror = this.handle_error.bind(this)
114
+ }
115
+
116
+ send(data: Uint8Array): void {
117
+ //console.log("send", data);
118
+
119
+ if (!this.socket || this.socket.readyState !== 1) {
120
+ this.send_queue.push(data)
121
+
122
+ if (this.send_queue.length > 2 * this.send_queue_limit) {
123
+ this.send_queue = this.send_queue.slice(-this.send_queue_limit)
124
+ }
125
+
126
+ this.connect()
127
+ } else {
128
+ this.socket.send(new Uint8Array(data))
129
+ }
130
+ }
131
+
132
+ change_proxy(url: string): void {
133
+ this.url = url
134
+
135
+ if (this.socket) {
136
+ this.socket.onclose = function () {}
137
+ this.socket.onerror = function () {}
138
+ this.socket.close()
139
+ this.socket = undefined
140
+ }
141
+ }
142
+ }