@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
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
use crate::cpu::cpu::*;
|
|
2
|
+
use crate::paging::OrPageFault;
|
|
3
|
+
|
|
4
|
+
pub unsafe fn resolve_modrm16(modrm_byte: i32) -> OrPageFault<i32> {
|
|
5
|
+
match modrm_byte & !0o070 {
|
|
6
|
+
0o000 => get_seg_prefix_ds(read_reg16(BX) + read_reg16(SI) & 0xFFFF),
|
|
7
|
+
0o100 => get_seg_prefix_ds(read_reg16(BX) + read_reg16(SI) + read_imm8s()? & 0xFFFF),
|
|
8
|
+
0o200 => get_seg_prefix_ds(read_reg16(BX) + read_reg16(SI) + read_imm16()? & 0xFFFF),
|
|
9
|
+
0o001 => get_seg_prefix_ds(read_reg16(BX) + read_reg16(DI) & 0xFFFF),
|
|
10
|
+
0o101 => get_seg_prefix_ds(read_reg16(BX) + read_reg16(DI) + read_imm8s()? & 0xFFFF),
|
|
11
|
+
0o201 => get_seg_prefix_ds(read_reg16(BX) + read_reg16(DI) + read_imm16()? & 0xFFFF),
|
|
12
|
+
0o002 => get_seg_prefix_ss(read_reg16(BP) + read_reg16(SI) & 0xFFFF),
|
|
13
|
+
0o102 => get_seg_prefix_ss(read_reg16(BP) + read_reg16(SI) + read_imm8s()? & 0xFFFF),
|
|
14
|
+
0o202 => get_seg_prefix_ss(read_reg16(BP) + read_reg16(SI) + read_imm16()? & 0xFFFF),
|
|
15
|
+
0o003 => get_seg_prefix_ss(read_reg16(BP) + read_reg16(DI) & 0xFFFF),
|
|
16
|
+
0o103 => get_seg_prefix_ss(read_reg16(BP) + read_reg16(DI) + read_imm8s()? & 0xFFFF),
|
|
17
|
+
0o203 => get_seg_prefix_ss(read_reg16(BP) + read_reg16(DI) + read_imm16()? & 0xFFFF),
|
|
18
|
+
0o004 => get_seg_prefix_ds(read_reg16(SI) & 0xFFFF),
|
|
19
|
+
0o104 => get_seg_prefix_ds(read_reg16(SI) + read_imm8s()? & 0xFFFF),
|
|
20
|
+
0o204 => get_seg_prefix_ds(read_reg16(SI) + read_imm16()? & 0xFFFF),
|
|
21
|
+
0o005 => get_seg_prefix_ds(read_reg16(DI) & 0xFFFF),
|
|
22
|
+
0o105 => get_seg_prefix_ds(read_reg16(DI) + read_imm8s()? & 0xFFFF),
|
|
23
|
+
0o205 => get_seg_prefix_ds(read_reg16(DI) + read_imm16()? & 0xFFFF),
|
|
24
|
+
0o006 => get_seg_prefix_ds(read_imm16()?),
|
|
25
|
+
0o106 => get_seg_prefix_ss(read_reg16(BP) + read_imm8s()? & 0xFFFF),
|
|
26
|
+
0o206 => get_seg_prefix_ss(read_reg16(BP) + read_imm16()? & 0xFFFF),
|
|
27
|
+
0o007 => get_seg_prefix_ds(read_reg16(BX) & 0xFFFF),
|
|
28
|
+
0o107 => get_seg_prefix_ds(read_reg16(BX) + read_imm8s()? & 0xFFFF),
|
|
29
|
+
0o207 => get_seg_prefix_ds(read_reg16(BX) + read_imm16()? & 0xFFFF),
|
|
30
|
+
_ => {
|
|
31
|
+
dbg_assert!(false);
|
|
32
|
+
std::hint::unreachable_unchecked()
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
pub unsafe fn resolve_modrm32_(modrm_byte: i32) -> OrPageFault<i32> {
|
|
38
|
+
let r = (modrm_byte & 7) as u8;
|
|
39
|
+
dbg_assert!(modrm_byte < 192);
|
|
40
|
+
Ok(if r as i32 == 4 {
|
|
41
|
+
if modrm_byte < 64 {
|
|
42
|
+
resolve_sib(false)?
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
resolve_sib(true)? + if modrm_byte < 128 { read_imm8s()? } else { read_imm32s()? }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else if r as i32 == 5 {
|
|
49
|
+
if modrm_byte < 64 {
|
|
50
|
+
get_seg_prefix_ds(read_imm32s()?)?
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
get_seg_prefix_ss(
|
|
54
|
+
read_reg32(EBP) + if modrm_byte < 128 { read_imm8s()? } else { read_imm32s()? },
|
|
55
|
+
)?
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else if modrm_byte < 64 {
|
|
59
|
+
get_seg_prefix_ds(read_reg32(r as i32))?
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
get_seg_prefix_ds(
|
|
63
|
+
read_reg32(r as i32) + if modrm_byte < 128 { read_imm8s()? } else { read_imm32s()? },
|
|
64
|
+
)?
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
unsafe fn resolve_sib(with_imm: bool) -> OrPageFault<i32> {
|
|
68
|
+
let sib_byte = read_imm8()?;
|
|
69
|
+
let r = sib_byte & 7;
|
|
70
|
+
let m = sib_byte >> 3 & 7;
|
|
71
|
+
let base;
|
|
72
|
+
let seg;
|
|
73
|
+
if r == 4 {
|
|
74
|
+
base = read_reg32(ESP);
|
|
75
|
+
seg = SS
|
|
76
|
+
}
|
|
77
|
+
else if r == 5 {
|
|
78
|
+
if with_imm {
|
|
79
|
+
base = read_reg32(EBP);
|
|
80
|
+
seg = SS
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
base = read_imm32s()?;
|
|
84
|
+
seg = DS
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
base = read_reg32(r);
|
|
89
|
+
seg = DS
|
|
90
|
+
}
|
|
91
|
+
let offset;
|
|
92
|
+
if m == 4 {
|
|
93
|
+
offset = 0
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
let s = sib_byte >> 6 & 3;
|
|
97
|
+
offset = read_reg32(m) << s
|
|
98
|
+
}
|
|
99
|
+
Ok(get_seg_prefix(seg)? + base + offset)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
pub unsafe fn resolve_modrm32(modrm_byte: i32) -> OrPageFault<i32> {
|
|
103
|
+
match modrm_byte & !0o070 {
|
|
104
|
+
0o000 => get_seg_prefix_ds(read_reg32(EAX)),
|
|
105
|
+
0o100 => get_seg_prefix_ds(read_reg32(EAX) + read_imm8s()?),
|
|
106
|
+
0o200 => get_seg_prefix_ds(read_reg32(EAX) + read_imm32s()?),
|
|
107
|
+
0o001 => get_seg_prefix_ds(read_reg32(ECX)),
|
|
108
|
+
0o101 => get_seg_prefix_ds(read_reg32(ECX) + read_imm8s()?),
|
|
109
|
+
0o201 => get_seg_prefix_ds(read_reg32(ECX) + read_imm32s()?),
|
|
110
|
+
0o002 => get_seg_prefix_ds(read_reg32(EDX)),
|
|
111
|
+
0o102 => get_seg_prefix_ds(read_reg32(EDX) + read_imm8s()?),
|
|
112
|
+
0o202 => get_seg_prefix_ds(read_reg32(EDX) + read_imm32s()?),
|
|
113
|
+
0o003 => get_seg_prefix_ds(read_reg32(EBX)),
|
|
114
|
+
0o103 => get_seg_prefix_ds(read_reg32(EBX) + read_imm8s()?),
|
|
115
|
+
0o203 => get_seg_prefix_ds(read_reg32(EBX) + read_imm32s()?),
|
|
116
|
+
0o004 => resolve_sib(false),
|
|
117
|
+
0o104 => Ok(resolve_sib(true)? + read_imm8s()?),
|
|
118
|
+
0o204 => Ok(resolve_sib(true)? + read_imm32s()?),
|
|
119
|
+
0o005 => get_seg_prefix_ds(read_imm32s()?),
|
|
120
|
+
0o105 => get_seg_prefix_ss(read_reg32(EBP) + read_imm8s()?),
|
|
121
|
+
0o205 => get_seg_prefix_ss(read_reg32(EBP) + read_imm32s()?),
|
|
122
|
+
0o006 => get_seg_prefix_ds(read_reg32(ESI)),
|
|
123
|
+
0o106 => get_seg_prefix_ds(read_reg32(ESI) + read_imm8s()?),
|
|
124
|
+
0o206 => get_seg_prefix_ds(read_reg32(ESI) + read_imm32s()?),
|
|
125
|
+
0o007 => get_seg_prefix_ds(read_reg32(EDI)),
|
|
126
|
+
0o107 => get_seg_prefix_ds(read_reg32(EDI) + read_imm8s()?),
|
|
127
|
+
0o207 => get_seg_prefix_ds(read_reg32(EDI) + read_imm32s()?),
|
|
128
|
+
_ => {
|
|
129
|
+
dbg_assert!(false);
|
|
130
|
+
std::hint::unreachable_unchecked()
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
#![allow(non_snake_case)]
|
|
2
|
+
|
|
3
|
+
// Programmable Interrupt Controller
|
|
4
|
+
// http://stanislavs.org/helppc/8259.html
|
|
5
|
+
|
|
6
|
+
use std::sync::{Mutex, MutexGuard};
|
|
7
|
+
|
|
8
|
+
pub const PIC_LOG: bool = false;
|
|
9
|
+
pub const PIC_LOG_VERBOSE: bool = false;
|
|
10
|
+
|
|
11
|
+
// Note: This layout is deliberately chosen to match the old JavaScript pic state
|
|
12
|
+
// (cpu.get_state_pic depens on this layout)
|
|
13
|
+
const _: () = assert!(std::mem::offset_of!(Pic0, special_mask_mode) == 12);
|
|
14
|
+
#[repr(C)]
|
|
15
|
+
struct Pic0 {
|
|
16
|
+
irq_mask: u8,
|
|
17
|
+
|
|
18
|
+
irq_map: u8,
|
|
19
|
+
|
|
20
|
+
// in-service register
|
|
21
|
+
// Holds interrupts that are currently being serviced
|
|
22
|
+
isr: u8,
|
|
23
|
+
|
|
24
|
+
// interrupt request register
|
|
25
|
+
// Holds interrupts that have been requested
|
|
26
|
+
irr: u8,
|
|
27
|
+
|
|
28
|
+
master: bool,
|
|
29
|
+
dummy: u8, // remove when state image is updated
|
|
30
|
+
|
|
31
|
+
expect_icw4: bool,
|
|
32
|
+
state: u8,
|
|
33
|
+
read_isr: bool,
|
|
34
|
+
auto_eoi: bool,
|
|
35
|
+
|
|
36
|
+
elcr: u8,
|
|
37
|
+
|
|
38
|
+
irq_value: u8,
|
|
39
|
+
special_mask_mode: bool,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
struct Pic {
|
|
43
|
+
master: Pic0,
|
|
44
|
+
slave: Pic0,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static PIC: Mutex<Pic> = Mutex::new(Pic {
|
|
48
|
+
master: Pic0 {
|
|
49
|
+
// all irqs off
|
|
50
|
+
irq_mask: 0,
|
|
51
|
+
// Bogus default value (both master and slave mapped to 0).
|
|
52
|
+
// Will be initialized by the BIOS
|
|
53
|
+
irq_map: 0,
|
|
54
|
+
// in-service register
|
|
55
|
+
// Holds interrupts that are currently being serviced
|
|
56
|
+
isr: 0,
|
|
57
|
+
// interrupt request register
|
|
58
|
+
// Holds interrupts that have been requested
|
|
59
|
+
irr: 0,
|
|
60
|
+
irq_value: 0,
|
|
61
|
+
expect_icw4: false,
|
|
62
|
+
state: 0,
|
|
63
|
+
read_isr: false,
|
|
64
|
+
auto_eoi: false,
|
|
65
|
+
special_mask_mode: false,
|
|
66
|
+
elcr: 0,
|
|
67
|
+
master: true,
|
|
68
|
+
dummy: 0,
|
|
69
|
+
},
|
|
70
|
+
slave: Pic0 {
|
|
71
|
+
// all irqs off
|
|
72
|
+
irq_mask: 0,
|
|
73
|
+
// Bogus default value (both master and slave mapped to 0).
|
|
74
|
+
// Will be initialized by the BIOS
|
|
75
|
+
irq_map: 0,
|
|
76
|
+
// in-service register
|
|
77
|
+
// Holds interrupts that are currently being serviced
|
|
78
|
+
isr: 0,
|
|
79
|
+
// interrupt request register
|
|
80
|
+
// Holds interrupts that have been requested
|
|
81
|
+
irr: 0,
|
|
82
|
+
irq_value: 0,
|
|
83
|
+
expect_icw4: false,
|
|
84
|
+
state: 0,
|
|
85
|
+
read_isr: false,
|
|
86
|
+
auto_eoi: false,
|
|
87
|
+
special_mask_mode: false,
|
|
88
|
+
elcr: 0,
|
|
89
|
+
master: false,
|
|
90
|
+
dummy: 0,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
fn get_pic() -> MutexGuard<'static, Pic> { PIC.try_lock().unwrap() }
|
|
95
|
+
|
|
96
|
+
// called from javascript for saving/restoring state
|
|
97
|
+
#[no_mangle]
|
|
98
|
+
pub fn get_pic_addr_master() -> u32 { &raw mut get_pic().master as u32 }
|
|
99
|
+
#[no_mangle]
|
|
100
|
+
pub fn get_pic_addr_slave() -> u32 { &raw mut get_pic().slave as u32 }
|
|
101
|
+
|
|
102
|
+
impl Pic0 {
|
|
103
|
+
fn get_irq(&mut self) -> Option<u8> {
|
|
104
|
+
let enabled_irr = self.irr & self.irq_mask;
|
|
105
|
+
|
|
106
|
+
if enabled_irr == 0 {
|
|
107
|
+
if PIC_LOG_VERBOSE {
|
|
108
|
+
dbg_log!(
|
|
109
|
+
"[PIC] no unmasked irrs. irr={:x} mask={:x} isr={:x}",
|
|
110
|
+
self.irr,
|
|
111
|
+
self.irq_mask,
|
|
112
|
+
self.isr
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
return None;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let irq_mask = enabled_irr & (!enabled_irr + 1);
|
|
119
|
+
let special_mask = if self.special_mask_mode { self.irq_mask } else { 0xFF };
|
|
120
|
+
|
|
121
|
+
if self.isr != 0 && (self.isr & (!self.isr + 1) & special_mask) <= irq_mask {
|
|
122
|
+
// wait for eoi of higher or same priority interrupt
|
|
123
|
+
if PIC_LOG {
|
|
124
|
+
dbg_log!(
|
|
125
|
+
"[PIC] higher prio: master={} isr={:x} mask={:x} irq={:x}",
|
|
126
|
+
self.master,
|
|
127
|
+
self.isr,
|
|
128
|
+
self.irq_mask,
|
|
129
|
+
irq_mask
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
return None;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
dbg_assert!(irq_mask != 0);
|
|
136
|
+
let irq_number = irq_mask.ilog2() as u8;
|
|
137
|
+
dbg_assert!(irq_mask == 1 << irq_number);
|
|
138
|
+
|
|
139
|
+
if PIC_LOG_VERBOSE {
|
|
140
|
+
dbg_log!("[PIC] request irq {}", irq_number);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
Some(irq_number)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
fn port0_read(self: &Pic0) -> u32 { (if self.read_isr { self.isr } else { self.irr }) as u32 }
|
|
147
|
+
fn port1_read(self: &Pic0) -> u32 { !self.irq_mask as u32 }
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
impl Pic {
|
|
151
|
+
fn set_irq(self: &mut Pic, i: u8) {
|
|
152
|
+
let mask = 1 << (i & 7);
|
|
153
|
+
let dev = if i < 8 { &mut self.master } else { &mut self.slave };
|
|
154
|
+
if dev.irq_value & mask == 0 || dev.elcr & mask != 0 {
|
|
155
|
+
dev.irr |= mask;
|
|
156
|
+
dev.irq_value |= mask;
|
|
157
|
+
if i >= 8 {
|
|
158
|
+
self.check_irqs_slave()
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
fn clear_irq(self: &mut Pic, i: u8) {
|
|
164
|
+
let mask = 1 << (i & 7);
|
|
165
|
+
let dev = if i < 8 { &mut self.master } else { &mut self.slave };
|
|
166
|
+
dev.irq_value &= !mask;
|
|
167
|
+
if dev.elcr & mask != 0 {
|
|
168
|
+
dev.irr &= !mask;
|
|
169
|
+
if i >= 8 {
|
|
170
|
+
self.check_irqs_slave()
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
fn port0_write(&mut self, index: u8, v: u8) {
|
|
176
|
+
let dev = if index == 0 { &mut self.master } else { &mut self.slave };
|
|
177
|
+
if v & 0x10 != 0 {
|
|
178
|
+
// xxxx1xxx
|
|
179
|
+
// icw1
|
|
180
|
+
dbg_log!("icw1 = {:x}", v);
|
|
181
|
+
dev.isr = 0;
|
|
182
|
+
dev.irr = 0;
|
|
183
|
+
dev.irq_mask = 0xff;
|
|
184
|
+
dev.irq_value = 0;
|
|
185
|
+
dev.auto_eoi = true;
|
|
186
|
+
|
|
187
|
+
dev.expect_icw4 = v & 1 != 0;
|
|
188
|
+
dbg_assert!(v & 2 == 0, "unimplemented: single mode");
|
|
189
|
+
dbg_assert!(v & 8 == 0, "unimplemented: level mode");
|
|
190
|
+
dev.state = 1;
|
|
191
|
+
}
|
|
192
|
+
else if v & 8 != 0 {
|
|
193
|
+
// xxx01xxx
|
|
194
|
+
// ocw3
|
|
195
|
+
dbg_log!("ocw3: {:x}", v);
|
|
196
|
+
if v & 2 != 0 {
|
|
197
|
+
dev.read_isr = v & 1 != 0;
|
|
198
|
+
}
|
|
199
|
+
if v & 4 != 0 {
|
|
200
|
+
dbg_assert!(false, "unimplemented: polling");
|
|
201
|
+
}
|
|
202
|
+
if v & 0x40 != 0 {
|
|
203
|
+
dev.special_mask_mode = (v & 0x20) == 0x20;
|
|
204
|
+
dbg_log!("special mask mode: {}", dev.special_mask_mode);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
// xxx00xxx
|
|
209
|
+
// ocw2
|
|
210
|
+
// end of interrupt
|
|
211
|
+
if PIC_LOG {
|
|
212
|
+
dbg_log!("eoi: {:x}", v);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
let eoi_type = v >> 5;
|
|
216
|
+
|
|
217
|
+
if eoi_type == 1 {
|
|
218
|
+
// non-specific eoi
|
|
219
|
+
dev.isr &= dev.isr - 1;
|
|
220
|
+
if PIC_LOG {
|
|
221
|
+
dbg_log!("new isr: {:x}", dev.isr);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else if eoi_type == 3 {
|
|
225
|
+
// specific eoi
|
|
226
|
+
dev.isr &= !(1 << (v & 7));
|
|
227
|
+
}
|
|
228
|
+
else if eoi_type == 6 {
|
|
229
|
+
// os2 v4, freebsd
|
|
230
|
+
let priority = v & 7;
|
|
231
|
+
dbg_log!("lowest priority: {:x}", priority);
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
dbg_log!("Unknown eoi: {:x} type={:x}", v, eoi_type);
|
|
235
|
+
dbg_assert!(false);
|
|
236
|
+
dev.isr &= dev.isr - 1;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if index == 1 {
|
|
240
|
+
self.check_irqs_slave()
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
fn port1_write(&mut self, index: u8, v: u8) {
|
|
246
|
+
let dev = if index == 0 { &mut self.master } else { &mut self.slave };
|
|
247
|
+
if dev.state == 0 {
|
|
248
|
+
if dev.expect_icw4 {
|
|
249
|
+
// icw4
|
|
250
|
+
dev.expect_icw4 = false;
|
|
251
|
+
dev.auto_eoi = v & 2 != 0;
|
|
252
|
+
dbg_log!("icw4: {:x} autoeoi={}", v, dev.auto_eoi);
|
|
253
|
+
dbg_assert!(v & 0x10 == 0, "unimplemented: nested mode");
|
|
254
|
+
dbg_assert!(v & 1 == 1, "unimplemented: 8086/88 mode");
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
// ocw1
|
|
258
|
+
dev.irq_mask = !v;
|
|
259
|
+
|
|
260
|
+
if PIC_LOG_VERBOSE {
|
|
261
|
+
dbg_log!("interrupt mask: {:x}", dev.irq_mask);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if index == 1 {
|
|
265
|
+
self.check_irqs_slave()
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else if dev.state == 1 {
|
|
270
|
+
// icw2
|
|
271
|
+
dev.irq_map = v;
|
|
272
|
+
dbg_log!("interrupts are mapped to {:x}", dev.irq_map);
|
|
273
|
+
dev.state += 1;
|
|
274
|
+
}
|
|
275
|
+
else if dev.state == 2 {
|
|
276
|
+
// icw3
|
|
277
|
+
dev.state = 0;
|
|
278
|
+
dbg_log!("icw3: {:x}", v);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
fn check_irqs_slave(&mut self) {
|
|
283
|
+
let is_set = self.slave.get_irq().is_some();
|
|
284
|
+
if is_set {
|
|
285
|
+
self.set_irq(2)
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
self.clear_irq(2)
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// called by the cpu
|
|
294
|
+
pub fn pic_acknowledge_irq() -> Option<u8> {
|
|
295
|
+
let mut pic = get_pic();
|
|
296
|
+
let irq = match pic.master.get_irq() {
|
|
297
|
+
Some(i) => i,
|
|
298
|
+
None => return None,
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
if pic.master.irr == 0 {
|
|
302
|
+
dbg_assert!(false);
|
|
303
|
+
//PIC_LOG_VERBOSE && dbg_log!("master> spurious requested=" + irq);
|
|
304
|
+
//Some(pic.irq_map | 7)
|
|
305
|
+
return None;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
let mask = 1 << irq;
|
|
309
|
+
|
|
310
|
+
if pic.master.elcr & mask == 0 {
|
|
311
|
+
// not in level mode
|
|
312
|
+
pic.master.irr &= !mask;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if !pic.master.auto_eoi {
|
|
316
|
+
pic.master.isr |= mask;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if PIC_LOG_VERBOSE {
|
|
320
|
+
dbg_log!("[PIC] master> acknowledge {}", irq);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
dbg_assert!(pic.master.get_irq().is_none());
|
|
324
|
+
|
|
325
|
+
if irq == 2 {
|
|
326
|
+
acknowledge_irq_slave(&mut pic)
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
Some(pic.master.irq_map | irq)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
fn acknowledge_irq_slave(pic: &mut Pic) -> Option<u8> {
|
|
334
|
+
let irq = match pic.slave.get_irq() {
|
|
335
|
+
Some(i) => i,
|
|
336
|
+
None => return None,
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
if pic.slave.irr == 0 {
|
|
340
|
+
//PIC_LOG_VERBOSE && dbg_log!("slave> spurious requested=" + irq);
|
|
341
|
+
//Some(pic.irq_map | 7)
|
|
342
|
+
dbg_assert!(false);
|
|
343
|
+
return None;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
let mask = 1 << irq;
|
|
347
|
+
|
|
348
|
+
if pic.slave.elcr & mask == 0 {
|
|
349
|
+
// not in level mode
|
|
350
|
+
pic.slave.irr &= !mask;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if !pic.slave.auto_eoi {
|
|
354
|
+
pic.slave.isr |= mask;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if PIC_LOG_VERBOSE {
|
|
358
|
+
dbg_log!("[PIC] slave> acknowledge {}", irq);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
dbg_assert!(pic.slave.get_irq().is_none());
|
|
362
|
+
pic.clear_irq(2);
|
|
363
|
+
|
|
364
|
+
Some(pic.slave.irq_map | irq)
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
pub fn set_irq(i: u8) {
|
|
368
|
+
dbg_assert!(i < 16);
|
|
369
|
+
|
|
370
|
+
if PIC_LOG_VERBOSE {
|
|
371
|
+
dbg_log!("[PIC] set irq {}", i);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
get_pic().set_irq(i)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
pub fn clear_irq(i: u8) {
|
|
378
|
+
dbg_assert!(i < 16);
|
|
379
|
+
|
|
380
|
+
if PIC_LOG_VERBOSE {
|
|
381
|
+
dbg_log!("[PIC] clear irq {}", i);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
get_pic().clear_irq(i)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
pub fn port20_read() -> u32 { get_pic().master.port0_read() }
|
|
388
|
+
pub fn port21_read() -> u32 { get_pic().master.port1_read() }
|
|
389
|
+
|
|
390
|
+
pub fn portA0_read() -> u32 { get_pic().slave.port0_read() }
|
|
391
|
+
pub fn portA1_read() -> u32 { get_pic().slave.port1_read() }
|
|
392
|
+
|
|
393
|
+
pub fn port20_write(v: u8) { get_pic().port0_write(0, v) }
|
|
394
|
+
pub fn port21_write(v: u8) { get_pic().port1_write(0, v) }
|
|
395
|
+
|
|
396
|
+
pub fn portA0_write(v: u8) { get_pic().port0_write(1, v) }
|
|
397
|
+
pub fn portA1_write(v: u8) { get_pic().port1_write(1, v) }
|
|
398
|
+
|
|
399
|
+
pub fn port4D0_read() -> u32 { get_pic().master.elcr as u32 }
|
|
400
|
+
pub fn port4D1_read() -> u32 { get_pic().slave.elcr as u32 }
|
|
401
|
+
pub fn port4D0_write(v: u8) { get_pic().master.elcr = v }
|
|
402
|
+
pub fn port4D1_write(v: u8) { get_pic().slave.elcr = v }
|