@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.
- package/LICENSE +22 -0
- package/LICENSE.MIT +22 -0
- package/Readme.md +237 -0
- package/dist/v86.browser.js +26666 -0
- package/dist/v86.browser.js.map +7 -0
- package/dist/v86.js +26632 -0
- package/dist/v86.js.map +7 -0
- package/gen/generate_analyzer.ts +512 -0
- package/gen/generate_interpreter.ts +522 -0
- package/gen/generate_jit.ts +624 -0
- package/gen/rust_ast.ts +107 -0
- package/gen/util.ts +35 -0
- package/gen/x86_table.ts +1836 -0
- package/lib/9p.ts +1547 -0
- package/lib/filesystem.ts +1879 -0
- package/lib/marshall.ts +168 -0
- package/lib/softfloat/softfloat.c +32501 -0
- package/lib/zstd/zstddeclib.c +13520 -0
- package/package.json +75 -0
- package/src/acpi.ts +267 -0
- package/src/browser/dummy_screen.ts +106 -0
- package/src/browser/fake_network.ts +1771 -0
- package/src/browser/fetch_network.ts +361 -0
- package/src/browser/filestorage.ts +124 -0
- package/src/browser/inbrowser_network.ts +57 -0
- package/src/browser/keyboard.ts +564 -0
- package/src/browser/main.ts +3415 -0
- package/src/browser/mouse.ts +255 -0
- package/src/browser/network.ts +142 -0
- package/src/browser/print_stats.ts +336 -0
- package/src/browser/screen.ts +978 -0
- package/src/browser/serial.ts +316 -0
- package/src/browser/speaker.ts +1223 -0
- package/src/browser/starter.ts +1688 -0
- package/src/browser/wisp_network.ts +332 -0
- package/src/browser/worker_bus.ts +64 -0
- package/src/buffer.ts +652 -0
- package/src/bus.ts +78 -0
- package/src/const.ts +128 -0
- package/src/cpu.ts +2891 -0
- package/src/dma.ts +474 -0
- package/src/elf.ts +251 -0
- package/src/floppy.ts +1778 -0
- package/src/ide.ts +3455 -0
- package/src/io.ts +504 -0
- package/src/iso9660.ts +317 -0
- package/src/kernel.ts +250 -0
- package/src/lib.ts +645 -0
- package/src/log.ts +149 -0
- package/src/main.ts +199 -0
- package/src/ne2k.ts +1589 -0
- package/src/pci.ts +815 -0
- package/src/pit.ts +406 -0
- package/src/ps2.ts +820 -0
- package/src/rtc.ts +537 -0
- package/src/rust/analysis.rs +101 -0
- package/src/rust/codegen.rs +2660 -0
- package/src/rust/config.rs +3 -0
- package/src/rust/control_flow.rs +425 -0
- package/src/rust/cpu/apic.rs +658 -0
- package/src/rust/cpu/arith.rs +1207 -0
- package/src/rust/cpu/call_indirect.rs +2 -0
- package/src/rust/cpu/cpu.rs +4501 -0
- package/src/rust/cpu/fpu.rs +923 -0
- package/src/rust/cpu/global_pointers.rs +112 -0
- package/src/rust/cpu/instructions.rs +2486 -0
- package/src/rust/cpu/instructions_0f.rs +5261 -0
- package/src/rust/cpu/ioapic.rs +316 -0
- package/src/rust/cpu/memory.rs +351 -0
- package/src/rust/cpu/misc_instr.rs +613 -0
- package/src/rust/cpu/mod.rs +16 -0
- package/src/rust/cpu/modrm.rs +133 -0
- package/src/rust/cpu/pic.rs +402 -0
- package/src/rust/cpu/sse_instr.rs +361 -0
- package/src/rust/cpu/string.rs +701 -0
- package/src/rust/cpu/vga.rs +175 -0
- package/src/rust/cpu_context.rs +69 -0
- package/src/rust/dbg.rs +98 -0
- package/src/rust/gen/analyzer.rs +3807 -0
- package/src/rust/gen/analyzer0f.rs +3992 -0
- package/src/rust/gen/interpreter.rs +4447 -0
- package/src/rust/gen/interpreter0f.rs +5404 -0
- package/src/rust/gen/jit.rs +5080 -0
- package/src/rust/gen/jit0f.rs +5547 -0
- package/src/rust/gen/mod.rs +14 -0
- package/src/rust/jit.rs +2443 -0
- package/src/rust/jit_instructions.rs +7881 -0
- package/src/rust/js_api.rs +6 -0
- package/src/rust/leb.rs +46 -0
- package/src/rust/lib.rs +29 -0
- package/src/rust/modrm.rs +330 -0
- package/src/rust/opstats.rs +249 -0
- package/src/rust/page.rs +15 -0
- package/src/rust/paging.rs +25 -0
- package/src/rust/prefix.rs +15 -0
- package/src/rust/profiler.rs +155 -0
- package/src/rust/regs.rs +38 -0
- package/src/rust/softfloat.rs +286 -0
- package/src/rust/state_flags.rs +27 -0
- package/src/rust/wasmgen/mod.rs +2 -0
- package/src/rust/wasmgen/wasm_builder.rs +1047 -0
- package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
- package/src/rust/zstd.rs +105 -0
- package/src/sb16.ts +1928 -0
- package/src/state.ts +359 -0
- package/src/uart.ts +472 -0
- package/src/vga.ts +2791 -0
- package/src/virtio.ts +1756 -0
- package/src/virtio_balloon.ts +273 -0
- package/src/virtio_console.ts +372 -0
- package/src/virtio_net.ts +326 -0
package/src/rtc.ts
ADDED
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
import { v86 } from './main.js'
|
|
2
|
+
import { LOG_RTC } from './const.js'
|
|
3
|
+
import { h } from './lib.js'
|
|
4
|
+
import { dbg_assert, dbg_log } from './log.js'
|
|
5
|
+
import { IO } from './io.js'
|
|
6
|
+
|
|
7
|
+
// Minimal interface for CPU fields RTC uses
|
|
8
|
+
interface RTCCpu {
|
|
9
|
+
io: IO
|
|
10
|
+
device_raise_irq(irq: number): void
|
|
11
|
+
device_lower_irq(irq: number): void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const CMOS_RTC_SECONDS = 0x00
|
|
15
|
+
export const CMOS_RTC_SECONDS_ALARM = 0x01
|
|
16
|
+
export const CMOS_RTC_MINUTES = 0x02
|
|
17
|
+
export const CMOS_RTC_MINUTES_ALARM = 0x03
|
|
18
|
+
export const CMOS_RTC_HOURS = 0x04
|
|
19
|
+
export const CMOS_RTC_HOURS_ALARM = 0x05
|
|
20
|
+
export const CMOS_RTC_DAY_WEEK = 0x06
|
|
21
|
+
export const CMOS_RTC_DAY_MONTH = 0x07
|
|
22
|
+
export const CMOS_RTC_MONTH = 0x08
|
|
23
|
+
export const CMOS_RTC_YEAR = 0x09
|
|
24
|
+
export const CMOS_STATUS_A = 0x0a
|
|
25
|
+
export const CMOS_STATUS_B = 0x0b
|
|
26
|
+
export const CMOS_STATUS_C = 0x0c
|
|
27
|
+
export const CMOS_STATUS_D = 0x0d
|
|
28
|
+
export const CMOS_DIAG_STATUS = 0x0e
|
|
29
|
+
export const CMOS_RESET_CODE = 0x0f
|
|
30
|
+
|
|
31
|
+
export const CMOS_FLOPPY_DRIVE_TYPE = 0x10
|
|
32
|
+
export const CMOS_DISK_DATA = 0x12
|
|
33
|
+
export const CMOS_EQUIPMENT_INFO = 0x14
|
|
34
|
+
export const CMOS_MEM_BASE_LOW = 0x15
|
|
35
|
+
export const CMOS_MEM_BASE_HIGH = 0x16
|
|
36
|
+
export const CMOS_MEM_OLD_EXT_LOW = 0x17
|
|
37
|
+
export const CMOS_MEM_OLD_EXT_HIGH = 0x18
|
|
38
|
+
export const CMOS_DISK_DRIVE1_TYPE = 0x19
|
|
39
|
+
export const CMOS_DISK_DRIVE2_TYPE = 0x1a
|
|
40
|
+
export const CMOS_DISK_DRIVE1_CYL = 0x1b
|
|
41
|
+
export const CMOS_DISK_DRIVE2_CYL = 0x24
|
|
42
|
+
export const CMOS_MEM_EXTMEM_LOW = 0x30
|
|
43
|
+
export const CMOS_MEM_EXTMEM_HIGH = 0x31
|
|
44
|
+
export const CMOS_CENTURY = 0x32
|
|
45
|
+
export const CMOS_MEM_EXTMEM2_LOW = 0x34
|
|
46
|
+
export const CMOS_MEM_EXTMEM2_HIGH = 0x35
|
|
47
|
+
export const CMOS_CENTURY2 = 0x37
|
|
48
|
+
export const CMOS_BIOS_BOOTFLAG1 = 0x38
|
|
49
|
+
export const CMOS_BIOS_DISKTRANSFLAG = 0x39
|
|
50
|
+
export const CMOS_BIOS_BOOTFLAG2 = 0x3d
|
|
51
|
+
export const CMOS_MEM_HIGHMEM_LOW = 0x5b
|
|
52
|
+
export const CMOS_MEM_HIGHMEM_MID = 0x5c
|
|
53
|
+
export const CMOS_MEM_HIGHMEM_HIGH = 0x5d
|
|
54
|
+
export const CMOS_BIOS_SMP_COUNT = 0x5f
|
|
55
|
+
|
|
56
|
+
// see CPU.prototype.fill_cmos
|
|
57
|
+
export const BOOT_ORDER_CD_FIRST = 0x123
|
|
58
|
+
export const BOOT_ORDER_HD_FIRST = 0x312
|
|
59
|
+
export const BOOT_ORDER_FD_FIRST = 0x321
|
|
60
|
+
|
|
61
|
+
type RTCState = [
|
|
62
|
+
number,
|
|
63
|
+
Uint8Array,
|
|
64
|
+
number,
|
|
65
|
+
number,
|
|
66
|
+
number,
|
|
67
|
+
number,
|
|
68
|
+
boolean,
|
|
69
|
+
number,
|
|
70
|
+
number,
|
|
71
|
+
number,
|
|
72
|
+
number,
|
|
73
|
+
number,
|
|
74
|
+
boolean,
|
|
75
|
+
number,
|
|
76
|
+
number,
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* RTC (real time clock) and CMOS
|
|
81
|
+
*/
|
|
82
|
+
export class RTC {
|
|
83
|
+
name: string
|
|
84
|
+
cpu: RTCCpu
|
|
85
|
+
cmos_index: number
|
|
86
|
+
cmos_data: Uint8Array
|
|
87
|
+
rtc_time: number
|
|
88
|
+
last_update: number
|
|
89
|
+
next_interrupt: number
|
|
90
|
+
next_interrupt_alarm: number
|
|
91
|
+
periodic_interrupt: boolean
|
|
92
|
+
periodic_interrupt_time: number
|
|
93
|
+
cmos_a: number
|
|
94
|
+
cmos_b: number
|
|
95
|
+
cmos_c: number
|
|
96
|
+
cmos_diag_status: number
|
|
97
|
+
nmi_disabled: number
|
|
98
|
+
update_interrupt: boolean
|
|
99
|
+
update_interrupt_time: number
|
|
100
|
+
|
|
101
|
+
constructor(cpu: RTCCpu) {
|
|
102
|
+
this.name = 'rtc'
|
|
103
|
+
this.cpu = cpu
|
|
104
|
+
|
|
105
|
+
this.cmos_index = 0
|
|
106
|
+
this.cmos_data = new Uint8Array(128)
|
|
107
|
+
|
|
108
|
+
// used for cmos entries
|
|
109
|
+
this.rtc_time = Date.now()
|
|
110
|
+
this.last_update = this.rtc_time
|
|
111
|
+
|
|
112
|
+
// used for periodic interrupt
|
|
113
|
+
this.next_interrupt = 0
|
|
114
|
+
|
|
115
|
+
// next alarm interrupt
|
|
116
|
+
this.next_interrupt_alarm = 0
|
|
117
|
+
|
|
118
|
+
this.periodic_interrupt = false
|
|
119
|
+
|
|
120
|
+
// corresponds to default value for cmos_a
|
|
121
|
+
this.periodic_interrupt_time = 1000 / 1024
|
|
122
|
+
|
|
123
|
+
this.cmos_a = 0x26
|
|
124
|
+
this.cmos_b = 2
|
|
125
|
+
this.cmos_c = 0
|
|
126
|
+
|
|
127
|
+
this.cmos_diag_status = 0
|
|
128
|
+
|
|
129
|
+
this.nmi_disabled = 0
|
|
130
|
+
|
|
131
|
+
this.update_interrupt = false
|
|
132
|
+
this.update_interrupt_time = 0
|
|
133
|
+
|
|
134
|
+
cpu.io.register_write(0x70, this, (out_byte: number): void => {
|
|
135
|
+
this.cmos_index = out_byte & 0x7f
|
|
136
|
+
this.nmi_disabled = out_byte >> 7
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
cpu.io.register_write(0x71, this, this.cmos_port_write.bind(this))
|
|
140
|
+
cpu.io.register_read(0x71, this, this.cmos_port_read.bind(this))
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
get_state(): RTCState {
|
|
144
|
+
const state: RTCState = [
|
|
145
|
+
this.cmos_index,
|
|
146
|
+
this.cmos_data,
|
|
147
|
+
this.rtc_time,
|
|
148
|
+
this.last_update,
|
|
149
|
+
this.next_interrupt,
|
|
150
|
+
this.next_interrupt_alarm,
|
|
151
|
+
this.periodic_interrupt,
|
|
152
|
+
this.periodic_interrupt_time,
|
|
153
|
+
this.cmos_a,
|
|
154
|
+
this.cmos_b,
|
|
155
|
+
this.cmos_c,
|
|
156
|
+
this.nmi_disabled,
|
|
157
|
+
this.update_interrupt,
|
|
158
|
+
this.update_interrupt_time,
|
|
159
|
+
this.cmos_diag_status,
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
return state
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
set_state(state: RTCState): void {
|
|
166
|
+
this.cmos_index = state[0]
|
|
167
|
+
this.cmos_data = state[1]
|
|
168
|
+
this.rtc_time = state[2]
|
|
169
|
+
this.last_update = state[3]
|
|
170
|
+
this.next_interrupt = state[4]
|
|
171
|
+
this.next_interrupt_alarm = state[5]
|
|
172
|
+
this.periodic_interrupt = state[6]
|
|
173
|
+
this.periodic_interrupt_time = state[7]
|
|
174
|
+
this.cmos_a = state[8]
|
|
175
|
+
this.cmos_b = state[9]
|
|
176
|
+
this.cmos_c = state[10]
|
|
177
|
+
this.nmi_disabled = state[11]
|
|
178
|
+
this.update_interrupt = state[12] || false
|
|
179
|
+
this.update_interrupt_time = state[13] || 0
|
|
180
|
+
this.cmos_diag_status = state[14] || 0
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
timer(time: number, _legacy_mode: boolean): number {
|
|
184
|
+
time = Date.now() // XXX
|
|
185
|
+
this.rtc_time += time - this.last_update
|
|
186
|
+
this.last_update = time
|
|
187
|
+
|
|
188
|
+
if (this.periodic_interrupt && this.next_interrupt < time) {
|
|
189
|
+
this.cpu.device_raise_irq(8)
|
|
190
|
+
this.cmos_c |= (1 << 6) | (1 << 7)
|
|
191
|
+
|
|
192
|
+
this.next_interrupt +=
|
|
193
|
+
this.periodic_interrupt_time *
|
|
194
|
+
Math.ceil(
|
|
195
|
+
(time - this.next_interrupt) / this.periodic_interrupt_time,
|
|
196
|
+
)
|
|
197
|
+
} else if (
|
|
198
|
+
this.next_interrupt_alarm &&
|
|
199
|
+
this.next_interrupt_alarm < time
|
|
200
|
+
) {
|
|
201
|
+
this.cpu.device_raise_irq(8)
|
|
202
|
+
this.cmos_c |= (1 << 5) | (1 << 7)
|
|
203
|
+
|
|
204
|
+
this.next_interrupt_alarm = 0
|
|
205
|
+
} else if (this.update_interrupt && this.update_interrupt_time < time) {
|
|
206
|
+
this.cpu.device_raise_irq(8)
|
|
207
|
+
this.cmos_c |= (1 << 4) | (1 << 7)
|
|
208
|
+
|
|
209
|
+
this.update_interrupt_time = time + 1000 // 1 second
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
let t = 100
|
|
213
|
+
|
|
214
|
+
if (this.periodic_interrupt && this.next_interrupt) {
|
|
215
|
+
t = Math.min(t, Math.max(0, this.next_interrupt - time))
|
|
216
|
+
}
|
|
217
|
+
if (this.next_interrupt_alarm) {
|
|
218
|
+
t = Math.min(t, Math.max(0, this.next_interrupt_alarm - time))
|
|
219
|
+
}
|
|
220
|
+
if (this.update_interrupt) {
|
|
221
|
+
t = Math.min(t, Math.max(0, this.update_interrupt_time - time))
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return t
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
bcd_pack(n: number): number {
|
|
228
|
+
let i = 0,
|
|
229
|
+
result = 0,
|
|
230
|
+
digit: number
|
|
231
|
+
|
|
232
|
+
while (n) {
|
|
233
|
+
digit = n % 10
|
|
234
|
+
|
|
235
|
+
result |= digit << (4 * i)
|
|
236
|
+
i++
|
|
237
|
+
n = (n - digit) / 10
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return result
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
bcd_unpack(n: number): number {
|
|
244
|
+
const low = n & 0xf
|
|
245
|
+
const high = (n >> 4) & 0xf
|
|
246
|
+
|
|
247
|
+
dbg_assert(n < 0x100)
|
|
248
|
+
dbg_assert(low < 10)
|
|
249
|
+
dbg_assert(high < 10)
|
|
250
|
+
|
|
251
|
+
return low + 10 * high
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
encode_time(t: number): number {
|
|
255
|
+
if (this.cmos_b & 4) {
|
|
256
|
+
// binary mode
|
|
257
|
+
return t
|
|
258
|
+
} else {
|
|
259
|
+
return this.bcd_pack(t)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
decode_time(t: number): number {
|
|
264
|
+
if (this.cmos_b & 4) {
|
|
265
|
+
// binary mode
|
|
266
|
+
return t
|
|
267
|
+
} else {
|
|
268
|
+
return this.bcd_unpack(t)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// TODO
|
|
273
|
+
// - interrupt on update
|
|
274
|
+
// - countdown
|
|
275
|
+
// - letting bios/os set values
|
|
276
|
+
// (none of these are used by seabios or the OSes we're
|
|
277
|
+
// currently testing)
|
|
278
|
+
cmos_port_read(): number {
|
|
279
|
+
const index = this.cmos_index
|
|
280
|
+
|
|
281
|
+
//this.cmos_index = 0xD;
|
|
282
|
+
|
|
283
|
+
switch (index) {
|
|
284
|
+
case CMOS_RTC_SECONDS:
|
|
285
|
+
dbg_log(
|
|
286
|
+
'read second: ' +
|
|
287
|
+
h(
|
|
288
|
+
this.encode_time(
|
|
289
|
+
new Date(this.rtc_time).getUTCSeconds(),
|
|
290
|
+
),
|
|
291
|
+
),
|
|
292
|
+
LOG_RTC,
|
|
293
|
+
)
|
|
294
|
+
return this.encode_time(new Date(this.rtc_time).getUTCSeconds())
|
|
295
|
+
case CMOS_RTC_MINUTES:
|
|
296
|
+
dbg_log(
|
|
297
|
+
'read minute: ' +
|
|
298
|
+
h(
|
|
299
|
+
this.encode_time(
|
|
300
|
+
new Date(this.rtc_time).getUTCMinutes(),
|
|
301
|
+
),
|
|
302
|
+
),
|
|
303
|
+
LOG_RTC,
|
|
304
|
+
)
|
|
305
|
+
return this.encode_time(new Date(this.rtc_time).getUTCMinutes())
|
|
306
|
+
case CMOS_RTC_HOURS:
|
|
307
|
+
dbg_log(
|
|
308
|
+
'read hour: ' +
|
|
309
|
+
h(
|
|
310
|
+
this.encode_time(
|
|
311
|
+
new Date(this.rtc_time).getUTCHours(),
|
|
312
|
+
),
|
|
313
|
+
),
|
|
314
|
+
LOG_RTC,
|
|
315
|
+
)
|
|
316
|
+
// TODO: 12 hour mode
|
|
317
|
+
return this.encode_time(new Date(this.rtc_time).getUTCHours())
|
|
318
|
+
case CMOS_RTC_DAY_WEEK:
|
|
319
|
+
dbg_log(
|
|
320
|
+
'read day: ' +
|
|
321
|
+
h(
|
|
322
|
+
this.encode_time(
|
|
323
|
+
new Date(this.rtc_time).getUTCDay() + 1,
|
|
324
|
+
),
|
|
325
|
+
),
|
|
326
|
+
LOG_RTC,
|
|
327
|
+
)
|
|
328
|
+
return this.encode_time(new Date(this.rtc_time).getUTCDay() + 1)
|
|
329
|
+
case CMOS_RTC_DAY_MONTH:
|
|
330
|
+
dbg_log(
|
|
331
|
+
'read day of month: ' +
|
|
332
|
+
h(
|
|
333
|
+
this.encode_time(
|
|
334
|
+
new Date(this.rtc_time).getUTCDate(),
|
|
335
|
+
),
|
|
336
|
+
),
|
|
337
|
+
LOG_RTC,
|
|
338
|
+
)
|
|
339
|
+
return this.encode_time(new Date(this.rtc_time).getUTCDate())
|
|
340
|
+
case CMOS_RTC_MONTH:
|
|
341
|
+
dbg_log(
|
|
342
|
+
'read month: ' +
|
|
343
|
+
h(
|
|
344
|
+
this.encode_time(
|
|
345
|
+
new Date(this.rtc_time).getUTCMonth() + 1,
|
|
346
|
+
),
|
|
347
|
+
),
|
|
348
|
+
LOG_RTC,
|
|
349
|
+
)
|
|
350
|
+
return this.encode_time(
|
|
351
|
+
new Date(this.rtc_time).getUTCMonth() + 1,
|
|
352
|
+
)
|
|
353
|
+
case CMOS_RTC_YEAR:
|
|
354
|
+
dbg_log(
|
|
355
|
+
'read year: ' +
|
|
356
|
+
h(
|
|
357
|
+
this.encode_time(
|
|
358
|
+
new Date(this.rtc_time).getUTCFullYear() % 100,
|
|
359
|
+
),
|
|
360
|
+
),
|
|
361
|
+
LOG_RTC,
|
|
362
|
+
)
|
|
363
|
+
return this.encode_time(
|
|
364
|
+
new Date(this.rtc_time).getUTCFullYear() % 100,
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
case CMOS_STATUS_A:
|
|
368
|
+
if (v86.microtick() % 1000 >= 999) {
|
|
369
|
+
// Set update-in-progress for one millisecond every second (we
|
|
370
|
+
// may not have precision higher than that in browser
|
|
371
|
+
// environments)
|
|
372
|
+
return this.cmos_a | 0x80
|
|
373
|
+
}
|
|
374
|
+
return this.cmos_a
|
|
375
|
+
case CMOS_STATUS_B:
|
|
376
|
+
//dbg_log("cmos read from index " + h(index));
|
|
377
|
+
return this.cmos_b
|
|
378
|
+
|
|
379
|
+
case CMOS_STATUS_C: {
|
|
380
|
+
// It is important to know that upon a IRQ 8, Status Register C
|
|
381
|
+
// will contain a bitmask telling which interrupt happened.
|
|
382
|
+
// What is important is that if register C is not read after an
|
|
383
|
+
// IRQ 8, then the interrupt will not happen again.
|
|
384
|
+
this.cpu.device_lower_irq(8)
|
|
385
|
+
|
|
386
|
+
dbg_log('cmos reg C read', LOG_RTC)
|
|
387
|
+
// Missing IRQF flag
|
|
388
|
+
//return cmos_b & 0x70;
|
|
389
|
+
const c = this.cmos_c
|
|
390
|
+
|
|
391
|
+
this.cmos_c &= ~0xf0
|
|
392
|
+
|
|
393
|
+
return c
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
case CMOS_STATUS_D:
|
|
397
|
+
return 1 << 7 // CMOS battery charged
|
|
398
|
+
|
|
399
|
+
case CMOS_DIAG_STATUS:
|
|
400
|
+
dbg_log('cmos diagnostic status read', LOG_RTC)
|
|
401
|
+
return this.cmos_diag_status
|
|
402
|
+
|
|
403
|
+
case CMOS_CENTURY:
|
|
404
|
+
case CMOS_CENTURY2:
|
|
405
|
+
dbg_log(
|
|
406
|
+
'read century: ' +
|
|
407
|
+
h(
|
|
408
|
+
this.encode_time(
|
|
409
|
+
(new Date(this.rtc_time).getUTCFullYear() /
|
|
410
|
+
100) |
|
|
411
|
+
0,
|
|
412
|
+
),
|
|
413
|
+
),
|
|
414
|
+
LOG_RTC,
|
|
415
|
+
)
|
|
416
|
+
return this.encode_time(
|
|
417
|
+
(new Date(this.rtc_time).getUTCFullYear() / 100) | 0,
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
default:
|
|
421
|
+
dbg_log('cmos read from index ' + h(index), LOG_RTC)
|
|
422
|
+
return this.cmos_data[this.cmos_index]
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
cmos_port_write(data_byte: number): void {
|
|
427
|
+
switch (this.cmos_index) {
|
|
428
|
+
case 0xa:
|
|
429
|
+
this.cmos_a = data_byte & 0x7f
|
|
430
|
+
this.periodic_interrupt_time =
|
|
431
|
+
1000 / (32768 >> ((this.cmos_a & 0xf) - 1))
|
|
432
|
+
|
|
433
|
+
dbg_log(
|
|
434
|
+
'Periodic interrupt, a=' +
|
|
435
|
+
h(this.cmos_a, 2) +
|
|
436
|
+
' t=' +
|
|
437
|
+
this.periodic_interrupt_time,
|
|
438
|
+
LOG_RTC,
|
|
439
|
+
)
|
|
440
|
+
break
|
|
441
|
+
case 0xb:
|
|
442
|
+
this.cmos_b = data_byte
|
|
443
|
+
if (this.cmos_b & 0x80) {
|
|
444
|
+
// remove update interrupt flag
|
|
445
|
+
this.cmos_b &= 0xef
|
|
446
|
+
}
|
|
447
|
+
if (this.cmos_b & 0x40) {
|
|
448
|
+
this.next_interrupt = Date.now()
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (this.cmos_b & 0x20) {
|
|
452
|
+
const now = new Date()
|
|
453
|
+
|
|
454
|
+
const seconds = this.decode_time(
|
|
455
|
+
this.cmos_data[CMOS_RTC_SECONDS_ALARM],
|
|
456
|
+
)
|
|
457
|
+
const minutes = this.decode_time(
|
|
458
|
+
this.cmos_data[CMOS_RTC_MINUTES_ALARM],
|
|
459
|
+
)
|
|
460
|
+
const hours = this.decode_time(
|
|
461
|
+
this.cmos_data[CMOS_RTC_HOURS_ALARM],
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
const alarm_date = new Date(
|
|
465
|
+
Date.UTC(
|
|
466
|
+
now.getUTCFullYear(),
|
|
467
|
+
now.getUTCMonth(),
|
|
468
|
+
now.getUTCDate(),
|
|
469
|
+
hours,
|
|
470
|
+
minutes,
|
|
471
|
+
seconds,
|
|
472
|
+
),
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
const ms_from_now = +alarm_date - +now
|
|
476
|
+
dbg_log(
|
|
477
|
+
'RTC alarm scheduled for ' +
|
|
478
|
+
alarm_date +
|
|
479
|
+
' hh:mm:ss=' +
|
|
480
|
+
hours +
|
|
481
|
+
':' +
|
|
482
|
+
minutes +
|
|
483
|
+
':' +
|
|
484
|
+
seconds +
|
|
485
|
+
' ms_from_now=' +
|
|
486
|
+
ms_from_now,
|
|
487
|
+
LOG_RTC,
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
this.next_interrupt_alarm = +alarm_date
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
if (this.cmos_b & 0x10) {
|
|
494
|
+
dbg_log('update interrupt', LOG_RTC)
|
|
495
|
+
this.update_interrupt_time = Date.now()
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
dbg_log('cmos b=' + h(this.cmos_b, 2), LOG_RTC)
|
|
499
|
+
break
|
|
500
|
+
|
|
501
|
+
case CMOS_DIAG_STATUS:
|
|
502
|
+
this.cmos_diag_status = data_byte
|
|
503
|
+
break
|
|
504
|
+
|
|
505
|
+
case CMOS_RTC_SECONDS_ALARM:
|
|
506
|
+
case CMOS_RTC_MINUTES_ALARM:
|
|
507
|
+
case CMOS_RTC_HOURS_ALARM:
|
|
508
|
+
this.cmos_write(this.cmos_index, data_byte)
|
|
509
|
+
break
|
|
510
|
+
|
|
511
|
+
default:
|
|
512
|
+
dbg_log(
|
|
513
|
+
'cmos write index ' +
|
|
514
|
+
h(this.cmos_index) +
|
|
515
|
+
': ' +
|
|
516
|
+
h(data_byte),
|
|
517
|
+
LOG_RTC,
|
|
518
|
+
)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
this.update_interrupt =
|
|
522
|
+
(this.cmos_b & 0x10) === 0x10 && (this.cmos_a & 0xf) > 0
|
|
523
|
+
this.periodic_interrupt =
|
|
524
|
+
(this.cmos_b & 0x40) === 0x40 && (this.cmos_a & 0xf) > 0
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
cmos_read(index: number): number {
|
|
528
|
+
dbg_assert(index < 128)
|
|
529
|
+
return this.cmos_data[index]
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
cmos_write(index: number, value: number): void {
|
|
533
|
+
dbg_log('cmos ' + h(index) + ' <- ' + h(value), LOG_RTC)
|
|
534
|
+
dbg_assert(index < 128)
|
|
535
|
+
this.cmos_data[index] = value
|
|
536
|
+
}
|
|
537
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#![allow(non_snake_case)]
|
|
2
|
+
|
|
3
|
+
use crate::cpu_context::CpuContext;
|
|
4
|
+
use crate::gen;
|
|
5
|
+
use crate::modrm;
|
|
6
|
+
use crate::prefix::{PREFIX_66, PREFIX_67, PREFIX_F2, PREFIX_F3};
|
|
7
|
+
use crate::regs::{CS, DS, ES, FS, GS, SS};
|
|
8
|
+
|
|
9
|
+
#[derive(PartialEq, Eq)]
|
|
10
|
+
pub enum AnalysisType {
|
|
11
|
+
Normal,
|
|
12
|
+
BlockBoundary,
|
|
13
|
+
Jump {
|
|
14
|
+
offset: i32,
|
|
15
|
+
is_32: bool,
|
|
16
|
+
condition: Option<u8>,
|
|
17
|
+
},
|
|
18
|
+
STI,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
pub struct Analysis {
|
|
22
|
+
pub no_next_instruction: bool,
|
|
23
|
+
pub absolute_jump: bool,
|
|
24
|
+
pub ty: AnalysisType,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pub fn analyze_step(mut cpu: &mut CpuContext) -> Analysis {
|
|
28
|
+
let mut analysis = Analysis {
|
|
29
|
+
no_next_instruction: false,
|
|
30
|
+
absolute_jump: false,
|
|
31
|
+
ty: AnalysisType::Normal,
|
|
32
|
+
};
|
|
33
|
+
cpu.prefixes = 0;
|
|
34
|
+
let opcode = cpu.read_imm8() as u32 | (cpu.osize_32() as u32) << 8;
|
|
35
|
+
gen::analyzer::analyzer(opcode, &mut cpu, &mut analysis);
|
|
36
|
+
analysis
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
pub fn analyze_step_handle_prefix(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
40
|
+
gen::analyzer::analyzer(
|
|
41
|
+
cpu.read_imm8() as u32 | (cpu.osize_32() as u32) << 8,
|
|
42
|
+
cpu,
|
|
43
|
+
analysis,
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
pub fn analyze_step_handle_segment_prefix(
|
|
47
|
+
segment: u32,
|
|
48
|
+
cpu: &mut CpuContext,
|
|
49
|
+
analysis: &mut Analysis,
|
|
50
|
+
) {
|
|
51
|
+
dbg_assert!(segment <= 5);
|
|
52
|
+
cpu.prefixes |= segment as u8 + 1;
|
|
53
|
+
analyze_step_handle_prefix(cpu, analysis)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pub fn instr16_0F_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
57
|
+
gen::analyzer0f::analyzer(cpu.read_imm8() as u32, cpu, analysis)
|
|
58
|
+
}
|
|
59
|
+
pub fn instr32_0F_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
60
|
+
gen::analyzer0f::analyzer(cpu.read_imm8() as u32 | 0x100, cpu, analysis)
|
|
61
|
+
}
|
|
62
|
+
pub fn instr_26_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
63
|
+
analyze_step_handle_segment_prefix(ES, cpu, analysis)
|
|
64
|
+
}
|
|
65
|
+
pub fn instr_2E_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
66
|
+
analyze_step_handle_segment_prefix(CS, cpu, analysis)
|
|
67
|
+
}
|
|
68
|
+
pub fn instr_36_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
69
|
+
analyze_step_handle_segment_prefix(SS, cpu, analysis)
|
|
70
|
+
}
|
|
71
|
+
pub fn instr_3E_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
72
|
+
analyze_step_handle_segment_prefix(DS, cpu, analysis)
|
|
73
|
+
}
|
|
74
|
+
pub fn instr_64_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
75
|
+
analyze_step_handle_segment_prefix(FS, cpu, analysis)
|
|
76
|
+
}
|
|
77
|
+
pub fn instr_65_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
78
|
+
analyze_step_handle_segment_prefix(GS, cpu, analysis)
|
|
79
|
+
}
|
|
80
|
+
pub fn instr_66_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
81
|
+
cpu.prefixes |= PREFIX_66;
|
|
82
|
+
analyze_step_handle_prefix(cpu, analysis)
|
|
83
|
+
}
|
|
84
|
+
pub fn instr_67_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
85
|
+
cpu.prefixes |= PREFIX_67;
|
|
86
|
+
analyze_step_handle_prefix(cpu, analysis)
|
|
87
|
+
}
|
|
88
|
+
pub fn instr_F0_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
89
|
+
// lock: Ignored
|
|
90
|
+
analyze_step_handle_prefix(cpu, analysis)
|
|
91
|
+
}
|
|
92
|
+
pub fn instr_F2_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
93
|
+
cpu.prefixes |= PREFIX_F2;
|
|
94
|
+
analyze_step_handle_prefix(cpu, analysis)
|
|
95
|
+
}
|
|
96
|
+
pub fn instr_F3_analyze(cpu: &mut CpuContext, analysis: &mut Analysis) {
|
|
97
|
+
cpu.prefixes |= PREFIX_F3;
|
|
98
|
+
analyze_step_handle_prefix(cpu, analysis)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
pub fn modrm_analyze(ctx: &mut CpuContext, modrm_byte: u8) { modrm::skip(ctx, modrm_byte); }
|