Moar reworks
This commit is contained in:
parent
a9f1a63900
commit
4fd4d326c1
|
@ -1,6 +1,7 @@
|
||||||
use std::convert::{From, Into};
|
use std::convert::{From, Into};
|
||||||
|
|
||||||
struct Address(usize);
|
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
|
||||||
|
pub struct Address(pub usize);
|
||||||
impl From<usize> for Address {
|
impl From<usize> for Address {
|
||||||
fn from(v: usize) -> Self {
|
fn from(v: usize) -> Self {
|
||||||
if v > 0xFFFF {
|
if v > 0xFFFF {
|
||||||
|
@ -9,11 +10,69 @@ impl From<usize> for Address {
|
||||||
Self(v)
|
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 {
|
impl From<u16> for Address {
|
||||||
fn from(v: u16) -> Self {
|
fn from(v: u16) -> Self {
|
||||||
Self(v as usize)
|
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 {
|
pub fn get_size(addr_mode: AddressingMode) -> usize {
|
||||||
OP_SIZES[addr_mode as 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)]
|
#[repr(u8)]
|
||||||
#[derive(PartialEq, Copy, Clone, Debug)]
|
#[derive(PartialEq, Copy, Clone, Debug)]
|
||||||
pub enum Flags {
|
pub enum Flags {
|
||||||
|
@ -15,7 +45,7 @@ pub struct Registers {
|
||||||
pub A: u8,
|
pub A: u8,
|
||||||
pub X: u8,
|
pub X: u8,
|
||||||
pub Y: u8,
|
pub Y: u8,
|
||||||
pub PC: u16,
|
pub PC: Address,
|
||||||
pub flags: u8,
|
pub flags: u8,
|
||||||
}
|
}
|
||||||
impl Registers {
|
impl Registers {
|
||||||
|
@ -52,7 +82,7 @@ impl std::default::Default for Registers {
|
||||||
A: 0x00,
|
A: 0x00,
|
||||||
X: 0x00,
|
X: 0x00,
|
||||||
Y: 0x00,
|
Y: 0x00,
|
||||||
PC: 0x0000,
|
PC: 0x0000usize.into(),
|
||||||
flags: 0b_0010_0000,
|
flags: 0b_0010_0000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +92,7 @@ impl std::fmt::Debug for Registers {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Registers: \n PC: {:04X}\n A: {:02X} X: {:02X} Y: {:02X}\nNV-BDIZC\n{:08b}",
|
"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;
|
use addressing_modes::AddressingMode;
|
||||||
mod opcodes;
|
mod opcodes;
|
||||||
use opcodes::OpcodeType;
|
use opcodes::OpcodeType;
|
||||||
mod registers;
|
mod components;
|
||||||
mod system;
|
mod system;
|
||||||
pub use system::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::error;
|
||||||
use super::opcodes;
|
use super::opcodes;
|
||||||
use super::registers::{Flags, Registers};
|
|
||||||
use super::OpcodeType;
|
use super::OpcodeType;
|
||||||
use super::{addressing_modes::get_size, AddressingMode};
|
|
||||||
|
|
||||||
fn invalid_mode<T>(mode_used: AddressingMode) -> T {
|
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)
|
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 {
|
macro_rules! fetch {
|
||||||
($self:ident PC+$off:expr) => {
|
($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:ident $addr:expr) => {
|
||||||
$self.ram[$addr as usize]
|
$self.ram[$addr]
|
||||||
};
|
};
|
||||||
($self:ident D $addr:expr) => {
|
($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 {
|
macro_rules! operation {
|
||||||
|
@ -35,22 +35,22 @@ macro_rules! operation {
|
||||||
|
|
||||||
pub struct System {
|
pub struct System {
|
||||||
pub cycles: usize,
|
pub cycles: usize,
|
||||||
pub ram: [u8; 0x10000],
|
pub ram: Ram,
|
||||||
pub registers: Registers,
|
pub registers: Registers,
|
||||||
}
|
}
|
||||||
impl System {
|
impl System {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
ram: [0x00; 0x10000],
|
ram: Ram([0x00; 0x10000]),
|
||||||
registers: Registers::default(),
|
registers: Registers::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn init(&mut self) -> Result<(), error::CpuError> {
|
pub fn init(&mut self) -> Result<(), error::CpuError> {
|
||||||
let lo: u16 = self.ram[RESET_VEC_ADDR] as u16;
|
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;
|
let addr = hi << 8 | lo;
|
||||||
self.registers.PC = addr;
|
self.registers.PC = addr.into();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn step(&mut self) -> Result<(), error::CpuError> {
|
pub fn step(&mut self) -> Result<(), error::CpuError> {
|
||||||
|
@ -61,8 +61,8 @@ impl System {
|
||||||
/* if self.registers.test(Flags::Break) {
|
/* if self.registers.test(Flags::Break) {
|
||||||
return Err(error::EmulatorError::Break);
|
return Err(error::EmulatorError::Break);
|
||||||
} */
|
} */
|
||||||
println!("Step on {:04X}", self.registers.PC);
|
println!("Step on {:04X}", *self.registers.PC);
|
||||||
let code = self.ram[self.registers.PC as usize];
|
let code = self.ram[self.registers.PC];
|
||||||
let code = match opcodes::from_code(code) {
|
let code = match opcodes::from_code(code) {
|
||||||
None => return Err(error::CpuError::UnknownOp(code)),
|
None => return Err(error::CpuError::UnknownOp(code)),
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
|
@ -78,28 +78,28 @@ impl System {
|
||||||
}
|
}
|
||||||
AddressingMode::ABS => {
|
AddressingMode::ABS => {
|
||||||
// Next 2 bytes are an address from where to fetch the real argument
|
// 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)
|
Some(fetch!(self D addr) as u16)
|
||||||
}
|
}
|
||||||
AddressingMode::ZPG => {
|
AddressingMode::ZPG => {
|
||||||
// Next byte is an address from the range 0x0000-0x00FF
|
// 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)
|
Some(fetch!(self addr) as u16)
|
||||||
}
|
}
|
||||||
AddressingMode::INDX => {
|
AddressingMode::INDX => {
|
||||||
// Take the next byte and add it to X,
|
// Take the next byte and add it to X,
|
||||||
// then use the result as an address and fetch 2 bytes
|
// then use the result as an address and fetch 2 bytes
|
||||||
let arg = fetch!(self PC+1); // Opcode arg
|
let arg = fetch!(self PC+1); // Opcode arg
|
||||||
let addr: u8 = operation!(self X+arg); // Zero-page addr
|
let addr: Address = operation!(self X+arg).into(); // Zero-page addr
|
||||||
let addr_lo = self.ram[addr as usize] as usize;
|
let addr_lo = self.ram[addr] as usize;
|
||||||
let addr_hi = self.ram[addr.wrapping_add(1) as usize] as usize;
|
let addr_hi = self.ram[addr.next()] as usize;
|
||||||
let res_addr = addr_hi << 8 | addr_lo;
|
let res_addr = addr_hi << 8 | addr_lo;
|
||||||
Some(res_addr as u16)
|
Some(res_addr as u16)
|
||||||
}
|
}
|
||||||
AddressingMode::REL => {
|
AddressingMode::REL => {
|
||||||
// Add PC with the next byte
|
// Add PC with the next byte
|
||||||
let arg = fetch!(self PC+1) as u8 as i8 as isize;
|
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;
|
let new_pc = (arg + pc) & 0xFFFF;
|
||||||
Some(new_pc as u16)
|
Some(new_pc as u16)
|
||||||
}
|
}
|
||||||
|
@ -120,21 +120,21 @@ impl System {
|
||||||
AddressingMode::IMM => self.registers.set_a(operation!(unwrap arg code) as u8),
|
AddressingMode::IMM => self.registers.set_a(operation!(unwrap arg code) as u8),
|
||||||
AddressingMode::ABS => self
|
AddressingMode::ABS => self
|
||||||
.registers
|
.registers
|
||||||
.set_a(fetch!(self operation!(unwrap arg code))),
|
.set_a(fetch!(self operation!(unwrap arg code).into())),
|
||||||
AddressingMode::ZPG => self
|
AddressingMode::ZPG => self
|
||||||
.registers
|
.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),
|
_ => panic!("Invalid addressing mode for {:?}", code.name),
|
||||||
},
|
},
|
||||||
OpcodeType::STA => match code.addr_mode {
|
OpcodeType::STA => match code.addr_mode {
|
||||||
AddressingMode::ABS => {
|
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 => {
|
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 => {
|
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),
|
_ => panic!("Invalid addressing mode for {:?}", code.name),
|
||||||
},
|
},
|
||||||
|
@ -143,18 +143,18 @@ impl System {
|
||||||
_ => panic!("Invalid addressing mode for {:?}", code.name),
|
_ => panic!("Invalid addressing mode for {:?}", code.name),
|
||||||
},
|
},
|
||||||
OpcodeType::JMP => match code.addr_mode {
|
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),
|
_ => panic!("Invalid addressing mode for {:?}", code.name),
|
||||||
},
|
},
|
||||||
OpcodeType::BEQ if code.addr_mode == AddressingMode::REL => {
|
OpcodeType::BEQ if code.addr_mode == AddressingMode::REL => {
|
||||||
if self.registers.test(Flags::Zero) {
|
if self.registers.test(Flags::Zero) {
|
||||||
self.registers.PC = operation!(unwrap arg code);
|
self.registers.PC = operation!(unwrap arg code).into();
|
||||||
branch_taken = true;
|
branch_taken = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OpcodeType::BNE if code.addr_mode == AddressingMode::REL => {
|
OpcodeType::BNE if code.addr_mode == AddressingMode::REL => {
|
||||||
if !self.registers.test(Flags::Zero) {
|
if !self.registers.test(Flags::Zero) {
|
||||||
self.registers.PC = operation!(unwrap arg code);
|
self.registers.PC = operation!(unwrap arg code).into();
|
||||||
branch_taken = true;
|
branch_taken = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,14 +169,14 @@ impl System {
|
||||||
if branch_taken || code.name == OpcodeType::JMP {
|
if branch_taken || code.name == OpcodeType::JMP {
|
||||||
println!("Don't increment PC");
|
println!("Don't increment PC");
|
||||||
} else {
|
} 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;
|
self.cycles += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn restart(&mut self) {
|
pub fn restart(&mut self) {
|
||||||
self.cycles = 0;
|
self.cycles = 0;
|
||||||
self.ram = [0x00; 0x10000];
|
self.ram.load([0x00; 0x10000]);
|
||||||
self.registers = Registers::default();
|
self.registers = Registers::default();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,18 +71,18 @@ impl ThreadedEmulator {
|
||||||
match cmd {
|
match cmd {
|
||||||
Cmd::Step => {
|
Cmd::Step => {
|
||||||
system.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);
|
tdata.send(page_02);
|
||||||
}
|
}
|
||||||
Cmd::Reset => {
|
Cmd::Reset => {
|
||||||
system.restart();
|
system.restart();
|
||||||
system.ram = *TEST_CODE;
|
system.ram.load(*TEST_CODE);
|
||||||
}
|
}
|
||||||
Cmd::Run => loop {
|
Cmd::Run => loop {
|
||||||
if let Err(e) = rcmd.recv_timeout(std::time::Duration::from_millis(1)) {
|
if let Err(e) = rcmd.recv_timeout(std::time::Duration::from_millis(1)) {
|
||||||
if e == std::sync::mpsc::RecvTimeoutError::Timeout {
|
if e == std::sync::mpsc::RecvTimeoutError::Timeout {
|
||||||
system.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);
|
tdata.send(page_02);
|
||||||
} else {
|
} else {
|
||||||
panic!("Controller mpsc disconnected: {}", e)
|
panic!("Controller mpsc disconnected: {}", e)
|
||||||
|
@ -94,14 +94,14 @@ impl ThreadedEmulator {
|
||||||
Cmd::Get(what) => match what {
|
Cmd::Get(what) => match what {
|
||||||
GetType::Flags => {}
|
GetType::Flags => {}
|
||||||
GetType::Range(start, end) => {
|
GetType::Range(start, end) => {
|
||||||
let data = &system.ram[start..end];
|
let data = &(*system.ram)[start..end];
|
||||||
tdata
|
tdata
|
||||||
.send(Vec::from(data))
|
.send(Vec::from(data))
|
||||||
.expect("Couldn't send requested value");
|
.expect("Couldn't send requested value");
|
||||||
}
|
}
|
||||||
GetType::Value(addr) => {
|
GetType::Value(addr) => {
|
||||||
tdata
|
tdata
|
||||||
.send(vec![system.ram[addr]])
|
.send(vec![(*system.ram)[addr]])
|
||||||
.expect("Couldn't send requested value");
|
.expect("Couldn't send requested value");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue