virtual-machine 0.0.0-rc1

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/src/uart.rs ADDED
@@ -0,0 +1,233 @@
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
+