Renamed emulator

This commit is contained in:
PeronTheDuck 2020-01-21 20:48:26 -03:00
parent e66085eb25
commit 00f7cf1726
8 changed files with 1291 additions and 0 deletions

32
src/sixty_five/addr Normal file
View File

@ -0,0 +1,32 @@
# ___0 _0__
A 0__0 1010
--------abs---------
abs ___0 11__
absX ___1 11__
absY ___1 1___
--------------------
rel 0000 ___1
--------ind---------
ind ___a bb0c
a b c
ind 0 1 0
X 0 0 1
Y 1 0 1
_: opcode?
ind 0110 1100
Xind ___0 0001
indY ___1 0001
--------------------
zpg ___0 01__
zpgX ___1 01__
zpgY 10_1 0110
___a bb_c
c => uses X|Y
a => x / y

View File

@ -0,0 +1,24 @@
pub fn get_size(addr_mode: AddressingMode) -> usize {
OP_SIZES[addr_mode as usize]
}
//A,abs,absX,absY,imm,impl,ind,indX,indY,rel,zpg,zpgX,zpgY
//1, 3, 3, 3, 2, 1, 3, 2, 2, 2, 2, 2, 2
pub static OP_SIZES: [usize; 13] = [1, 3, 3, 3, 2, 1, 3, 2, 2, 2, 2, 2, 2];
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum AddressingMode {
A = 0, // LSR A
ABS, // LDA $1234
ABSX, // STA $3000,X
ABSY, // AND $4000,Y
IMM, // LDA #$10
IMPL, // CLC
IND, // JMP ($FFFC)
INDX, // LDA ($40,X)
INDY, // LDA ($40),Y
REL, // LABEL // +4
ZPG, // LDA $10
ZPGX, // LDA $10,X
ZPGY, // LDA $10,Y
}

68
src/sixty_five/cpu.rs Normal file
View File

@ -0,0 +1,68 @@
#[repr(u8)]
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum Flags {
Negative = 128,
Overflow = 64,
AlwaysOne = 32,
Break = 16,
Decimal = 8,
Int = 4,
Zero = 2,
Carry = 1,
}
#[allow(non_snake_case)]
pub struct Cpu {
pub A: u8,
pub X: u8,
pub Y: u8,
pub PC: u16,
pub flags: u8,
}
impl Cpu {
pub fn test(&self, flag: Flags) -> bool {
(self.flags & flag as u8) != 0
}
pub fn set_flag(&mut self, flag: Flags, status: bool) {
if status {
self.flags |= flag as u8;
} else {
self.flags &= 0xFF - flag as u8;
}
}
pub fn add_a(&mut self, n: u8) {
let n = n as u16;
let a = self.A as u16;
let res = n + a;
if res > 0xFF {
self.set_flag(Flags::Carry, true);
} else {
self.set_flag(Flags::Carry, false);
}
self.set_a((res & 0xFF) as u8);
}
pub fn set_a(&mut self, value: u8) {
self.set_flag(Flags::Zero, value == 0x00); // Set Zero if A is zero
self.set_flag(Flags::Negative, value & 0x80 != 0); // Test sign bit
self.A = value;
}
}
impl std::default::Default for Cpu {
fn default() -> Self {
Self {
A: 0x00,
X: 0x00,
Y: 0x00,
PC: 0x0000,
flags: 0b_0010_0000,
}
}
}
impl std::fmt::Debug for Cpu {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
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
)
}
}

194
src/sixty_five/emulator.rs Normal file
View File

@ -0,0 +1,194 @@
use super::cpu::{Cpu, Flags};
use super::error;
use super::opcodes;
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;
macro_rules! fetch {
($self:ident PC+$off:expr) => {
$self.ram[$self.cpu.PC as usize + $off]
};
($self:ident $addr:expr) => {
$self.ram[$addr as usize]
};
($self:ident D $addr:expr) => {
($self.ram[$addr as usize + 1] as u16) << 8 | $self.ram[$addr as usize] as u16
};
}
macro_rules! operation {
($self:ident A+$b:expr) => {
$self.cpu.A.wrapping_add($b as u8)
};
($self:ident X+$b:expr) => {
$self.cpu.X.wrapping_add($b as u8)
};
(unwrap $arg:ident $addr:ident) => {
$arg.unwrap_or_else(|| invalid_mode($addr.addr_mode))
};
}
pub struct Emulator {
pub cycles: usize,
pub ram: [u8; 0x10000],
pub cpu: Cpu,
}
impl Emulator {
pub fn new() -> Self {
Self {
cycles: 0,
ram: [0x00; 0x10000],
cpu: Cpu::default(),
}
}
pub fn init(&mut self) -> Result<(), error::EmulatorError> {
let lo: u16 = self.ram[RESET_VEC_ADDR] as u16;
let hi: u16 = self.ram[RESET_VEC_ADDR + 1] as u16;
let addr = hi << 8 | lo;
self.cpu.PC = addr;
Ok(())
}
pub fn step(&mut self) -> Result<(), error::EmulatorError> {
if self.cycles == 0 {
println!("Initializing");
self.init()?;
}
if self.cpu.test(Flags::Break) {
return Err(error::EmulatorError::Break);
}
println!("Step on {:04X}", self.cpu.PC);
let code = self.ram[self.cpu.PC as usize];
let code = match opcodes::from_code(code) {
None => return Err(error::EmulatorError::UnknownOp(code)),
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
let addr = self.cpu.PC as usize + 1;
Some(fetch!(self D addr) as u16)
}
AddressingMode::ZPG => {
// Next byte is an address from the range 0x0000-0x00FF
let addr = self.cpu.PC as usize + 1;
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 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.cpu.PC as usize as isize;
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");
println!("{:#?}", self.cpu);
return Err(error::EmulatorError::Break);
}
OpcodeType::NOP => {}
OpcodeType::LDA => match code.addr_mode {
AddressingMode::IMM => self.cpu.set_a(operation!(unwrap arg code) as u8),
AddressingMode::ABS => self.cpu.set_a(fetch!(self operation!(unwrap arg code))),
AddressingMode::ZPG => self.cpu.set_a(fetch!(self operation!(unwrap arg code))),
_ => panic!("Invalid addressing mode for {:?}", code.name),
},
OpcodeType::STA => match code.addr_mode {
AddressingMode::ABS => self.ram[operation!(unwrap arg code) as usize] = self.cpu.A,
AddressingMode::ZPG => self.ram[operation!(unwrap arg code) as usize] = self.cpu.A,
AddressingMode::INDX => self.ram[operation!(unwrap arg code) as usize] = self.cpu.A,
_ => panic!("Invalid addressing mode for {:?}", code.name),
},
OpcodeType::ADC => match code.addr_mode {
AddressingMode::IMM => self.cpu.add_a(operation!(unwrap arg code) as u8),
_ => panic!("Invalid addressing mode for {:?}", code.name),
},
OpcodeType::JMP => match code.addr_mode {
AddressingMode::ABS => self.cpu.PC = operation!(unwrap arg code) as u16,
_ => panic!("Invalid addressing mode for {:?}", code.name),
},
OpcodeType::BEQ if code.addr_mode == AddressingMode::REL => {
if self.cpu.test(Flags::Zero) {
self.cpu.PC = operation!(unwrap arg code);
branch_taken = true;
}
}
OpcodeType::BNE if code.addr_mode == AddressingMode::REL => {
if !self.cpu.test(Flags::Zero) {
self.cpu.PC = operation!(unwrap arg code);
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 {
self.cpu.PC += get_size(code.addr_mode) as u16;
}
self.cycles += 1;
Ok(())
}
pub fn restart(&mut self) {
self.cycles = 0;
self.ram = [0x00; 0x10000];
self.cpu = Cpu::default();
}
}
mod test {
#[test]
fn test_flags() {
use super::{Cpu, Flags};
let mut cpu: Cpu = Cpu::default();
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);
}
}

25
src/sixty_five/error.rs Normal file
View File

@ -0,0 +1,25 @@
use std::boxed::Box;
use std::error::Error;
use std::fmt::{Display, Error as FmtError, Formatter};
#[derive(Debug)]
pub enum EmulatorError {
UnknownOp(u8),
Break,
Suberror(Box<dyn Error>),
}
impl Display for EmulatorError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
f,
"Emulator Error: {}",
match self {
EmulatorError::Suberror(e) => e.description().to_string(),
EmulatorError::Break => "Emulator Terminated".to_string(),
EmulatorError::UnknownOp(code) => format!("Unknown OP with code {:02X}", code),
}
)
}
}
impl Error for EmulatorError {}

9
src/sixty_five/mod.rs Normal file
View File

@ -0,0 +1,9 @@
pub mod error;
mod addressing_modes;
use addressing_modes::AddressingMode;
mod opcodes;
use opcodes::OpcodeType;
mod cpu;
mod emulator;
pub use emulator::Emulator;

883
src/sixty_five/opcodes.rs Normal file
View File

@ -0,0 +1,883 @@
use super::addressing_modes::AddressingMode;
pub const OPCODES: [Option<OpcodeData>; 0x100] = [
Some(OpcodeData {
name: OpcodeType::BRK,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::ORA,
addr_mode: AddressingMode::INDX,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::ORA,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::ASL,
addr_mode: AddressingMode::ZPG,
}),
None,
Some(OpcodeData {
name: OpcodeType::PHP,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::ORA,
addr_mode: AddressingMode::IMM,
}),
Some(OpcodeData {
name: OpcodeType::ASL,
addr_mode: AddressingMode::A,
}),
None,
None,
Some(OpcodeData {
name: OpcodeType::ORA,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::ASL,
addr_mode: AddressingMode::ABS,
}),
None,
Some(OpcodeData {
name: OpcodeType::BPL,
addr_mode: AddressingMode::REL,
}),
Some(OpcodeData {
name: OpcodeType::ORA,
addr_mode: AddressingMode::INDY,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::ORA,
addr_mode: AddressingMode::ZPGX,
}),
Some(OpcodeData {
name: OpcodeType::ASL,
addr_mode: AddressingMode::ZPGX,
}),
None,
Some(OpcodeData {
name: OpcodeType::CLC,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::ORA,
addr_mode: AddressingMode::ABSY,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::ORA,
addr_mode: AddressingMode::ABSX,
}),
Some(OpcodeData {
name: OpcodeType::ASL,
addr_mode: AddressingMode::ABSX,
}),
None,
Some(OpcodeData {
name: OpcodeType::JSR,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::AND,
addr_mode: AddressingMode::INDX,
}),
None,
None,
Some(OpcodeData {
name: OpcodeType::BIT,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::AND,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::ROL,
addr_mode: AddressingMode::ZPG,
}),
None,
Some(OpcodeData {
name: OpcodeType::PLP,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::AND,
addr_mode: AddressingMode::IMM,
}),
Some(OpcodeData {
name: OpcodeType::ROL,
addr_mode: AddressingMode::A,
}),
None,
Some(OpcodeData {
name: OpcodeType::BIT,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::AND,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::ROL,
addr_mode: AddressingMode::ABS,
}),
None,
Some(OpcodeData {
name: OpcodeType::BMI,
addr_mode: AddressingMode::REL,
}),
Some(OpcodeData {
name: OpcodeType::AND,
addr_mode: AddressingMode::INDY,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::AND,
addr_mode: AddressingMode::ZPGX,
}),
Some(OpcodeData {
name: OpcodeType::ROL,
addr_mode: AddressingMode::ZPGX,
}),
None,
Some(OpcodeData {
name: OpcodeType::SEC,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::AND,
addr_mode: AddressingMode::ABSY,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::AND,
addr_mode: AddressingMode::ABSX,
}),
Some(OpcodeData {
name: OpcodeType::ROL,
addr_mode: AddressingMode::ABSX,
}),
None,
Some(OpcodeData {
name: OpcodeType::RTI,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::EOR,
addr_mode: AddressingMode::INDX,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::EOR,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::LSR,
addr_mode: AddressingMode::ZPG,
}),
None,
Some(OpcodeData {
name: OpcodeType::PHA,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::EOR,
addr_mode: AddressingMode::IMM,
}),
Some(OpcodeData {
name: OpcodeType::LSR,
addr_mode: AddressingMode::A,
}),
None,
Some(OpcodeData {
name: OpcodeType::JMP,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::EOR,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::LSR,
addr_mode: AddressingMode::ABS,
}),
None,
Some(OpcodeData {
name: OpcodeType::BVC,
addr_mode: AddressingMode::REL,
}),
Some(OpcodeData {
name: OpcodeType::EOR,
addr_mode: AddressingMode::INDY,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::EOR,
addr_mode: AddressingMode::ZPGX,
}),
Some(OpcodeData {
name: OpcodeType::LSR,
addr_mode: AddressingMode::ZPGX,
}),
None,
Some(OpcodeData {
name: OpcodeType::CLI,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::EOR,
addr_mode: AddressingMode::ABSY,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::EOR,
addr_mode: AddressingMode::ABSX,
}),
Some(OpcodeData {
name: OpcodeType::LSR,
addr_mode: AddressingMode::ABSX,
}),
None,
Some(OpcodeData {
name: OpcodeType::RTS,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::ADC,
addr_mode: AddressingMode::INDX,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::ADC,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::ROR,
addr_mode: AddressingMode::ZPG,
}),
None,
Some(OpcodeData {
name: OpcodeType::PLA,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::ADC,
addr_mode: AddressingMode::IMM,
}),
Some(OpcodeData {
name: OpcodeType::ROR,
addr_mode: AddressingMode::A,
}),
None,
Some(OpcodeData {
name: OpcodeType::JMP,
addr_mode: AddressingMode::IND,
}),
Some(OpcodeData {
name: OpcodeType::ADC,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::ROR,
addr_mode: AddressingMode::ABS,
}),
None,
Some(OpcodeData {
name: OpcodeType::BVS,
addr_mode: AddressingMode::REL,
}),
Some(OpcodeData {
name: OpcodeType::ADC,
addr_mode: AddressingMode::INDY,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::ADC,
addr_mode: AddressingMode::ZPGX,
}),
Some(OpcodeData {
name: OpcodeType::ROR,
addr_mode: AddressingMode::ZPGX,
}),
None,
Some(OpcodeData {
name: OpcodeType::SEI,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::ADC,
addr_mode: AddressingMode::ABSY,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::ADC,
addr_mode: AddressingMode::ABSX,
}),
Some(OpcodeData {
name: OpcodeType::ROR,
addr_mode: AddressingMode::ABSX,
}),
None,
None,
Some(OpcodeData {
name: OpcodeType::STA,
addr_mode: AddressingMode::INDX,
}),
None,
None,
Some(OpcodeData {
name: OpcodeType::STY,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::STA,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::STX,
addr_mode: AddressingMode::ZPG,
}),
None,
Some(OpcodeData {
name: OpcodeType::DEY,
addr_mode: AddressingMode::IMPL,
}),
None,
Some(OpcodeData {
name: OpcodeType::TXA,
addr_mode: AddressingMode::IMPL,
}),
None,
Some(OpcodeData {
name: OpcodeType::STY,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::STA,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::STX,
addr_mode: AddressingMode::ABS,
}),
None,
Some(OpcodeData {
name: OpcodeType::BCC,
addr_mode: AddressingMode::REL,
}),
Some(OpcodeData {
name: OpcodeType::STA,
addr_mode: AddressingMode::INDY,
}),
None,
None,
Some(OpcodeData {
name: OpcodeType::STY,
addr_mode: AddressingMode::ZPGX,
}),
Some(OpcodeData {
name: OpcodeType::STA,
addr_mode: AddressingMode::ZPGX,
}),
Some(OpcodeData {
name: OpcodeType::STX,
addr_mode: AddressingMode::ZPGY,
}),
None,
Some(OpcodeData {
name: OpcodeType::TYA,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::STA,
addr_mode: AddressingMode::ABSY,
}),
Some(OpcodeData {
name: OpcodeType::TXS,
addr_mode: AddressingMode::IMPL,
}),
None,
None,
Some(OpcodeData {
name: OpcodeType::STA,
addr_mode: AddressingMode::ABSX,
}),
None,
None,
Some(OpcodeData {
name: OpcodeType::LDY,
addr_mode: AddressingMode::IMM,
}),
Some(OpcodeData {
name: OpcodeType::LDA,
addr_mode: AddressingMode::INDX,
}),
Some(OpcodeData {
name: OpcodeType::LDX,
addr_mode: AddressingMode::IMM,
}),
None,
Some(OpcodeData {
name: OpcodeType::LDY,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::LDA,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::LDX,
addr_mode: AddressingMode::ZPG,
}),
None,
Some(OpcodeData {
name: OpcodeType::TAY,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::LDA,
addr_mode: AddressingMode::IMM,
}),
Some(OpcodeData {
name: OpcodeType::TAX,
addr_mode: AddressingMode::IMPL,
}),
None,
Some(OpcodeData {
name: OpcodeType::LDY,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::LDA,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::LDX,
addr_mode: AddressingMode::ABS,
}),
None,
Some(OpcodeData {
name: OpcodeType::BCS,
addr_mode: AddressingMode::REL,
}),
Some(OpcodeData {
name: OpcodeType::LDA,
addr_mode: AddressingMode::INDY,
}),
None,
None,
Some(OpcodeData {
name: OpcodeType::LDY,
addr_mode: AddressingMode::ZPGX,
}),
Some(OpcodeData {
name: OpcodeType::LDA,
addr_mode: AddressingMode::ZPGX,
}),
Some(OpcodeData {
name: OpcodeType::LDX,
addr_mode: AddressingMode::ZPGY,
}),
None,
Some(OpcodeData {
name: OpcodeType::CLV,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::LDA,
addr_mode: AddressingMode::ABSY,
}),
Some(OpcodeData {
name: OpcodeType::TSX,
addr_mode: AddressingMode::IMPL,
}),
None,
Some(OpcodeData {
name: OpcodeType::LDY,
addr_mode: AddressingMode::ABSX,
}),
Some(OpcodeData {
name: OpcodeType::LDA,
addr_mode: AddressingMode::ABSX,
}),
Some(OpcodeData {
name: OpcodeType::LDX,
addr_mode: AddressingMode::ABSY,
}),
None,
Some(OpcodeData {
name: OpcodeType::CPY,
addr_mode: AddressingMode::IMM,
}),
Some(OpcodeData {
name: OpcodeType::CMP,
addr_mode: AddressingMode::INDX,
}),
None,
None,
Some(OpcodeData {
name: OpcodeType::CPY,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::CMP,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::DEC,
addr_mode: AddressingMode::ZPG,
}),
None,
Some(OpcodeData {
name: OpcodeType::INY,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::CMP,
addr_mode: AddressingMode::IMM,
}),
Some(OpcodeData {
name: OpcodeType::DEX,
addr_mode: AddressingMode::IMPL,
}),
None,
Some(OpcodeData {
name: OpcodeType::CPY,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::CMP,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::DEC,
addr_mode: AddressingMode::ABS,
}),
None,
Some(OpcodeData {
name: OpcodeType::BNE,
addr_mode: AddressingMode::REL,
}),
Some(OpcodeData {
name: OpcodeType::CMP,
addr_mode: AddressingMode::INDY,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::CMP,
addr_mode: AddressingMode::ZPGX,
}),
Some(OpcodeData {
name: OpcodeType::DEC,
addr_mode: AddressingMode::ZPGX,
}),
None,
Some(OpcodeData {
name: OpcodeType::CLD,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::CMP,
addr_mode: AddressingMode::ABSY,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::CMP,
addr_mode: AddressingMode::ABSX,
}),
Some(OpcodeData {
name: OpcodeType::DEC,
addr_mode: AddressingMode::ABSX,
}),
None,
Some(OpcodeData {
name: OpcodeType::CPX,
addr_mode: AddressingMode::IMM,
}),
Some(OpcodeData {
name: OpcodeType::SBC,
addr_mode: AddressingMode::INDX,
}),
None,
None,
Some(OpcodeData {
name: OpcodeType::CPX,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::SBC,
addr_mode: AddressingMode::ZPG,
}),
Some(OpcodeData {
name: OpcodeType::INC,
addr_mode: AddressingMode::ZPG,
}),
None,
Some(OpcodeData {
name: OpcodeType::INX,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::SBC,
addr_mode: AddressingMode::IMM,
}),
Some(OpcodeData {
name: OpcodeType::NOP,
addr_mode: AddressingMode::IMPL,
}),
None,
Some(OpcodeData {
name: OpcodeType::CPX,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::SBC,
addr_mode: AddressingMode::ABS,
}),
Some(OpcodeData {
name: OpcodeType::INC,
addr_mode: AddressingMode::ABS,
}),
None,
Some(OpcodeData {
name: OpcodeType::BEQ,
addr_mode: AddressingMode::REL,
}),
Some(OpcodeData {
name: OpcodeType::SBC,
addr_mode: AddressingMode::INDY,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::SBC,
addr_mode: AddressingMode::ZPGX,
}),
Some(OpcodeData {
name: OpcodeType::INC,
addr_mode: AddressingMode::ZPGX,
}),
None,
Some(OpcodeData {
name: OpcodeType::SED,
addr_mode: AddressingMode::IMPL,
}),
Some(OpcodeData {
name: OpcodeType::SBC,
addr_mode: AddressingMode::ABSY,
}),
None,
None,
None,
Some(OpcodeData {
name: OpcodeType::SBC,
addr_mode: AddressingMode::ABSX,
}),
Some(OpcodeData {
name: OpcodeType::INC,
addr_mode: AddressingMode::ABSX,
}),
None,
];
/* pub fn get_code(name: OpcodeType, addr_mode: AddressingMode) -> Result<u8, Error> {
for (i, opcode) in OPCODES.iter().enumerate() {
match opcode {
None => continue,
Some(ref opcode) => {
if opcode.name == name && opcode.addr_mode == addr_mode {
return Ok((i & 0xFF) as u8);
}
}
}
}
Err(Error::UnkownOpcode { name: name.into() })
} */
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum OpcodeType {
ADC,
AND,
ASL,
BCC, // Branch ops
BCS, // Branch ops
BEQ, // Branch ops
BIT,
BMI, // Branch ops
BNE, // Branch ops
BPL, // Branch ops
BRK,
BVC, // Branch ops
BVS, // Branch ops
CLC,
CLD,
CLI,
CLV,
CMP,
CPX,
CPY,
DEC,
DEX,
DEY,
EOR,
INC,
INX,
INY,
JMP,
JSR,
LDA,
LDX,
LDY,
LSR,
NOP,
ORA,
PHA,
PHP,
PLA,
PLP,
ROL,
ROR,
RTI,
RTS,
SBC,
SEC,
SED,
SEI,
STA,
STX,
STY,
TAX,
TAY,
TSX,
TXA,
TXS,
TYA,
}
impl OpcodeType {
pub fn identify<'s, S: std::ops::Deref<Target = &'s str>>(
string: &S,
) -> Result<OpcodeType, ()> {
match **string {
"ADC" => Ok(OpcodeType::ADC),
"AND" => Ok(OpcodeType::AND),
"ASL" => Ok(OpcodeType::ASL),
"BCC" => Ok(OpcodeType::BCC),
"BCS" => Ok(OpcodeType::BCS),
"BEQ" => Ok(OpcodeType::BEQ),
"BIT" => Ok(OpcodeType::BIT),
"BMI" => Ok(OpcodeType::BMI),
"BNE" => Ok(OpcodeType::BNE),
"BPL" => Ok(OpcodeType::BPL),
"BRK" => Ok(OpcodeType::BRK),
"BVC" => Ok(OpcodeType::BVC),
"BVS" => Ok(OpcodeType::BVS),
"CLC" => Ok(OpcodeType::CLC),
"CLD" => Ok(OpcodeType::CLD),
"CLI" => Ok(OpcodeType::CLI),
"CLV" => Ok(OpcodeType::CLV),
"CMP" => Ok(OpcodeType::CMP),
"CPX" => Ok(OpcodeType::CPX),
"CPY" => Ok(OpcodeType::CPY),
"DEC" => Ok(OpcodeType::DEC),
"DEX" => Ok(OpcodeType::DEX),
"DEY" => Ok(OpcodeType::DEY),
"EOR" => Ok(OpcodeType::EOR),
"INC" => Ok(OpcodeType::INC),
"INX" => Ok(OpcodeType::INX),
"INY" => Ok(OpcodeType::INY),
"JMP" => Ok(OpcodeType::JMP),
"JSR" => Ok(OpcodeType::JSR),
"LDA" => Ok(OpcodeType::LDA),
"LDX" => Ok(OpcodeType::LDX),
"LDY" => Ok(OpcodeType::LDY),
"LSR" => Ok(OpcodeType::LSR),
"NOP" => Ok(OpcodeType::NOP),
"ORA" => Ok(OpcodeType::ORA),
"PHA" => Ok(OpcodeType::PHA),
"PHP" => Ok(OpcodeType::PHP),
"PLA" => Ok(OpcodeType::PLA),
"PLP" => Ok(OpcodeType::PLP),
"ROL" => Ok(OpcodeType::ROL),
"ROR" => Ok(OpcodeType::ROR),
"RTI" => Ok(OpcodeType::RTI),
"RTS" => Ok(OpcodeType::RTS),
"SBC" => Ok(OpcodeType::SBC),
"SEC" => Ok(OpcodeType::SEC),
"SED" => Ok(OpcodeType::SED),
"SEI" => Ok(OpcodeType::SEI),
"STA" => Ok(OpcodeType::STA),
"STX" => Ok(OpcodeType::STX),
"STY" => Ok(OpcodeType::STY),
"TAX" => Ok(OpcodeType::TAX),
"TAY" => Ok(OpcodeType::TAY),
"TSX" => Ok(OpcodeType::TSX),
"TXA" => Ok(OpcodeType::TXA),
"TXS" => Ok(OpcodeType::TXS),
"TYA" => Ok(OpcodeType::TYA),
_ => Err(()),
}
}
pub fn is_branch_op(self) -> bool {
use OpcodeType::*;
let branch_ops = [BCC, BCS, BEQ, BMI, BNE, BPL, BVC, BVS];
branch_ops.contains(&self)
}
}
impl std::convert::Into<String> for OpcodeType {
fn into(self) -> String {
format!("{:?}", self)
}
}
#[derive(Debug, Copy, Clone)]
pub struct OpcodeData {
pub name: OpcodeType,
pub addr_mode: AddressingMode,
}
pub fn from_code(code: u8) -> Option<OpcodeData> {
OPCODES[code as usize]
}
mod test {
#[test]
fn test_opcode_name() {
use super::OpcodeType;
let strings = vec![("LDA", true), ("STA", true), ("JMP", true), ("xd", false)];
for (string, is_ok) in strings.iter() {
let res = OpcodeType::identify(&string);
println!("{} -> {:?}", string, res);
assert_eq!(res.is_ok(), *is_ok);
}
}
}

56
src/sixty_five/ops Normal file
View File

@ -0,0 +1,56 @@
ADC 011A AA01
AND 001A AA01
ASL 000A AA10
BCC 1001 0000
BCS 1011 0000
BEQ 1111 0000
BIT 0010 A100
BMI 0011 0000
BNE 1101 0000
BPL 0001 0000
BRK 0000 0000
BVC 0101 0000
BVS 0111 0000
CLC 0001 1000
CLD 1101 1000
CLI 0101 1000
CLV 1011 1000
CMP 110A AA01
CPA 1110 AA00
CPY 1100 AA00
DEC 110A A110
DEA 1100 1010
DEY 1000 1000
EOR 010A AA01
INC 111A A110
INA 1110 1000
INY 1100 1000
JMP 01A0 1100
JSR 0010 0000
LDA 10AA AA01
LDA 101A AA10
LDY 101A AA00
LSR 010A AA10
NOP 1110 1010
ORA 000A AA01
PHA 0100 1000
PHP 0000 1000
PLA 0110 1000
PLP 0010 1000
ROL 001A AA10
ROR 011A AA10
RTI 0100 0000
RTS 0110 0000
SBC 111A AA01
SEC 0011 1000
SED 1111 1000
SEI 0111 0000
STA 100A AA01
STA 100A A110
STY 100A A100
TAA 1010 1010
TAY 1010 1000
TSA 1011 1010
TAA 1000 1010
TAS 1001 1010
TYA 1001 1000