2022-02-19 11:13:27 -06:00
|
|
|
use crate::memory::PeekPoke;
|
2022-02-20 14:25:43 -06:00
|
|
|
use crate::word::Word;
|
2022-02-19 11:13:27 -06:00
|
|
|
|
|
|
|
|
pub trait Device {
|
|
|
|
|
fn tick(&mut self);
|
|
|
|
|
fn reset(&mut self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct Bus<A, B> {
|
|
|
|
|
start: Word,
|
|
|
|
|
end: Word,
|
|
|
|
|
device: A,
|
2022-02-22 21:46:26 -06:00
|
|
|
rest: B,
|
2022-02-19 11:13:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<A, B> Bus<A, B> {
|
|
|
|
|
fn new(start: u32, end: u32, device: A, rest: B) -> Self {
|
2022-02-22 21:46:26 -06:00
|
|
|
Self {
|
|
|
|
|
start: start.into(),
|
|
|
|
|
end: end.into(),
|
|
|
|
|
device,
|
|
|
|
|
rest,
|
|
|
|
|
}
|
2022-02-19 11:13:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn at(addr: u32, device: A, rest: B) -> Self {
|
|
|
|
|
Self::new(addr, addr, device, rest)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<A: PeekPoke, B: PeekPoke> PeekPoke for Bus<A, B> {
|
|
|
|
|
fn peek(&self, addr: Word) -> u8 {
|
|
|
|
|
if addr >= self.start && addr <= self.end {
|
|
|
|
|
self.device.peek(addr - self.start)
|
|
|
|
|
} else {
|
|
|
|
|
self.rest.peek(addr)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn poke(&mut self, addr: Word, val: u8) {
|
|
|
|
|
if addr >= self.start && addr <= self.end {
|
|
|
|
|
self.device.poke(addr - self.start, val)
|
|
|
|
|
} else {
|
|
|
|
|
self.rest.poke(addr, val)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<A: Device, B: Device> Device for Bus<A, B> {
|
|
|
|
|
fn tick(&mut self) {
|
|
|
|
|
self.device.tick();
|
|
|
|
|
self.rest.tick();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn reset(&mut self) {
|
|
|
|
|
self.device.reset();
|
|
|
|
|
self.rest.reset();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
struct TestDevice(i32);
|
|
|
|
|
impl Device for TestDevice {
|
2022-02-22 21:46:26 -06:00
|
|
|
fn tick(&mut self) {
|
|
|
|
|
self.0 += 1
|
|
|
|
|
}
|
|
|
|
|
fn reset(&mut self) {
|
|
|
|
|
self.0 = 10
|
|
|
|
|
}
|
2022-02-19 11:13:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ArrayDevice([u8; 10]);
|
|
|
|
|
impl PeekPoke for ArrayDevice {
|
2022-02-22 21:46:26 -06:00
|
|
|
fn peek(&self, addr: Word) -> u8 {
|
|
|
|
|
self.0[usize::from(addr)]
|
|
|
|
|
}
|
|
|
|
|
fn poke(&mut self, addr: Word, val: u8) {
|
|
|
|
|
self.0[usize::from(addr)] = val
|
|
|
|
|
}
|
2022-02-19 11:13:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_tick() {
|
|
|
|
|
let device1 = TestDevice(5);
|
|
|
|
|
let device2 = TestDevice(6);
|
|
|
|
|
let device3 = TestDevice(7);
|
|
|
|
|
let mut bus = Bus::at(5, device1, Bus::at(6, device2, device3));
|
|
|
|
|
|
2022-02-22 21:46:26 -06:00
|
|
|
for _ in 0..5 {
|
|
|
|
|
bus.tick()
|
|
|
|
|
}
|
2022-02-19 11:13:27 -06:00
|
|
|
assert_eq!(bus.device.0, 10);
|
|
|
|
|
assert_eq!(bus.rest.device.0, 11);
|
|
|
|
|
assert_eq!(bus.rest.rest.0, 12);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_reset() {
|
|
|
|
|
let device1 = TestDevice(5);
|
|
|
|
|
let device2 = TestDevice(6);
|
|
|
|
|
let mut bus = Bus::at(5, device1, device2);
|
|
|
|
|
|
|
|
|
|
bus.reset();
|
|
|
|
|
assert_eq!(bus.device.0, 10);
|
|
|
|
|
assert_eq!(bus.rest.0, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_poke_peek() {
|
|
|
|
|
let mut bus = Bus::new(5, 10, ArrayDevice([0u8; 10]), ArrayDevice([0u8; 10]));
|
|
|
|
|
bus.poke_u32(2, 2); // Goes into the 2nd device
|
|
|
|
|
bus.poke_u32(6, 6); // Goes into the first device...
|
|
|
|
|
assert_eq!(bus.device.0[1], 6); // At index 1
|
|
|
|
|
assert_eq!(bus.rest.0[2], 2); // Second device gets the other write
|
|
|
|
|
|
|
|
|
|
// Neither device sees the other's write:
|
|
|
|
|
assert_eq!(bus.device.0[2], 0);
|
|
|
|
|
assert_eq!(bus.rest.0[1], 0);
|
|
|
|
|
|
|
|
|
|
assert_eq!(bus.peek_u32(2), 2); // Reading from the first device
|
|
|
|
|
assert_eq!(bus.peek_u32(6), 6); // And the second
|
|
|
|
|
}
|
2022-02-22 21:46:26 -06:00
|
|
|
}
|