1use std::sync::{
2 Arc,
3 atomic::{AtomicU8, Ordering},
4};
5
6use crate::{DmaDirection, DmaRequest, Error, PortRange, Result};
7
8const MEMORY_SIZE: usize = 1 << 20;
9pub(crate) mod playback;
10pub use playback::DmaCompletion;
11
12#[derive(Clone, Debug)]
18pub struct ConventionalMemory {
19 bytes: Arc<[AtomicU8]>,
20}
21
22impl Default for ConventionalMemory {
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28impl ConventionalMemory {
29 pub fn new() -> Self {
31 Self {
32 bytes: (0..MEMORY_SIZE).map(|_| AtomicU8::new(0)).collect(),
33 }
34 }
35
36 fn range(&self, address: u32, length: usize) -> Result<core::ops::Range<usize>> {
37 let start = usize::try_from(address).map_err(|_| Error::TooLarge)?;
38 let end = start
39 .checked_add(length)
40 .filter(|&end| end <= MEMORY_SIZE)
41 .ok_or(Error::Config(
42 "conventional memory access exceeds one megabyte",
43 ))?;
44 Ok(start..end)
45 }
46
47 pub fn read_byte(&self, address: u32) -> Result<u8> {
49 let range = self.range(address, 1)?;
50 Ok(self.bytes[range.start].load(Ordering::Acquire))
51 }
52
53 pub fn write_byte(&self, address: u32, value: u8) -> Result<()> {
55 let range = self.range(address, 1)?;
56 self.bytes[range.start].store(value, Ordering::Release);
57 Ok(())
58 }
59
60 pub fn write(&self, address: u32, bytes: &[u8]) -> Result<()> {
62 let range = self.range(address, bytes.len())?;
63 for (destination, &value) in self.bytes[range].iter().zip(bytes) {
64 destination.store(value, Ordering::Release);
65 }
66 Ok(())
67 }
68
69 pub fn read(&self, address: u32, out: &mut [u8]) -> Result<()> {
71 let range = self.range(address, out.len())?;
72 for (source, destination) in self.bytes[range].iter().zip(out) {
73 *destination = source.load(Ordering::Acquire);
74 }
75 Ok(())
76 }
77}
78
79#[derive(Clone, Copy, Debug, Eq, PartialEq)]
81pub enum DmaUnit {
82 Byte(u8),
84 Word(u16),
86}
87
88#[derive(Clone, Copy, Debug)]
89struct Channel {
90 address: u16,
91 count: u16,
92 base_address: u16,
93 base_count: u16,
94 page: u8,
95 mode: u8,
96 masked: bool,
97 active: bool,
98}
99
100impl Channel {
101 const RESET: Self = Self {
102 address: 0,
103 count: 0,
104 base_address: 0,
105 base_count: 0,
106 page: 0,
107 mode: 0,
108 masked: true,
109 active: false,
110 };
111}
112
113#[derive(Clone, Copy, Debug)]
124pub struct DmaController {
125 channels: [Channel; 8],
126 high_byte: [bool; 2],
127 command: [u8; 2],
128 terminal_count: [u8; 2],
129 software_request: [u8; 2],
130}
131
132impl Default for DmaController {
133 fn default() -> Self {
134 Self::new()
135 }
136}
137
138impl DmaController {
139 pub const fn new() -> Self {
141 Self {
142 channels: [Channel::RESET; 8],
143 high_byte: [false; 2],
144 command: [0; 2],
145 terminal_count: [0; 2],
146 software_request: [0; 2],
147 }
148 }
149
150 pub fn ports(&self) -> &[PortRange] {
152 const PORTS: &[PortRange] = &[
153 PortRange::new(0x00, 0x0f),
154 PortRange::new(0x81, 0x83),
155 PortRange::single(0x87),
156 PortRange::new(0x89, 0x8b),
157 PortRange::single(0xc0),
158 PortRange::single(0xc2),
159 PortRange::single(0xc4),
160 PortRange::single(0xc6),
161 PortRange::single(0xc8),
162 PortRange::single(0xca),
163 PortRange::single(0xcc),
164 PortRange::single(0xce),
165 PortRange::single(0xd0),
166 PortRange::single(0xd2),
167 PortRange::single(0xd4),
168 PortRange::single(0xd6),
169 PortRange::single(0xd8),
170 PortRange::single(0xda),
171 PortRange::single(0xdc),
172 PortRange::single(0xde),
173 ];
174 PORTS
175 }
176
177 fn page_channel(port: u16) -> Option<usize> {
178 match port {
179 0x87 => Some(0),
180 0x83 => Some(1),
181 0x81 => Some(2),
182 0x82 => Some(3),
183 0x8b => Some(5),
184 0x89 => Some(6),
185 0x8a => Some(7),
186 _ => None,
187 }
188 }
189
190 fn register(port: u16) -> Option<(usize, usize)> {
191 match port {
192 0x00..=0x0f => Some((0, usize::from(port))),
193 0xc0..=0xde if port & 1 == 0 => Some((1, usize::from((port - 0xc0) / 2))),
194 _ => None,
195 }
196 }
197
198 fn set_half(register: &mut u16, value: u8, high: bool) {
199 *register = if high {
200 (*register & 0x00ff) | (u16::from(value) << 8)
201 } else {
202 (*register & 0xff00) | u16::from(value)
203 };
204 }
205
206 pub fn outb(&mut self, port: u16, value: u8) {
208 if let Some(channel) = Self::page_channel(port) {
209 self.channels[channel].page = value;
210 return;
211 }
212 let Some((chip, register)) = Self::register(port) else {
213 return;
214 };
215 if register < 8 {
216 let index = chip * 4 + register / 2;
217 if index != 4 {
218 let channel = &mut self.channels[index];
219 if register & 1 == 0 {
220 Self::set_half(&mut channel.address, value, self.high_byte[chip]);
221 Self::set_half(&mut channel.base_address, value, self.high_byte[chip]);
222 } else {
223 Self::set_half(&mut channel.count, value, self.high_byte[chip]);
224 Self::set_half(&mut channel.base_count, value, self.high_byte[chip]);
225 }
226 channel.active = true;
227 }
228 self.high_byte[chip] = !self.high_byte[chip];
229 return;
230 }
231 let index = chip * 4 + usize::from(value & 3);
232 match register {
233 8 => self.command[chip] = value,
234 9 => {
235 let bit = 1 << (value & 3);
236 if value & 4 == 0 {
237 self.software_request[chip] &= !bit;
238 } else {
239 self.software_request[chip] |= bit;
240 }
241 }
242 10 => self.channels[index].masked = value & 4 != 0,
243 11 => {
244 if index != 4 {
245 self.channels[index].mode = value;
246 }
247 }
248 12 => self.high_byte[chip] = false,
249 13 => {
250 self.command[chip] = 0;
251 self.terminal_count[chip] = 0;
252 self.software_request[chip] = 0;
253 self.high_byte[chip] = false;
254 for channel in &mut self.channels[chip * 4..chip * 4 + 4] {
255 channel.masked = true;
256 }
257 }
258 14 => {
259 for channel in &mut self.channels[chip * 4..chip * 4 + 4] {
260 channel.masked = false;
261 }
262 }
263 15 => {
264 for (local, channel) in self.channels[chip * 4..chip * 4 + 4].iter_mut().enumerate()
265 {
266 channel.masked = value & (1 << local) != 0;
267 }
268 }
269 _ => {}
270 }
271 }
272
273 pub fn inb(&mut self, port: u16) -> u8 {
276 if let Some(channel) = Self::page_channel(port) {
277 return self.channels[channel].page;
278 }
279 let Some((chip, register)) = Self::register(port) else {
280 return 0xff;
281 };
282 if register < 8 {
283 let index = chip * 4 + register / 2;
284 let value = if index == 4 {
285 0xffff
286 } else if register & 1 == 0 {
287 self.channels[index].address
288 } else {
289 self.channels[index].count
290 };
291 let byte = if self.high_byte[chip] {
292 (value >> 8) as u8
293 } else {
294 value as u8
295 };
296 self.high_byte[chip] = !self.high_byte[chip];
297 byte
298 } else if register == 8 {
299 let value = self.terminal_count[chip] | (self.software_request[chip] << 4);
300 self.terminal_count[chip] = 0;
301 value
302 } else {
303 0xff
304 }
305 }
306
307 pub fn transfer(
316 &mut self,
317 request: DmaRequest,
318 memory: &ConventionalMemory,
319 ) -> Result<Option<DmaUnit>> {
320 let index = usize::from(request.channel.number());
321 let chip = index / 4;
322 let channel = self.channels[index];
323 if request.direction != DmaDirection::MemoryToDevice
324 || channel.masked
325 || !channel.active
326 || self.command[chip] & 4 != 0
327 || channel.mode & 0x0c != 0x08
328 || channel.mode & 0xc0 == 0xc0
329 {
330 return Ok(None);
331 }
332 let unit = if chip == 0 {
333 let address = (u32::from(channel.page) << 16) | u32::from(channel.address);
334 DmaUnit::Byte(memory.read_byte(address)?)
335 } else {
336 let address =
337 (u32::from(channel.page & 0xfe) << 16) | (u32::from(channel.address) << 1);
338 let mut bytes = [0; 2];
339 memory.read(address, &mut bytes)?;
340 DmaUnit::Word(u16::from_le_bytes(bytes))
341 };
342 let current = &mut self.channels[index];
343 current.address = if channel.mode & 0x20 != 0 {
344 channel.address.wrapping_sub(1)
345 } else {
346 channel.address.wrapping_add(1)
347 };
348 current.count = channel.count.wrapping_sub(1);
349 if channel.count == 0 {
350 self.terminal_count[chip] |= 1 << (index % 4);
351 self.software_request[chip] &= !(1 << (index % 4));
352 if channel.mode & 0x10 != 0 {
353 current.address = current.base_address;
354 current.count = current.base_count;
355 } else {
356 current.active = false;
357 }
358 }
359 Ok(Some(unit))
360 }
361}