@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/dma.ts ADDED
@@ -0,0 +1,474 @@
1
+ import { LOG_DMA } from './const.js'
2
+ import { h } from './lib.js'
3
+ import { dbg_log } from './log.js'
4
+ import { IO } from './io.js'
5
+
6
+ interface DMACpu {
7
+ io: IO
8
+ mem8: Uint8Array
9
+ write_blob(blob: Uint8Array, offset: number): void
10
+ }
11
+
12
+ interface DMABuffer {
13
+ byteLength: number
14
+ get(start: number, len: number, fn: (data: Uint8Array) => void): void
15
+ set(start: number, data: Uint8Array, fn: () => void): void
16
+ }
17
+
18
+ interface UnmaskListener {
19
+ fn: (channel: number) => void
20
+ this_value: unknown
21
+ }
22
+
23
+ export class DMA {
24
+ name: string
25
+ cpu: DMACpu
26
+ channel_page: Uint8Array
27
+ channel_pagehi: Uint8Array
28
+ channel_addr: Uint16Array
29
+ channel_addr_init: Uint16Array
30
+ channel_count: Uint16Array
31
+ channel_count_init: Uint16Array
32
+ channel_mask: Uint8Array
33
+ channel_mode: Uint8Array
34
+ unmask_listeners: UnmaskListener[]
35
+ lsb_msb_flipflop: number
36
+
37
+ constructor(cpu: DMACpu) {
38
+ this.name = 'dma'
39
+ this.cpu = cpu
40
+
41
+ this.channel_page = new Uint8Array(8)
42
+ this.channel_pagehi = new Uint8Array(8)
43
+ this.channel_addr = new Uint16Array(8)
44
+ this.channel_addr_init = new Uint16Array(8)
45
+ this.channel_count = new Uint16Array(8)
46
+ this.channel_count_init = new Uint16Array(8)
47
+ this.channel_mask = new Uint8Array(8)
48
+ this.channel_mode = new Uint8Array(8)
49
+ this.unmask_listeners = []
50
+
51
+ this.lsb_msb_flipflop = 0
52
+
53
+ const io = cpu.io
54
+
55
+ io.register_write(0x00, this, this.port_addr_write.bind(this, 0))
56
+ io.register_write(0x02, this, this.port_addr_write.bind(this, 1))
57
+ io.register_write(0x04, this, this.port_addr_write.bind(this, 2))
58
+ io.register_write(0x06, this, this.port_addr_write.bind(this, 3))
59
+ io.register_write(0x01, this, this.port_count_write.bind(this, 0))
60
+ io.register_write(0x03, this, this.port_count_write.bind(this, 1))
61
+ io.register_write(0x05, this, this.port_count_write.bind(this, 2))
62
+ io.register_write(0x07, this, this.port_count_write.bind(this, 3))
63
+
64
+ io.register_read(0x00, this, this.port_addr_read.bind(this, 0))
65
+ io.register_read(0x02, this, this.port_addr_read.bind(this, 1))
66
+ io.register_read(0x04, this, this.port_addr_read.bind(this, 2))
67
+ io.register_read(0x06, this, this.port_addr_read.bind(this, 3))
68
+ io.register_read(0x01, this, this.port_count_read.bind(this, 0))
69
+ io.register_read(0x03, this, this.port_count_read.bind(this, 1))
70
+ io.register_read(0x05, this, this.port_count_read.bind(this, 2))
71
+ io.register_read(0x07, this, this.port_count_read.bind(this, 3))
72
+
73
+ io.register_write(0xc0, this, this.port_addr_write.bind(this, 4))
74
+ io.register_write(0xc4, this, this.port_addr_write.bind(this, 5))
75
+ io.register_write(0xc8, this, this.port_addr_write.bind(this, 6))
76
+ io.register_write(0xcc, this, this.port_addr_write.bind(this, 7))
77
+ io.register_write(0xc2, this, this.port_count_write.bind(this, 4))
78
+ io.register_write(0xc6, this, this.port_count_write.bind(this, 5))
79
+ io.register_write(0xca, this, this.port_count_write.bind(this, 6))
80
+ io.register_write(0xce, this, this.port_count_write.bind(this, 7))
81
+
82
+ io.register_read(0xc0, this, this.port_addr_read.bind(this, 4))
83
+ io.register_read(0xc4, this, this.port_addr_read.bind(this, 5))
84
+ io.register_read(0xc8, this, this.port_addr_read.bind(this, 6))
85
+ io.register_read(0xcc, this, this.port_addr_read.bind(this, 7))
86
+ io.register_read(0xc2, this, this.port_count_read.bind(this, 4))
87
+ io.register_read(0xc6, this, this.port_count_read.bind(this, 5))
88
+ io.register_read(0xca, this, this.port_count_read.bind(this, 6))
89
+ io.register_read(0xce, this, this.port_count_read.bind(this, 7))
90
+
91
+ io.register_write(0x87, this, this.port_page_write.bind(this, 0))
92
+ io.register_write(0x83, this, this.port_page_write.bind(this, 1))
93
+ io.register_write(0x81, this, this.port_page_write.bind(this, 2))
94
+ io.register_write(0x82, this, this.port_page_write.bind(this, 3))
95
+ io.register_write(0x8f, this, this.port_page_write.bind(this, 4))
96
+ io.register_write(0x8b, this, this.port_page_write.bind(this, 5))
97
+ io.register_write(0x89, this, this.port_page_write.bind(this, 6))
98
+ io.register_write(0x8a, this, this.port_page_write.bind(this, 7))
99
+
100
+ io.register_read(0x87, this, this.port_page_read.bind(this, 0))
101
+ io.register_read(0x83, this, this.port_page_read.bind(this, 1))
102
+ io.register_read(0x81, this, this.port_page_read.bind(this, 2))
103
+ io.register_read(0x82, this, this.port_page_read.bind(this, 3))
104
+ io.register_read(0x8f, this, this.port_page_read.bind(this, 4))
105
+ io.register_read(0x8b, this, this.port_page_read.bind(this, 5))
106
+ io.register_read(0x89, this, this.port_page_read.bind(this, 6))
107
+ io.register_read(0x8a, this, this.port_page_read.bind(this, 7))
108
+
109
+ io.register_write(0x487, this, this.port_pagehi_write.bind(this, 0))
110
+ io.register_write(0x483, this, this.port_pagehi_write.bind(this, 1))
111
+ io.register_write(0x481, this, this.port_pagehi_write.bind(this, 2))
112
+ io.register_write(0x482, this, this.port_pagehi_write.bind(this, 3))
113
+ io.register_write(0x48b, this, this.port_pagehi_write.bind(this, 5))
114
+ io.register_write(0x489, this, this.port_pagehi_write.bind(this, 6))
115
+ io.register_write(0x48a, this, this.port_pagehi_write.bind(this, 7))
116
+
117
+ io.register_read(0x487, this, this.port_pagehi_read.bind(this, 0))
118
+ io.register_read(0x483, this, this.port_pagehi_read.bind(this, 1))
119
+ io.register_read(0x481, this, this.port_pagehi_read.bind(this, 2))
120
+ io.register_read(0x482, this, this.port_pagehi_read.bind(this, 3))
121
+ io.register_read(0x48b, this, this.port_pagehi_read.bind(this, 5))
122
+ io.register_read(0x489, this, this.port_pagehi_read.bind(this, 6))
123
+ io.register_read(0x48a, this, this.port_pagehi_read.bind(this, 7))
124
+
125
+ io.register_write(0x0a, this, this.port_singlemask_write.bind(this, 0))
126
+ io.register_write(0xd4, this, this.port_singlemask_write.bind(this, 4))
127
+ io.register_write(0x0f, this, this.port_multimask_write.bind(this, 0))
128
+ io.register_write(0xde, this, this.port_multimask_write.bind(this, 4))
129
+
130
+ io.register_read(0x0f, this, this.port_multimask_read.bind(this, 0))
131
+ io.register_read(0xde, this, this.port_multimask_read.bind(this, 4))
132
+
133
+ io.register_write(0x0b, this, this.port_mode_write.bind(this, 0))
134
+ io.register_write(0xd6, this, this.port_mode_write.bind(this, 4))
135
+
136
+ io.register_write(0x0c, this, this.portC_write)
137
+ io.register_write(0xd8, this, this.portC_write)
138
+ }
139
+
140
+ get_state(): [
141
+ Uint8Array,
142
+ Uint8Array,
143
+ Uint16Array,
144
+ Uint16Array,
145
+ Uint16Array,
146
+ Uint16Array,
147
+ Uint8Array,
148
+ Uint8Array,
149
+ number,
150
+ ] {
151
+ return [
152
+ this.channel_page,
153
+ this.channel_pagehi,
154
+ this.channel_addr,
155
+ this.channel_addr_init,
156
+ this.channel_count,
157
+ this.channel_count_init,
158
+ this.channel_mask,
159
+ this.channel_mode,
160
+ this.lsb_msb_flipflop,
161
+ ]
162
+ }
163
+
164
+ set_state(
165
+ state: [
166
+ Uint8Array,
167
+ Uint8Array,
168
+ Uint16Array,
169
+ Uint16Array,
170
+ Uint16Array,
171
+ Uint16Array,
172
+ Uint8Array,
173
+ Uint8Array,
174
+ number,
175
+ ],
176
+ ): void {
177
+ this.channel_page = state[0]
178
+ this.channel_pagehi = state[1]
179
+ this.channel_addr = state[2]
180
+ this.channel_addr_init = state[3]
181
+ this.channel_count = state[4]
182
+ this.channel_count_init = state[5]
183
+ this.channel_mask = state[6]
184
+ this.channel_mode = state[7]
185
+ this.lsb_msb_flipflop = state[8]
186
+ }
187
+
188
+ port_count_write(channel: number, data_byte: number): void {
189
+ dbg_log('count write [' + channel + '] = ' + h(data_byte), LOG_DMA)
190
+
191
+ this.channel_count[channel] = this.flipflop_get(
192
+ this.channel_count[channel],
193
+ data_byte,
194
+ false,
195
+ )
196
+
197
+ this.channel_count_init[channel] = this.flipflop_get(
198
+ this.channel_count_init[channel],
199
+ data_byte,
200
+ true,
201
+ )
202
+ }
203
+
204
+ port_count_read(channel: number): number {
205
+ dbg_log(
206
+ 'count read [' + channel + '] -> ' + h(this.channel_count[channel]),
207
+ LOG_DMA,
208
+ )
209
+ return this.flipflop_read(this.channel_count[channel])
210
+ }
211
+
212
+ port_addr_write(channel: number, data_byte: number): void {
213
+ dbg_log('addr write [' + channel + '] = ' + h(data_byte), LOG_DMA)
214
+
215
+ this.channel_addr[channel] = this.flipflop_get(
216
+ this.channel_addr[channel],
217
+ data_byte,
218
+ false,
219
+ )
220
+
221
+ this.channel_addr_init[channel] = this.flipflop_get(
222
+ this.channel_addr_init[channel],
223
+ data_byte,
224
+ true,
225
+ )
226
+ }
227
+
228
+ port_addr_read(channel: number): number {
229
+ dbg_log(
230
+ 'addr read [' + channel + '] -> ' + h(this.channel_addr[channel]),
231
+ LOG_DMA,
232
+ )
233
+ return this.flipflop_read(this.channel_addr[channel])
234
+ }
235
+
236
+ port_pagehi_write(channel: number, data_byte: number): void {
237
+ dbg_log('pagehi write [' + channel + '] = ' + h(data_byte), LOG_DMA)
238
+ this.channel_pagehi[channel] = data_byte
239
+ }
240
+
241
+ port_pagehi_read(channel: number): number {
242
+ dbg_log('pagehi read [' + channel + ']', LOG_DMA)
243
+ return this.channel_pagehi[channel]
244
+ }
245
+
246
+ port_page_write(channel: number, data_byte: number): void {
247
+ dbg_log('page write [' + channel + '] = ' + h(data_byte), LOG_DMA)
248
+ this.channel_page[channel] = data_byte
249
+ }
250
+
251
+ port_page_read(channel: number): number {
252
+ dbg_log('page read [' + channel + ']', LOG_DMA)
253
+ return this.channel_page[channel]
254
+ }
255
+
256
+ port_singlemask_write(channel_offset: number, data_byte: number): void {
257
+ const channel = (data_byte & 0x3) + channel_offset
258
+ const value = data_byte & 0x4 ? 1 : 0
259
+ dbg_log(
260
+ 'singlechannel mask write [' + channel + '] = ' + value,
261
+ LOG_DMA,
262
+ )
263
+ this.update_mask(channel, value)
264
+ }
265
+
266
+ port_multimask_write(channel_offset: number, data_byte: number): void {
267
+ dbg_log('multichannel mask write: ' + h(data_byte), LOG_DMA)
268
+ for (let i = 0; i < 4; i++) {
269
+ this.update_mask(channel_offset + i, data_byte & (1 << i))
270
+ }
271
+ }
272
+
273
+ port_multimask_read(channel_offset: number): number {
274
+ let value = 0
275
+ value |= this.channel_mask[channel_offset + 0]
276
+ value |= this.channel_mask[channel_offset + 1] << 1
277
+ value |= this.channel_mask[channel_offset + 2] << 2
278
+ value |= this.channel_mask[channel_offset + 3] << 3
279
+ dbg_log('multichannel mask read: ' + h(value), LOG_DMA)
280
+ return value
281
+ }
282
+
283
+ port_mode_write(channel_offset: number, data_byte: number): void {
284
+ const channel = (data_byte & 0x3) + channel_offset
285
+ dbg_log('mode write [' + channel + '] = ' + h(data_byte), LOG_DMA)
286
+ this.channel_mode[channel] = data_byte
287
+ }
288
+
289
+ portC_write(_data_byte: number): void {
290
+ dbg_log('flipflop reset', LOG_DMA)
291
+ this.lsb_msb_flipflop = 0
292
+ }
293
+
294
+ on_unmask(fn: (channel: number) => void, this_value: unknown): void {
295
+ this.unmask_listeners.push({
296
+ fn: fn,
297
+ this_value: this_value,
298
+ })
299
+ }
300
+
301
+ update_mask(channel: number, value: number): void {
302
+ if (this.channel_mask[channel] !== value) {
303
+ this.channel_mask[channel] = value
304
+
305
+ if (!value) {
306
+ dbg_log('firing on_unmask(' + channel + ')', LOG_DMA)
307
+ for (let i = 0; i < this.unmask_listeners.length; i++) {
308
+ this.unmask_listeners[i].fn.call(
309
+ this.unmask_listeners[i].this_value,
310
+ channel,
311
+ )
312
+ }
313
+ }
314
+ }
315
+ }
316
+
317
+ // read data, write to memory
318
+ do_read(
319
+ buffer: DMABuffer,
320
+ start: number,
321
+ len: number,
322
+ channel: number,
323
+ fn: (error: boolean) => void,
324
+ ): void {
325
+ const read_count = this.count_get_8bit(channel),
326
+ addr = this.address_get_8bit(channel)
327
+
328
+ dbg_log('DMA write channel ' + channel, LOG_DMA)
329
+ dbg_log('to ' + h(addr) + ' len ' + h(read_count), LOG_DMA)
330
+
331
+ if (len < read_count) {
332
+ dbg_log(
333
+ 'DMA should read more than provided: ' +
334
+ h(len) +
335
+ ' ' +
336
+ h(read_count),
337
+ LOG_DMA,
338
+ )
339
+ }
340
+
341
+ if (start + read_count > buffer.byteLength) {
342
+ dbg_log('DMA read outside of buffer', LOG_DMA)
343
+ fn(true)
344
+ } else {
345
+ const cpu = this.cpu
346
+ this.channel_addr[channel] += read_count
347
+
348
+ buffer.get(start, read_count, function (data: Uint8Array) {
349
+ cpu.write_blob(data, addr)
350
+ fn(false)
351
+ })
352
+ }
353
+ }
354
+
355
+ // write data, read memory
356
+ // start and len in bytes
357
+ do_write(
358
+ buffer: DMABuffer,
359
+ start: number,
360
+ len: number,
361
+ channel: number,
362
+ fn: (error: boolean) => void,
363
+ ): void {
364
+ let read_count = (this.channel_count[channel] + 1) & 0xffff,
365
+ read_bytes = read_count * (channel >= 5 ? 2 : 1),
366
+ unfinished = false,
367
+ want_more = false
368
+ const bytes_per_count = channel >= 5 ? 2 : 1
369
+ const addr = this.address_get_8bit(channel)
370
+ const autoinit = this.channel_mode[channel] & 0x10
371
+
372
+ dbg_log('DMA write channel ' + channel, LOG_DMA)
373
+ dbg_log('to ' + h(addr) + ' len ' + h(read_bytes), LOG_DMA)
374
+
375
+ if (len < read_bytes) {
376
+ dbg_log('DMA should read more than provided', LOG_DMA)
377
+ read_count = Math.floor(len / bytes_per_count)
378
+ read_bytes = read_count * bytes_per_count
379
+ unfinished = true
380
+ } else if (len > read_bytes) {
381
+ dbg_log('DMA attempted to read more than provided', LOG_DMA)
382
+ want_more = true
383
+ }
384
+
385
+ if (start + read_bytes > buffer.byteLength) {
386
+ dbg_log('DMA write outside of buffer', LOG_DMA)
387
+ fn(true)
388
+ } else {
389
+ this.channel_addr[channel] += read_count
390
+ this.channel_count[channel] -= read_count
391
+ // when complete, counter should underflow to 0xFFFF
392
+
393
+ if (!unfinished && autoinit) {
394
+ dbg_log('DMA autoinit', LOG_DMA)
395
+ this.channel_addr[channel] = this.channel_addr_init[channel]
396
+ this.channel_count[channel] = this.channel_count_init[channel]
397
+ }
398
+
399
+ buffer.set(
400
+ start,
401
+ this.cpu.mem8.subarray(addr, addr + read_bytes),
402
+ () => {
403
+ if (want_more && autoinit) {
404
+ dbg_log('DMA continuing from start', LOG_DMA)
405
+ this.do_write(
406
+ buffer,
407
+ start + read_bytes,
408
+ len - read_bytes,
409
+ channel,
410
+ fn,
411
+ )
412
+ } else {
413
+ fn(false)
414
+ }
415
+ },
416
+ )
417
+ }
418
+ }
419
+
420
+ address_get_8bit(channel: number): number {
421
+ let addr = this.channel_addr[channel]
422
+
423
+ // http://wiki.osdev.org/ISA_DMA#16_bit_issues
424
+ if (channel >= 5) {
425
+ addr = addr << 1
426
+ }
427
+
428
+ addr &= 0xffff
429
+ addr |= this.channel_page[channel] << 16
430
+ addr |= this.channel_pagehi[channel] << 24
431
+
432
+ return addr
433
+ }
434
+
435
+ count_get_8bit(channel: number): number {
436
+ let count = this.channel_count[channel] + 1
437
+
438
+ if (channel >= 5) {
439
+ count *= 2
440
+ }
441
+
442
+ return count
443
+ }
444
+
445
+ flipflop_get(
446
+ old_dword: number,
447
+ new_byte: number,
448
+ continuing: boolean,
449
+ ): number {
450
+ if (!continuing) {
451
+ this.lsb_msb_flipflop ^= 1
452
+ }
453
+
454
+ if (this.lsb_msb_flipflop) {
455
+ // low byte
456
+ return (old_dword & ~0xff) | new_byte
457
+ } else {
458
+ // high byte
459
+ return (old_dword & ~0xff00) | (new_byte << 8)
460
+ }
461
+ }
462
+
463
+ flipflop_read(dword: number): number {
464
+ this.lsb_msb_flipflop ^= 1
465
+
466
+ if (this.lsb_msb_flipflop) {
467
+ // low byte
468
+ return dword & 0xff
469
+ } else {
470
+ // high byte
471
+ return (dword >> 8) & 0xff
472
+ }
473
+ }
474
+ }