diff --git a/src/emulator/addressing_modes.rs b/src/emulator/addressing_modes.rs index 37a774a..1eb9037 100644 --- a/src/emulator/addressing_modes.rs +++ b/src/emulator/addressing_modes.rs @@ -1,6 +1,7 @@ use std::convert::{From, Into}; -struct Address(usize); +#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] +pub struct Address(pub usize); impl From for Address { fn from(v: usize) -> Self { if v > 0xFFFF { @@ -9,11 +10,69 @@ impl From for Address { Self(v) } } +impl From for Address { + fn from(v: i32) -> Self { + if v < 0 || v > 0xFFFF { + panic!("Can't use {}i32 as address", v); + } + Address((v & 0xFFFF) as usize) + } +} impl From for Address { fn from(v: u16) -> Self { Self(v as usize) } } +impl From for Address { + fn from(v: u8) -> Self { + Address((v as usize) & 0xFF) + } +} +impl Into for Address { + fn into(self) -> usize { + *self & 0xFFFF + } +} +impl Into for Address { + fn into(self) -> u16 { + (*self & 0xFFFF) as u16 + } +} +impl std::ops::Deref for Address { + type Target = usize; + fn deref(&self) -> &usize { + &self.0 + } +} +impl std::ops::DerefMut for Address { + fn deref_mut(&mut self) -> &mut usize { + &mut self.0 + } +} +impl std::ops::Add for Address { + type Output = Self; + fn add(self, rhs: Self) -> Self { + let result = *self + *rhs; + if result > 0xFFFF { + panic!( + "Resulting op between Address and 0x{:04X} is bigger than 0xFFFF", + *rhs + ); + } + Address(result) + } +} +impl Address { + pub fn same_page_add>(self, rhs: I) -> Self { + let rhs = rhs.into() & 0x00FF; + let hi = *self & 0xFF00; + let lo = (*self + rhs) & 0xFF; + Address(hi | lo) + } + pub fn next(&self) -> Self { + Address(self.0 + 1) + } +} pub fn get_size(addr_mode: AddressingMode) -> usize { OP_SIZES[addr_mode as usize] diff --git a/src/emulator/registers.rs b/src/emulator/components.rs similarity index 67% rename from src/emulator/registers.rs rename to src/emulator/components.rs index a662451..1018951 100644 --- a/src/emulator/registers.rs +++ b/src/emulator/components.rs @@ -1,3 +1,33 @@ +use super::addressing_modes::Address; + +/* #region Ram */ +pub struct Ram(pub [u8; 0x10000]); +impl Ram { + pub fn load(&mut self, code: [u8; 0x10000]) { + self.0 = code; + } +} +impl std::ops::Index
for Ram { + type Output = u8; + fn index(&self, idx: Address) -> &u8 { + let idx: usize = idx.into(); + &self.0[idx] + } +} +impl std::ops::IndexMut
for Ram { + fn index_mut(&mut self, idx: Address) -> &mut u8 { + let idx: usize = idx.into(); + &mut self.0[idx] + } +} +impl std::ops::Deref for Ram { + type Target = [u8; 0x10000]; + fn deref(&self) -> &[u8; 0x10000] { + &self.0 + } +} +/* #endregion */ + #[repr(u8)] #[derive(PartialEq, Copy, Clone, Debug)] pub enum Flags { @@ -15,7 +45,7 @@ pub struct Registers { pub A: u8, pub X: u8, pub Y: u8, - pub PC: u16, + pub PC: Address, pub flags: u8, } impl Registers { @@ -52,7 +82,7 @@ impl std::default::Default for Registers { A: 0x00, X: 0x00, Y: 0x00, - PC: 0x0000, + PC: 0x0000usize.into(), flags: 0b_0010_0000, } } @@ -62,7 +92,7 @@ impl std::fmt::Debug for Registers { write!( f, "Registers: \n PC: {:04X}\n A: {:02X} X: {:02X} Y: {:02X}\nNV-BDIZC\n{:08b}", - self.PC, self.A, self.X, self.Y, self.flags + *self.PC, self.A, self.X, self.Y, self.flags ) } } diff --git a/src/emulator/mod.rs b/src/emulator/mod.rs index 5239c93..c343204 100644 --- a/src/emulator/mod.rs +++ b/src/emulator/mod.rs @@ -5,6 +5,6 @@ mod addressing_modes; use addressing_modes::AddressingMode; mod opcodes; use opcodes::OpcodeType; -mod registers; +mod components; mod system; pub use system::System; diff --git a/src/emulator/system.rs b/src/emulator/system.rs index 3463b38..d117abd 100644 --- a/src/emulator/system.rs +++ b/src/emulator/system.rs @@ -1,24 +1,24 @@ +use super::addressing_modes::{get_size, Address, AddressingMode}; +use super::components::{Flags, Ram, Registers}; use super::error; use super::opcodes; -use super::registers::{Flags, Registers}; use super::OpcodeType; -use super::{addressing_modes::get_size, AddressingMode}; fn invalid_mode(mode_used: AddressingMode) -> T { panic!("The addressign mode used ({:?}) is either not valid for this opcode, or expects an argument which was not provided",mode_used) } -static RESET_VEC_ADDR: usize = 0xFFFC; +static RESET_VEC_ADDR: Address = Address(0xFFFC); macro_rules! fetch { ($self:ident PC+$off:expr) => { - $self.ram[$self.registers.PC as usize + $off] + $self.ram[$self.registers.PC + Address($off)] }; ($self:ident $addr:expr) => { - $self.ram[$addr as usize] + $self.ram[$addr] }; ($self:ident D $addr:expr) => { - ($self.ram[$addr as usize + 1] as u16) << 8 | $self.ram[$addr as usize] as u16 + ($self.ram[$addr.next()] as u16) << 8 | $self.ram[$addr] as u16 }; } macro_rules! operation { @@ -35,22 +35,22 @@ macro_rules! operation { pub struct System { pub cycles: usize, - pub ram: [u8; 0x10000], + pub ram: Ram, pub registers: Registers, } impl System { pub fn new() -> Self { Self { cycles: 0, - ram: [0x00; 0x10000], + ram: Ram([0x00; 0x10000]), registers: Registers::default(), } } pub fn init(&mut self) -> Result<(), error::CpuError> { let lo: u16 = self.ram[RESET_VEC_ADDR] as u16; - let hi: u16 = self.ram[RESET_VEC_ADDR + 1] as u16; + let hi: u16 = self.ram[RESET_VEC_ADDR.same_page_add(1usize)] as u16; let addr = hi << 8 | lo; - self.registers.PC = addr; + self.registers.PC = addr.into(); Ok(()) } pub fn step(&mut self) -> Result<(), error::CpuError> { @@ -61,8 +61,8 @@ impl System { /* if self.registers.test(Flags::Break) { return Err(error::EmulatorError::Break); } */ - println!("Step on {:04X}", self.registers.PC); - let code = self.ram[self.registers.PC as usize]; + println!("Step on {:04X}", *self.registers.PC); + let code = self.ram[self.registers.PC]; let code = match opcodes::from_code(code) { None => return Err(error::CpuError::UnknownOp(code)), Some(v) => v, @@ -78,28 +78,28 @@ impl System { } AddressingMode::ABS => { // Next 2 bytes are an address from where to fetch the real argument - let addr = self.registers.PC as usize + 1; + let addr = self.registers.PC.next(); Some(fetch!(self D addr) as u16) } AddressingMode::ZPG => { // Next byte is an address from the range 0x0000-0x00FF - let addr = self.registers.PC as usize + 1; + let addr = self.registers.PC.same_page_add(1u16); Some(fetch!(self addr) as u16) } AddressingMode::INDX => { // Take the next byte and add it to X, // then use the result as an address and fetch 2 bytes let arg = fetch!(self PC+1); // Opcode arg - let addr: u8 = operation!(self X+arg); // Zero-page addr - let addr_lo = self.ram[addr as usize] as usize; - let addr_hi = self.ram[addr.wrapping_add(1) as usize] as usize; + let addr: Address = operation!(self X+arg).into(); // Zero-page addr + let addr_lo = self.ram[addr] as usize; + let addr_hi = self.ram[addr.next()] as usize; let res_addr = addr_hi << 8 | addr_lo; Some(res_addr as u16) } AddressingMode::REL => { // Add PC with the next byte let arg = fetch!(self PC+1) as u8 as i8 as isize; - let pc = self.registers.PC as usize as isize; + let pc = (*self.registers.PC) as isize; let new_pc = (arg + pc) & 0xFFFF; Some(new_pc as u16) } @@ -120,21 +120,21 @@ impl System { AddressingMode::IMM => self.registers.set_a(operation!(unwrap arg code) as u8), AddressingMode::ABS => self .registers - .set_a(fetch!(self operation!(unwrap arg code))), + .set_a(fetch!(self operation!(unwrap arg code).into())), AddressingMode::ZPG => self .registers - .set_a(fetch!(self operation!(unwrap arg code))), + .set_a(fetch!(self operation!(unwrap arg code).into())), _ => panic!("Invalid addressing mode for {:?}", code.name), }, OpcodeType::STA => match code.addr_mode { AddressingMode::ABS => { - self.ram[operation!(unwrap arg code) as usize] = self.registers.A + self.ram[operation!(unwrap arg code).into()] = self.registers.A } AddressingMode::ZPG => { - self.ram[operation!(unwrap arg code) as usize] = self.registers.A + self.ram[operation!(unwrap arg code).into()] = self.registers.A } AddressingMode::INDX => { - self.ram[operation!(unwrap arg code) as usize] = self.registers.A + self.ram[operation!(unwrap arg code).into()] = self.registers.A } _ => panic!("Invalid addressing mode for {:?}", code.name), }, @@ -143,18 +143,18 @@ impl System { _ => panic!("Invalid addressing mode for {:?}", code.name), }, OpcodeType::JMP => match code.addr_mode { - AddressingMode::ABS => self.registers.PC = operation!(unwrap arg code) as u16, + AddressingMode::ABS => self.registers.PC = operation!(unwrap arg code).into(), _ => panic!("Invalid addressing mode for {:?}", code.name), }, OpcodeType::BEQ if code.addr_mode == AddressingMode::REL => { if self.registers.test(Flags::Zero) { - self.registers.PC = operation!(unwrap arg code); + self.registers.PC = operation!(unwrap arg code).into(); branch_taken = true; } } OpcodeType::BNE if code.addr_mode == AddressingMode::REL => { if !self.registers.test(Flags::Zero) { - self.registers.PC = operation!(unwrap arg code); + self.registers.PC = operation!(unwrap arg code).into(); branch_taken = true; } } @@ -169,14 +169,14 @@ impl System { if branch_taken || code.name == OpcodeType::JMP { println!("Don't increment PC"); } else { - self.registers.PC += get_size(code.addr_mode) as u16; + self.registers.PC = self.registers.PC + get_size(code.addr_mode).into(); } self.cycles += 1; Ok(()) } pub fn restart(&mut self) { self.cycles = 0; - self.ram = [0x00; 0x10000]; + self.ram.load([0x00; 0x10000]); self.registers = Registers::default(); } } diff --git a/src/handler.rs b/src/handler.rs index be9bbf0..e96d127 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -71,18 +71,18 @@ impl ThreadedEmulator { match cmd { Cmd::Step => { system.step()?; - let page_02 = Vec::from(&system.ram[0x200..0x300]); + let page_02 = Vec::from(&(*system.ram)[0x200..0x300]); tdata.send(page_02); } Cmd::Reset => { system.restart(); - system.ram = *TEST_CODE; + system.ram.load(*TEST_CODE); } Cmd::Run => loop { if let Err(e) = rcmd.recv_timeout(std::time::Duration::from_millis(1)) { if e == std::sync::mpsc::RecvTimeoutError::Timeout { system.step()?; - let page_02 = Vec::from(&system.ram[0x200..0x300]); + let page_02 = Vec::from(&(*system.ram)[0x200..0x300]); tdata.send(page_02); } else { panic!("Controller mpsc disconnected: {}", e) @@ -94,14 +94,14 @@ impl ThreadedEmulator { Cmd::Get(what) => match what { GetType::Flags => {} GetType::Range(start, end) => { - let data = &system.ram[start..end]; + let data = &(*system.ram)[start..end]; tdata .send(Vec::from(data)) .expect("Couldn't send requested value"); } GetType::Value(addr) => { tdata - .send(vec![system.ram[addr]]) + .send(vec![(*system.ram)[addr]]) .expect("Couldn't send requested value"); } },