virtual-machine 0.0.3 → 0.0.10
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/build/{chunk-GZ343GYI.mjs → chunk-MELUIZWO.mjs} +6 -104
- package/build/cli.js +591 -709
- package/build/index.d.ts +2 -11
- package/build/index.js +9 -107
- package/build/index.mjs +4 -4
- package/build/{riscv_vm-3CIEJ5K7.mjs → riscv_vm-JTPPWIT3.mjs} +1 -1
- package/package.json +12 -5
- package/.yarn/install-state.gz +0 -0
- package/.yarnrc.yml +0 -1
- package/Cargo.toml +0 -49
- package/build/chunk-LJUNPJTY.mjs +0 -670
- package/build/chunk-Q7TFYQ5G.mjs +0 -670
- package/build/riscv_vm-MHIWEZQY.mjs +0 -12
- package/build/riscv_vm-VNML57ES.mjs +0 -12
- package/build.sh +0 -25
- package/cli.ts +0 -268
- package/index.ts +0 -16
- package/src/bus.rs +0 -558
- package/src/clint.rs +0 -132
- package/src/console.rs +0 -83
- package/src/cpu.rs +0 -1913
- package/src/csr.rs +0 -67
- package/src/decoder.rs +0 -789
- package/src/dram.rs +0 -146
- package/src/emulator.rs +0 -603
- package/src/lib.rs +0 -270
- package/src/main.rs +0 -373
- package/src/mmu.rs +0 -331
- package/src/net.rs +0 -121
- package/src/net_tap.rs +0 -164
- package/src/net_webtransport.rs +0 -446
- package/src/net_ws.rs +0 -396
- package/src/plic.rs +0 -261
- package/src/uart.rs +0 -233
- package/src/virtio.rs +0 -1074
- package/tsconfig.json +0 -19
- package/tsup/index.ts +0 -79
- package/tsup/tsup.cli.ts +0 -8
- package/tsup/tsup.core.cjs.ts +0 -7
- package/tsup/tsup.core.esm.ts +0 -8
package/src/uart.rs
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
use crate::dram::MemoryError;
|
|
2
|
-
use std::collections::VecDeque;
|
|
3
|
-
|
|
4
|
-
pub const UART_BASE: u64 = 0x1000_0000;
|
|
5
|
-
pub const UART_SIZE: u64 = 0x100;
|
|
6
|
-
|
|
7
|
-
// Registers (offset)
|
|
8
|
-
const RBR: u64 = 0x00; // Receiver Buffer (Read)
|
|
9
|
-
const THR: u64 = 0x00; // Transmitter Holding (Write)
|
|
10
|
-
const DLL: u64 = 0x00; // Divisor Latch LSB (Read/Write if DLAB=1)
|
|
11
|
-
const IER: u64 = 0x01; // Interrupt Enable
|
|
12
|
-
const DLM: u64 = 0x01; // Divisor Latch MSB (Read/Write if DLAB=1)
|
|
13
|
-
const IIR: u64 = 0x02; // Interrupt Identity (Read)
|
|
14
|
-
const FCR: u64 = 0x02; // FIFO Control (Write)
|
|
15
|
-
const LCR: u64 = 0x03; // Line Control
|
|
16
|
-
const MCR: u64 = 0x04; // Modem Control
|
|
17
|
-
const LSR: u64 = 0x05; // Line Status
|
|
18
|
-
const MSR: u64 = 0x06; // Modem Status
|
|
19
|
-
const SCR: u64 = 0x07; // Scratch
|
|
20
|
-
|
|
21
|
-
pub struct Uart {
|
|
22
|
-
pub input: VecDeque<u8>,
|
|
23
|
-
pub output: VecDeque<u8>,
|
|
24
|
-
|
|
25
|
-
// Registers
|
|
26
|
-
pub ier: u8,
|
|
27
|
-
pub iir: u8,
|
|
28
|
-
pub fcr: u8,
|
|
29
|
-
pub lcr: u8,
|
|
30
|
-
pub mcr: u8,
|
|
31
|
-
pub lsr: u8,
|
|
32
|
-
pub msr: u8,
|
|
33
|
-
pub scr: u8,
|
|
34
|
-
|
|
35
|
-
// Divisor
|
|
36
|
-
pub dll: u8,
|
|
37
|
-
pub dlm: u8,
|
|
38
|
-
|
|
39
|
-
pub interrupting: bool,
|
|
40
|
-
|
|
41
|
-
/// Internal state to track if THRE interrupt is pending (waiting for IIR read or THR write).
|
|
42
|
-
/// This separates the "condition" (THR empty) from the "event" (Interrupt Pending).
|
|
43
|
-
thre_ip: bool,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
impl Uart {
|
|
47
|
-
pub fn new() -> Self {
|
|
48
|
-
Self {
|
|
49
|
-
input: VecDeque::new(),
|
|
50
|
-
output: VecDeque::new(),
|
|
51
|
-
|
|
52
|
-
ier: 0x00,
|
|
53
|
-
iir: 0x01, // Default: no interrupt pending
|
|
54
|
-
fcr: 0x00,
|
|
55
|
-
lcr: 0x00,
|
|
56
|
-
mcr: 0x00,
|
|
57
|
-
lsr: 0x60, // Transmitter Empty (bit 5) | Transmitter Holding Register Empty (bit 6)
|
|
58
|
-
msr: 0x00,
|
|
59
|
-
scr: 0x00,
|
|
60
|
-
|
|
61
|
-
dll: 0x00,
|
|
62
|
-
dlm: 0x00,
|
|
63
|
-
|
|
64
|
-
interrupting: false,
|
|
65
|
-
thre_ip: true, // Starts empty, so initial state could be pending if enabled
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
pub fn update_interrupts(&mut self) {
|
|
70
|
-
self.interrupting = false;
|
|
71
|
-
self.iir = 0x01; // Default: no interrupt pending
|
|
72
|
-
|
|
73
|
-
// Priority 1: Receiver Line Status (not implemented extensively)
|
|
74
|
-
|
|
75
|
-
// Priority 2: Received Data Available
|
|
76
|
-
if (self.lsr & 0x01) != 0 && (self.ier & 0x01) != 0 {
|
|
77
|
-
self.interrupting = true;
|
|
78
|
-
self.iir = 0x04; // Recieved Data Available
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Priority 3: Transmitter Holding Register Empty
|
|
83
|
-
// Triggered if THR is empty AND IER bit 1 is set AND we haven't acknowledged it yet.
|
|
84
|
-
if self.thre_ip && (self.ier & 0x02) != 0 {
|
|
85
|
-
self.interrupting = true;
|
|
86
|
-
self.iir = 0x02; // THRE
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Priority 4: Modem Status (not implemented)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
pub fn load(&mut self, offset: u64, size: u64) -> Result<u64, MemoryError> {
|
|
94
|
-
if size != 1 {
|
|
95
|
-
// Some OS might try 4-byte reads, technically not allowed by spec but we can be lenient or strict.
|
|
96
|
-
// Spec says 8-bit width. Let's return 0 for now if not byte access.
|
|
97
|
-
return Ok(0);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
let val = match offset {
|
|
101
|
-
RBR => {
|
|
102
|
-
if (self.lcr & 0x80) != 0 {
|
|
103
|
-
self.dll
|
|
104
|
-
} else {
|
|
105
|
-
// RBR: Read from input FIFO
|
|
106
|
-
let byte = self.input.pop_front().unwrap_or(0);
|
|
107
|
-
// Update LSR: if more data, set bit 0, else clear it
|
|
108
|
-
if self.input.is_empty() {
|
|
109
|
-
self.lsr &= !0x01;
|
|
110
|
-
} else {
|
|
111
|
-
self.lsr |= 0x01;
|
|
112
|
-
}
|
|
113
|
-
self.update_interrupts();
|
|
114
|
-
byte
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
IER => {
|
|
118
|
-
if (self.lcr & 0x80) != 0 {
|
|
119
|
-
self.dlm
|
|
120
|
-
} else {
|
|
121
|
-
self.ier
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
IIR => {
|
|
125
|
-
let val = self.iir;
|
|
126
|
-
// Reading IIR clears THRE interrupt if it is the indicated interrupt
|
|
127
|
-
if (val & 0x0F) == 0x02 {
|
|
128
|
-
self.thre_ip = false;
|
|
129
|
-
self.update_interrupts();
|
|
130
|
-
log::trace!("[UART] IIR read cleared THRE ip");
|
|
131
|
-
} else {
|
|
132
|
-
log::trace!("[UART] IIR read val={:x} (thre_ip={})", val, self.thre_ip);
|
|
133
|
-
}
|
|
134
|
-
val
|
|
135
|
-
}
|
|
136
|
-
LCR => self.lcr,
|
|
137
|
-
MCR => self.mcr,
|
|
138
|
-
LSR => self.lsr,
|
|
139
|
-
MSR => self.msr,
|
|
140
|
-
SCR => self.scr,
|
|
141
|
-
_ => 0,
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
Ok(val as u64)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
pub fn store(&mut self, offset: u64, size: u64, value: u64) -> Result<(), MemoryError> {
|
|
148
|
-
if size != 1 {
|
|
149
|
-
return Ok(());
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
let val = (value & 0xff) as u8;
|
|
153
|
-
|
|
154
|
-
match offset {
|
|
155
|
-
THR => {
|
|
156
|
-
if (self.lcr & 0x80) != 0 {
|
|
157
|
-
self.dll = val;
|
|
158
|
-
} else {
|
|
159
|
-
// THR: Write to output
|
|
160
|
-
log::trace!(
|
|
161
|
-
"[UART] TX '{}' (0x{:02x})",
|
|
162
|
-
if val.is_ascii_graphic() {
|
|
163
|
-
val as char
|
|
164
|
-
} else {
|
|
165
|
-
'.'
|
|
166
|
-
},
|
|
167
|
-
val
|
|
168
|
-
);
|
|
169
|
-
self.output.push_back(val);
|
|
170
|
-
// We instantly "transmit", so THRE (bit 5) is always set.
|
|
171
|
-
// Writing to THR clears the THRE interrupt (if pending),
|
|
172
|
-
// but since it becomes empty immediately, we set thre_ip to true again?
|
|
173
|
-
// In real HW, it goes Not Empty -> Empty.
|
|
174
|
-
// So we should clear it, then re-assert it.
|
|
175
|
-
// For edge-triggered emulation, simply re-asserting is correct because we transitioned.
|
|
176
|
-
self.lsr |= 0x20;
|
|
177
|
-
self.thre_ip = true;
|
|
178
|
-
self.update_interrupts();
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
IER => {
|
|
182
|
-
if (self.lcr & 0x80) != 0 {
|
|
183
|
-
self.dlm = val;
|
|
184
|
-
} else {
|
|
185
|
-
self.ier = val;
|
|
186
|
-
self.update_interrupts();
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
FCR => {
|
|
190
|
-
self.fcr = val;
|
|
191
|
-
if (self.fcr & 0x02) != 0 {
|
|
192
|
-
self.input.clear();
|
|
193
|
-
self.lsr &= !0x01;
|
|
194
|
-
}
|
|
195
|
-
if (self.fcr & 0x04) != 0 {
|
|
196
|
-
self.output.clear();
|
|
197
|
-
self.lsr |= 0x60; // Empty
|
|
198
|
-
}
|
|
199
|
-
self.update_interrupts();
|
|
200
|
-
}
|
|
201
|
-
LCR => {
|
|
202
|
-
self.lcr = val;
|
|
203
|
-
}
|
|
204
|
-
MCR => {
|
|
205
|
-
self.mcr = val;
|
|
206
|
-
}
|
|
207
|
-
LSR => {
|
|
208
|
-
// Usually read-only, but factory test mode might write. Ignore.
|
|
209
|
-
}
|
|
210
|
-
MSR => {
|
|
211
|
-
// Read-only.
|
|
212
|
-
}
|
|
213
|
-
SCR => {
|
|
214
|
-
self.scr = val;
|
|
215
|
-
}
|
|
216
|
-
_ => {}
|
|
217
|
-
}
|
|
218
|
-
Ok(())
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Interface for the Host
|
|
222
|
-
pub fn push_input(&mut self, byte: u8) {
|
|
223
|
-
self.input.push_back(byte);
|
|
224
|
-
self.lsr |= 0x01; // Data Ready
|
|
225
|
-
self.update_interrupts();
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
pub fn pop_output(&mut self) -> Option<u8> {
|
|
229
|
-
self.output.pop_front()
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
|