First part of Bus
This commit is contained in:
@@ -24,6 +24,11 @@ impl std::ops::Sub<i32> for Word {
|
||||
fn sub(self, rhs: i32) -> Self::Output { self + -rhs }
|
||||
}
|
||||
|
||||
impl std::ops::Sub<Word> for Word {
|
||||
type Output = Word;
|
||||
fn sub(self, rhs: Word) -> Self::Output { Word(self.0 - rhs.0) }
|
||||
}
|
||||
|
||||
impl std::ops::SubAssign<i32> for Word {
|
||||
fn sub_assign(&mut self, rhs: i32) { *self = *self - rhs; }
|
||||
}
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
use crate::memory::PeekPoke;
|
||||
use crate::address::Word;
|
||||
|
||||
pub trait Device {
|
||||
fn tick(&mut self);
|
||||
fn reset(&mut self);
|
||||
}
|
||||
|
||||
pub struct Bus<A, B> {
|
||||
start: Word,
|
||||
end: Word,
|
||||
device: A,
|
||||
rest: B
|
||||
}
|
||||
|
||||
impl<A, B> Bus<A, B> {
|
||||
fn new(start: u32, end: u32, device: A, rest: B) -> Self {
|
||||
Self { start: start.into(), end: end.into(), device, rest }
|
||||
}
|
||||
|
||||
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 {
|
||||
fn tick(&mut self) { self.0 += 1 }
|
||||
fn reset(&mut self) { self.0 = 10 }
|
||||
}
|
||||
|
||||
struct ArrayDevice([u8; 10]);
|
||||
impl PeekPoke for ArrayDevice {
|
||||
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 }
|
||||
}
|
||||
|
||||
#[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));
|
||||
|
||||
for _ in 0..5 { bus.tick() }
|
||||
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
|
||||
}
|
||||
}
|
||||
+12
-12
@@ -141,8 +141,8 @@ impl CPU {
|
||||
self.push_data(x);
|
||||
self.push_data(y)
|
||||
}
|
||||
Opcode::Store => { self.memory.poke(x, y as u8) }
|
||||
Opcode::Storew => { self.memory.poke24(x, y) }
|
||||
Opcode::Store => { self.memory.poke(x.into(), y as u8) }
|
||||
Opcode::Storew => { self.memory.poke24(x.into(), y) }
|
||||
Opcode::Setsdp => {
|
||||
self.dp = x.into();
|
||||
self.sp = y.into()
|
||||
@@ -189,11 +189,11 @@ impl CPU {
|
||||
Opcode::Hlt => { self.halted = true }
|
||||
Opcode::Load => {
|
||||
let x = self.pop_data();
|
||||
self.push_data(self.memory.peek(x) as u32)
|
||||
self.push_data(self.memory.peek(x.into()) as u32)
|
||||
}
|
||||
Opcode::Loadw => {
|
||||
let x = self.pop_data();
|
||||
self.push_data(self.memory.peek24(x))
|
||||
self.push_data(self.memory.peek24(x.into()))
|
||||
}
|
||||
Opcode::Inton => { self.int_enabled = true }
|
||||
Opcode::Intoff => { self.int_enabled = false }
|
||||
@@ -436,8 +436,8 @@ mod tests {
|
||||
let mut cpu = CPU::new(Memory::default());
|
||||
cpu.push_data(37u32);
|
||||
cpu.push_data(45u32);
|
||||
assert_eq!(cpu.memory.peek24(256), 37);
|
||||
assert_eq!(cpu.memory.peek24(259), 45);
|
||||
assert_eq!(cpu.memory.peek24_u32(256), 37);
|
||||
assert_eq!(cpu.memory.peek24_u32(259), 45);
|
||||
|
||||
cpu.push_call(12u32);
|
||||
cpu.push_call(34u32);
|
||||
@@ -458,12 +458,12 @@ mod tests {
|
||||
#[test]
|
||||
fn test_cpu_fetch() {
|
||||
let mut cpu = CPU::new(Memory::default());
|
||||
cpu.memory.poke(0x400, 0x01); // nop 1 arg
|
||||
cpu.memory.poke(0x401, 0x02); // 2
|
||||
cpu.memory.poke(0x402, 0x07); // add 3 arg
|
||||
cpu.memory.poke24(0x403, 0x123456); // 3-byte arg
|
||||
cpu.memory.poke(0x406, 29 << 2); // hlt
|
||||
cpu.memory.poke(0x407, 0xfc); // gibberish
|
||||
cpu.memory.poke_u32(0x400, 0x01); // nop 1 arg
|
||||
cpu.memory.poke_u32(0x401, 0x02); // 2
|
||||
cpu.memory.poke_u32(0x402, 0x07); // add 3 arg
|
||||
cpu.memory.poke24_u32(0x403, 0x123456); // 3-byte arg
|
||||
cpu.memory.poke_u32(0x406, 29 << 2); // hlt
|
||||
cpu.memory.poke_u32(0x407, 0xfc); // gibberish
|
||||
|
||||
assert_eq!(cpu.fetch(), Ok(Instruction { opcode: Opcode::Nop, arg: Some(2), length: 2 }));
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ mod memory;
|
||||
mod address;
|
||||
mod opcodes;
|
||||
mod cpu;
|
||||
mod bus;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
|
||||
+21
-18
@@ -39,27 +39,30 @@ impl std::ops::IndexMut<Word> for Memory {
|
||||
}
|
||||
|
||||
pub trait PeekPoke {
|
||||
fn peek<A: Into<Word>>(&self, addr: A) -> u8;
|
||||
fn poke<A: Into<Word>>(&mut self, addr: A, val: u8);
|
||||
fn peek(&self, addr: Word) -> u8;
|
||||
fn poke(&mut self, addr: Word, val: u8);
|
||||
|
||||
fn peek24<A: Into<Word>>(&self, addr: A) -> u32 {
|
||||
let addr = addr.into();
|
||||
fn peek24(&self, addr: Word) -> u32 {
|
||||
(self.peek(addr) as u32)
|
||||
| ((self.peek(addr + 1) as u32) << 8)
|
||||
| ((self.peek(addr + 2) as u32) << 16)
|
||||
}
|
||||
|
||||
fn poke24<A: Into<Word>>(&mut self, addr: A, val: u32) {
|
||||
let addr = addr.into();
|
||||
fn poke24(&mut self, addr: Word, val: u32) {
|
||||
self.poke(addr, val as u8);
|
||||
self.poke(addr + 1, (val >> 8) as u8);
|
||||
self.poke(addr + 2, (val >> 16) as u8);
|
||||
}
|
||||
|
||||
fn peek_u32(&self, addr: u32) -> u8 { self.peek(addr.into()) }
|
||||
fn poke_u32(&mut self, addr: u32, val: u8) { self.poke(addr.into(), val) }
|
||||
fn peek24_u32(&mut self, addr: u32) -> u32 { self.peek24(addr.into()) }
|
||||
fn poke24_u32(&mut self, addr: u32, val: u32) { self.poke24(addr.into(), val) }
|
||||
}
|
||||
|
||||
impl PeekPoke for Memory {
|
||||
fn peek<A: Into<Word>>(&self, addr: A) -> u8 { self[addr.into()] }
|
||||
fn poke<A: Into<Word>>(&mut self, addr: A, val: u8) { self[addr.into()] = val; }
|
||||
fn peek(&self, addr: Word) -> u8 { self[addr.into()] }
|
||||
fn poke(&mut self, addr: Word, val: u8) { self[addr.into()] = val; }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -69,21 +72,21 @@ mod tests {
|
||||
#[test]
|
||||
fn test_mem_peek_poke() {
|
||||
let mut mem = Memory::default();
|
||||
assert_eq!(mem.peek(35), 0);
|
||||
mem.poke(35, 45);
|
||||
assert_eq!(mem.peek(35), 45);
|
||||
assert_eq!(mem.peek(36), 0);
|
||||
assert_eq!(mem.peek_u32(35), 0);
|
||||
mem.poke_u32(35, 45);
|
||||
assert_eq!(mem.peek_u32(35), 45);
|
||||
assert_eq!(mem.peek_u32(36), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mem_word_fns() {
|
||||
let mut mem = Memory::default();
|
||||
mem.poke24(10, 0x123456);
|
||||
assert_eq!(mem.peek(10), 0x56);
|
||||
assert_eq!(mem.peek(11), 0x34);
|
||||
assert_eq!(mem.peek(12), 0x12);
|
||||
assert_eq!(mem.peek24(10), 0x123456);
|
||||
assert_eq!(mem.peek24(11), 0x001234);
|
||||
mem.poke24(10.into(), 0x123456);
|
||||
assert_eq!(mem.peek_u32(10), 0x56);
|
||||
assert_eq!(mem.peek_u32(11), 0x34);
|
||||
assert_eq!(mem.peek_u32(12), 0x12);
|
||||
assert_eq!(mem.peek24(10.into()), 0x123456);
|
||||
assert_eq!(mem.peek24(11.into()), 0x001234);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user