crustacean_6502_emulator/src/emulator/system.rs

205 lines
7.8 KiB
Rust
Raw Normal View History

2020-01-28 06:21:14 +00:00
use super::addressing_modes::{get_size, Address, AddressingMode};
use super::components::{Flags, Ram, Registers};
2020-01-21 23:48:26 +00:00
use super::error;
use super::opcodes;
use super::OpcodeType;
fn invalid_mode<T>(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)
}
2020-01-28 06:21:14 +00:00
static RESET_VEC_ADDR: Address = Address(0xFFFC);
2020-01-21 23:48:26 +00:00
macro_rules! fetch {
($self:ident PC+$off:expr) => {
2020-01-28 06:21:14 +00:00
$self.ram[$self.registers.PC + Address($off)]
2020-01-21 23:48:26 +00:00
};
($self:ident $addr:expr) => {
2020-01-28 06:21:14 +00:00
$self.ram[$addr]
2020-01-21 23:48:26 +00:00
};
($self:ident D $addr:expr) => {
2020-01-28 06:21:14 +00:00
($self.ram[$addr.next()] as u16) << 8 | $self.ram[$addr] as u16
2020-01-21 23:48:26 +00:00
};
}
macro_rules! operation {
($self:ident A+$b:expr) => {
2020-01-28 03:09:05 +00:00
$self.registers.A.wrapping_add($b as u8)
2020-01-21 23:48:26 +00:00
};
($self:ident X+$b:expr) => {
2020-01-28 03:09:05 +00:00
$self.registers.X.wrapping_add($b as u8)
2020-01-21 23:48:26 +00:00
};
(unwrap $arg:ident $addr:ident) => {
$arg.unwrap_or_else(|| invalid_mode($addr.addr_mode))
};
}
2020-01-28 03:09:05 +00:00
pub struct System {
2020-01-21 23:48:26 +00:00
pub cycles: usize,
2020-01-28 06:21:14 +00:00
pub ram: Ram,
2020-01-28 03:09:05 +00:00
pub registers: Registers,
2020-01-21 23:48:26 +00:00
}
2020-01-28 03:09:05 +00:00
impl System {
2020-01-21 23:48:26 +00:00
pub fn new() -> Self {
Self {
cycles: 0,
2020-01-28 06:21:14 +00:00
ram: Ram([0x00; 0x10000]),
2020-01-28 03:09:05 +00:00
registers: Registers::default(),
2020-01-21 23:48:26 +00:00
}
}
2020-01-28 03:09:05 +00:00
pub fn init(&mut self) -> Result<(), error::CpuError> {
2020-01-21 23:48:26 +00:00
let lo: u16 = self.ram[RESET_VEC_ADDR] as u16;
2020-01-28 06:21:14 +00:00
let hi: u16 = self.ram[RESET_VEC_ADDR.same_page_add(1usize)] as u16;
2020-01-21 23:48:26 +00:00
let addr = hi << 8 | lo;
2020-01-28 06:21:14 +00:00
self.registers.PC = addr.into();
2020-01-21 23:48:26 +00:00
Ok(())
}
2020-01-28 03:09:05 +00:00
pub fn step(&mut self) -> Result<(), error::CpuError> {
2020-01-21 23:48:26 +00:00
if self.cycles == 0 {
println!("Initializing");
self.init()?;
}
2020-01-28 03:09:05 +00:00
/* if self.registers.test(Flags::Break) {
2020-01-21 23:48:26 +00:00
return Err(error::EmulatorError::Break);
2020-01-28 03:09:05 +00:00
} */
2020-01-28 06:21:14 +00:00
println!("Step on {:04X}", *self.registers.PC);
let code = self.ram[self.registers.PC];
2020-01-21 23:48:26 +00:00
let code = match opcodes::from_code(code) {
2020-01-28 03:09:05 +00:00
None => return Err(error::CpuError::UnknownOp(code)),
2020-01-21 23:48:26 +00:00
Some(v) => v,
};
println!(" Opcode {:?}", code.name);
let arg: Option<u16> = match code.addr_mode {
AddressingMode::IMPL => None, // No argument
AddressingMode::A => None, // No argument
AddressingMode::IMM => {
// Next byte is the argument
let addr = fetch!(self PC+1);
Some(addr as u16)
}
AddressingMode::ABS => {
// Next 2 bytes are an address from where to fetch the real argument
2020-01-28 06:21:14 +00:00
let addr = self.registers.PC.next();
2020-01-21 23:48:26 +00:00
Some(fetch!(self D addr) as u16)
}
AddressingMode::ZPG => {
// Next byte is an address from the range 0x0000-0x00FF
2020-01-28 06:21:14 +00:00
let addr = self.registers.PC.same_page_add(1u16);
2020-01-21 23:48:26 +00:00
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
2020-01-28 06:21:14 +00:00
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;
2020-01-21 23:48:26 +00:00
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;
2020-01-28 06:21:14 +00:00
let pc = (*self.registers.PC) as isize;
2020-01-21 23:48:26 +00:00
let new_pc = (arg + pc) & 0xFFFF;
Some(new_pc as u16)
}
_ => {
unimplemented!("Unimplemented addressing mode {:?}", code.addr_mode);
}
};
let mut branch_taken = false; // Don't update PC if we take a branch
println!(" Argument: {:#04X?}", arg);
match code.name {
OpcodeType::BRK => {
println!("Stepped on break. Ending");
2020-01-28 03:09:05 +00:00
println!("{:#?}", self.registers);
/* return Err(error::EmulatorError::Break); */
2020-01-21 23:48:26 +00:00
}
OpcodeType::NOP => {}
OpcodeType::LDA => match code.addr_mode {
2020-01-28 03:09:05 +00:00
AddressingMode::IMM => self.registers.set_a(operation!(unwrap arg code) as u8),
AddressingMode::ABS => self
.registers
2020-01-28 06:21:14 +00:00
.set_a(fetch!(self operation!(unwrap arg code).into())),
2020-01-28 03:09:05 +00:00
AddressingMode::ZPG => self
.registers
2020-01-28 06:21:14 +00:00
.set_a(fetch!(self operation!(unwrap arg code).into())),
2020-01-21 23:48:26 +00:00
_ => panic!("Invalid addressing mode for {:?}", code.name),
},
OpcodeType::STA => match code.addr_mode {
2020-01-28 03:09:05 +00:00
AddressingMode::ABS => {
2020-01-28 06:21:14 +00:00
self.ram[operation!(unwrap arg code).into()] = self.registers.A
2020-01-28 03:09:05 +00:00
}
AddressingMode::ZPG => {
2020-01-28 06:21:14 +00:00
self.ram[operation!(unwrap arg code).into()] = self.registers.A
2020-01-28 03:09:05 +00:00
}
AddressingMode::INDX => {
2020-01-28 06:21:14 +00:00
self.ram[operation!(unwrap arg code).into()] = self.registers.A
2020-01-28 03:09:05 +00:00
}
2020-01-21 23:48:26 +00:00
_ => panic!("Invalid addressing mode for {:?}", code.name),
},
OpcodeType::ADC => match code.addr_mode {
2020-01-28 03:09:05 +00:00
AddressingMode::IMM => self.registers.add_a(operation!(unwrap arg code) as u8),
2020-01-21 23:48:26 +00:00
_ => panic!("Invalid addressing mode for {:?}", code.name),
},
OpcodeType::JMP => match code.addr_mode {
2020-01-28 06:21:14 +00:00
AddressingMode::ABS => self.registers.PC = operation!(unwrap arg code).into(),
2020-01-21 23:48:26 +00:00
_ => panic!("Invalid addressing mode for {:?}", code.name),
},
OpcodeType::BEQ if code.addr_mode == AddressingMode::REL => {
2020-01-28 03:09:05 +00:00
if self.registers.test(Flags::Zero) {
2020-01-28 06:21:14 +00:00
self.registers.PC = operation!(unwrap arg code).into();
2020-01-21 23:48:26 +00:00
branch_taken = true;
}
}
OpcodeType::BNE if code.addr_mode == AddressingMode::REL => {
2020-01-28 03:09:05 +00:00
if !self.registers.test(Flags::Zero) {
2020-01-28 06:21:14 +00:00
self.registers.PC = operation!(unwrap arg code).into();
2020-01-21 23:48:26 +00:00
branch_taken = true;
}
}
_ => {
unimplemented!(
"Unimplemented opcode {:?} with {:?}",
code.name,
code.addr_mode
);
}
}
if branch_taken || code.name == OpcodeType::JMP {
println!("Don't increment PC");
} else {
2020-01-28 06:21:14 +00:00
self.registers.PC = self.registers.PC + get_size(code.addr_mode).into();
2020-01-21 23:48:26 +00:00
}
self.cycles += 1;
Ok(())
}
pub fn restart(&mut self) {
self.cycles = 0;
2020-01-28 06:21:14 +00:00
self.ram.load([0x00; 0x10000]);
2020-01-28 03:09:05 +00:00
self.registers = Registers::default();
2020-01-21 23:48:26 +00:00
}
}
mod test {
#[test]
fn test_flags() {
2020-01-28 03:09:05 +00:00
use super::{Flags, Registers};
let mut cpu: Registers = Registers::default();
2020-01-21 23:48:26 +00:00
cpu.set_flag(Flags::Zero, true);
assert_eq!(cpu.test(Flags::Zero), true);
cpu.set_flag(Flags::Zero, false);
assert_eq!(cpu.test(Flags::Zero), false);
cpu.set_flag(Flags::Zero, true);
cpu.set_flag(Flags::Negative, true);
cpu.set_flag(Flags::Int, true);
assert_eq!(cpu.test(Flags::Zero), true);
assert_eq!(cpu.test(Flags::Negative), true);
assert_eq!(cpu.test(Flags::Int), true);
cpu.set_flag(Flags::Negative, false);
assert_eq!(cpu.test(Flags::Zero), true);
assert_eq!(cpu.test(Flags::Negative), false);
assert_eq!(cpu.test(Flags::Int), true);
}
}