@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,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 }