Moar reworks
This commit is contained in:
parent
a9f1a63900
commit
4fd4d326c1
|
@ -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<usize> for Address {
|
||||
fn from(v: usize) -> Self {
|
||||
if v > 0xFFFF {
|
||||
|
@ -9,11 +10,69 @@ impl From<usize> for Address {
|
|||
Self(v)
|
||||
}
|
||||
}
|
||||
impl From<i32> 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<u16> for Address {
|
||||
fn from(v: u16) -> Self {
|
||||
Self(v as usize)
|
||||
}
|
||||
}
|
||||
impl From<u8> for Address {
|
||||
fn from(v: u8) -> Self {
|
||||
Address((v as usize) & 0xFF)
|
||||
}
|
||||
}
|
||||
impl Into<usize> for Address {
|
||||
fn into(self) -> usize {
|
||||
*self & 0xFFFF
|
||||
}
|
||||
}
|
||||
impl Into<u16> 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<I: Into<usize>>(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]
|
||||
|
|
|
@ -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<Address> for Ram {
|
||||
type Output = u8;
|
||||
fn index(&self, idx: Address) -> &u8 {
|
||||
let idx: usize = idx.into();
|
||||
&self.0[idx]
|
||||
}
|
||||
}
|
||||
impl std::ops::IndexMut<Address> 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
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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<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)
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue