mirror of
https://github.com/balt-dev/r6502.git
synced 2024-12-12 01:29:56 +00:00
Format
This commit is contained in:
parent
7f40ffc5ee
commit
e6050511f0
101
src/emulation.rs
101
src/emulation.rs
@ -21,8 +21,9 @@ pub trait WriteCallback {
|
||||
/// A helper for easily creating simple implementations of [`ReadCallback`].
|
||||
pub struct FunctionReadCallback<F>(pub F);
|
||||
|
||||
impl<F> ReadCallback for FunctionReadCallback<F> where
|
||||
F: FnMut(&mut State, u16) -> u8
|
||||
impl<F> ReadCallback for FunctionReadCallback<F>
|
||||
where
|
||||
F: FnMut(&mut State, u16) -> u8,
|
||||
{
|
||||
fn callback(&mut self, state: &mut State, address: u16) -> u8 {
|
||||
self.0(state, address)
|
||||
@ -32,8 +33,9 @@ impl<F> ReadCallback for FunctionReadCallback<F> where
|
||||
/// A helper for easily creating simple implementations of [`WriteCallback`].
|
||||
pub struct FunctionWriteCallback<F>(pub F);
|
||||
|
||||
impl<F> WriteCallback for FunctionWriteCallback<F> where
|
||||
F: FnMut(&mut State, u16, u8)
|
||||
impl<F> WriteCallback for FunctionWriteCallback<F>
|
||||
where
|
||||
F: FnMut(&mut State, u16, u8),
|
||||
{
|
||||
fn callback(&mut self, state: &mut State, address: u16, byte: u8) {
|
||||
self.0(state, address, byte);
|
||||
@ -116,7 +118,8 @@ impl<R: ReadCallback, W: WriteCallback> Emulator<R, W> {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn with_rom_from(mut self, slice: &[u8], location: u16) -> Self {
|
||||
self.state.memory[location as usize..location as usize + slice.len()].copy_from_slice(slice);
|
||||
self.state.memory[location as usize..location as usize + slice.len()]
|
||||
.copy_from_slice(slice);
|
||||
self
|
||||
}
|
||||
|
||||
@ -181,7 +184,6 @@ impl<R: ReadCallback, W: WriteCallback> Emulator<R, W> {
|
||||
self.read(0x100 + u16::from(self.state.stack_pointer))
|
||||
}
|
||||
|
||||
|
||||
/// Sets a callback to be called when memory is read from, allowing for memory-mapped reads.
|
||||
/// See [`ReadCallback`].
|
||||
#[inline]
|
||||
@ -190,7 +192,7 @@ impl<R: ReadCallback, W: WriteCallback> Emulator<R, W> {
|
||||
Emulator {
|
||||
state: self.state,
|
||||
read_callback: callback,
|
||||
write_callback: self.write_callback
|
||||
write_callback: self.write_callback,
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,7 +204,7 @@ impl<R: ReadCallback, W: WriteCallback> Emulator<R, W> {
|
||||
Emulator {
|
||||
state: self.state,
|
||||
read_callback: self.read_callback,
|
||||
write_callback: callback
|
||||
write_callback: callback,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -212,14 +214,15 @@ impl Default for Emulator<DefaultReadCallback, DefaultWriteCallback> {
|
||||
Self {
|
||||
state: State::default(),
|
||||
read_callback: DefaultReadCallback,
|
||||
write_callback: DefaultWriteCallback
|
||||
write_callback: DefaultWriteCallback,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[allow(clippy::missing_fields_in_debug)]
|
||||
impl<R: ReadCallback + core::fmt::Debug, W: WriteCallback + core::fmt::Debug> core::fmt::Debug for Emulator<R, W> {
|
||||
impl<R: ReadCallback + core::fmt::Debug, W: WriteCallback + core::fmt::Debug> core::fmt::Debug
|
||||
for Emulator<R, W>
|
||||
{
|
||||
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
fmt.debug_struct("Emulator")
|
||||
.field("state", &self.state)
|
||||
@ -242,7 +245,10 @@ impl<R: ReadCallback, W: WriteCallback> Emulator<R, W> {
|
||||
Some(match mode {
|
||||
Absolute(addr) => addr,
|
||||
ZeroPage(addr) => u16::from(addr),
|
||||
Relative(offset) => self.state.program_counter.wrapping_add_signed(i16::from(offset)),
|
||||
Relative(offset) => self
|
||||
.state
|
||||
.program_counter
|
||||
.wrapping_add_signed(i16::from(offset)),
|
||||
AbsoluteIndirect(addr) => {
|
||||
let high = self.read(addr);
|
||||
let low = self.read(addr.wrapping_add(1));
|
||||
@ -384,13 +390,19 @@ impl<R: ReadCallback, W: WriteCallback> Emulator<R, W> {
|
||||
|
||||
let (high_lhs, low_lhs) = to_bcd_nibbles(lhs);
|
||||
let (high_rhs, low_rhs) = to_bcd_nibbles(rhs);
|
||||
let low_sum = low_lhs + low_rhs + u8::from(self.state.status.contains(Status::CARRY));
|
||||
let low_sum =
|
||||
low_lhs + low_rhs + u8::from(self.state.status.contains(Status::CARRY));
|
||||
let (low_carry, low) = (low_sum / 10, low_sum % 10);
|
||||
let high_sum = high_lhs + high_rhs + low_carry;
|
||||
let (sum, carry) = from_bcd_nibbles(low, high_sum);
|
||||
self.state.status.set(Status::CARRY, carry);
|
||||
let overflow_sum = u16::from(from_bcd(lhs)) + u16::from(from_bcd(rhs)) + u16::from(self.state.status.contains(Status::CARRY));
|
||||
self.state.status.set(Status::OVERFLOW, (lhs & 0x80) != (overflow_sum & 0x80) as u8);
|
||||
let overflow_sum = u16::from(from_bcd(lhs))
|
||||
+ u16::from(from_bcd(rhs))
|
||||
+ u16::from(self.state.status.contains(Status::CARRY));
|
||||
self.state.status.set(
|
||||
Status::OVERFLOW,
|
||||
(lhs & 0x80) != (overflow_sum & 0x80) as u8,
|
||||
);
|
||||
self.state.status.set(Status::ZERO, sum == 0);
|
||||
self.state.status.set(Status::NEGATIVE, (sum as i8) < 0);
|
||||
self.state.accumulator = sum;
|
||||
@ -405,7 +417,9 @@ impl<R: ReadCallback, W: WriteCallback> Emulator<R, W> {
|
||||
|
||||
let (high_lhs, low_lhs) = to_bcd_nibbles(lhs);
|
||||
let (high_rhs, low_rhs) = to_bcd_nibbles(rhs);
|
||||
let mut low = low_lhs as i8 - low_rhs as i8 - i8::from(!self.state.status.contains(Status::CARRY));
|
||||
let mut low = low_lhs as i8
|
||||
- low_rhs as i8
|
||||
- i8::from(!self.state.status.contains(Status::CARRY));
|
||||
let mut low_borrow = 0;
|
||||
if low < 0 {
|
||||
low += 10;
|
||||
@ -493,18 +507,22 @@ impl<R: ReadCallback, W: WriteCallback> Emulator<R, W> {
|
||||
let byte = self.byte(mode);
|
||||
let result = self.state.accumulator & byte;
|
||||
self.state.status.set(Status::ZERO, result == 0);
|
||||
self.state.status.set(Status::NEGATIVE, byte & 0b1000_0000 != 0);
|
||||
self.state.status.set(Status::OVERFLOW, byte & 0b0100_0000 != 0);
|
||||
self.state
|
||||
.status
|
||||
.set(Status::NEGATIVE, byte & 0b1000_0000 != 0);
|
||||
self.state
|
||||
.status
|
||||
.set(Status::OVERFLOW, byte & 0b0100_0000 != 0);
|
||||
})?,
|
||||
CMP => opcode.address_mode.map(|mode|
|
||||
self.compare(self.state.accumulator, mode)
|
||||
)?,
|
||||
CPX => opcode.address_mode.map(|mode|
|
||||
self.compare(self.state.x_register, mode)
|
||||
)?,
|
||||
CPY => opcode.address_mode.map(|mode|
|
||||
self.compare(self.state.y_register, mode)
|
||||
)?,
|
||||
CMP => opcode
|
||||
.address_mode
|
||||
.map(|mode| self.compare(self.state.accumulator, mode))?,
|
||||
CPX => opcode
|
||||
.address_mode
|
||||
.map(|mode| self.compare(self.state.x_register, mode))?,
|
||||
CPY => opcode
|
||||
.address_mode
|
||||
.map(|mode| self.compare(self.state.y_register, mode))?,
|
||||
inst @ (BCC | BNE | BPL | BVC | BCS | BEQ | BMI | BVS) => {
|
||||
opcode.address_mode.and_then(|mode| {
|
||||
let mask = match inst {
|
||||
@ -531,7 +549,7 @@ impl<R: ReadCallback, W: WriteCallback> Emulator<R, W> {
|
||||
PLA => {
|
||||
let new_acc = self.pop();
|
||||
self.state.accumulator = self.set_flags(new_acc);
|
||||
},
|
||||
}
|
||||
PHP => self.push((self.state.status | Status::UNUSED | Status::BREAK).bits()),
|
||||
PLP => self.state.status = Status::from_bits_retain(self.pop()) | Status::UNUSED,
|
||||
JMP => opcode.address_mode.and_then(|mode| {
|
||||
@ -540,11 +558,12 @@ impl<R: ReadCallback, W: WriteCallback> Emulator<R, W> {
|
||||
Some(())
|
||||
})?,
|
||||
JSR => opcode.address_mode.and_then(|mode| {
|
||||
let [high, low] =
|
||||
self.state.program_counter
|
||||
.wrapping_add(u16::from(opcode_length))
|
||||
.wrapping_sub(1)
|
||||
.to_le_bytes();
|
||||
let [high, low] = self
|
||||
.state
|
||||
.program_counter
|
||||
.wrapping_add(u16::from(opcode_length))
|
||||
.wrapping_sub(1)
|
||||
.to_le_bytes();
|
||||
self.state.program_counter = self.addr(mode)?;
|
||||
self.push(low);
|
||||
self.push(high);
|
||||
@ -580,7 +599,10 @@ impl<R: ReadCallback, W: WriteCallback> Emulator<R, W> {
|
||||
}
|
||||
|
||||
if increment {
|
||||
self.state.program_counter = self.state.program_counter.wrapping_add(u16::from(opcode_length));
|
||||
self.state.program_counter = self
|
||||
.state
|
||||
.program_counter
|
||||
.wrapping_add(u16::from(opcode_length));
|
||||
}
|
||||
|
||||
Some(false)
|
||||
@ -617,16 +639,17 @@ impl<R: ReadCallback, W: WriteCallback> Emulator<R, W> {
|
||||
|
||||
/// Computes binary add with carry
|
||||
fn adc(&mut self, rhs: u8) -> u8 {
|
||||
let sum =
|
||||
u16::from(self.state.accumulator) +
|
||||
u16::from(rhs) +
|
||||
u16::from(self.state.status.contains(Status::CARRY));
|
||||
let sum = u16::from(self.state.accumulator)
|
||||
+ u16::from(rhs)
|
||||
+ u16::from(self.state.status.contains(Status::CARRY));
|
||||
|
||||
let acc = u16::from(self.state.accumulator);
|
||||
let rhs = u16::from(rhs);
|
||||
|
||||
self.state.status.set(Status::CARRY, sum > 0xFF);
|
||||
self.state.status.set(Status::OVERFLOW, !(acc ^ rhs) & (acc ^ sum) & 0x80 != 0);
|
||||
self.state
|
||||
.status
|
||||
.set(Status::OVERFLOW, !(acc ^ rhs) & (acc ^ sum) & 0x80 != 0);
|
||||
|
||||
let sum = sum as u8;
|
||||
|
||||
|
@ -51,7 +51,7 @@ impl fmt::Display for AddressMode {
|
||||
AddressMode::ZeroPageX(n) => write!(f, "${n:02X},X"),
|
||||
AddressMode::ZeroPageY(n) => write!(f, "${n:02X},Y"),
|
||||
AddressMode::ZeroPageIndirectX(n) => write!(f, "(${n:02X},X)"),
|
||||
AddressMode::ZeroPageYIndirect(n) => write!(f, "(${n:02X}),Y")
|
||||
AddressMode::ZeroPageYIndirect(n) => write!(f, "(${n:02X}),Y"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -179,7 +179,7 @@ pub enum Instruction {
|
||||
/// Forces a hardware interrupt.
|
||||
BRK,
|
||||
/// Does nothing.
|
||||
NOP
|
||||
NOP,
|
||||
}
|
||||
|
||||
impl Instruction {
|
||||
@ -222,7 +222,10 @@ impl Opcode {
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn new(instruction: Instruction, address_mode: Option<AddressMode>) -> Self {
|
||||
Self { instruction, address_mode }
|
||||
Self {
|
||||
instruction,
|
||||
address_mode,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,158 +381,157 @@ macro_rules! opcodes {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
opcodes! {
|
||||
Opcode::new(BRK, None) => 0x00,
|
||||
Opcode::new(ORA, Some(ZeroPageIndirectX)) => 0x01,
|
||||
Opcode::new(ORA, Some(ZeroPage)) => 0x05,
|
||||
Opcode::new(ASL, Some(ZeroPage)) => 0x06,
|
||||
Opcode::new(PHP, None) => 0x08,
|
||||
Opcode::new(ORA, Some(Immediate)) => 0x09,
|
||||
Opcode::new(ASL, Some(Accumulator)) => 0x0A,
|
||||
Opcode::new(ORA, Some(Absolute)) => 0x0D,
|
||||
Opcode::new(ASL, Some(Absolute)) => 0x0E,
|
||||
Opcode::new(ORA, Some(ZeroPageIndirectX)) => 0x01,
|
||||
Opcode::new(ORA, Some(ZeroPage)) => 0x05,
|
||||
Opcode::new(ASL, Some(ZeroPage)) => 0x06,
|
||||
Opcode::new(PHP, None) => 0x08,
|
||||
Opcode::new(ORA, Some(Immediate)) => 0x09,
|
||||
Opcode::new(ASL, Some(Accumulator)) => 0x0A,
|
||||
Opcode::new(ORA, Some(Absolute)) => 0x0D,
|
||||
Opcode::new(ASL, Some(Absolute)) => 0x0E,
|
||||
Opcode::new(BPL, Some(Relative)) => 0x10,
|
||||
Opcode::new(ORA, Some(ZeroPageYIndirect)) => 0x11,
|
||||
Opcode::new(ORA, Some(ZeroPageX)) => 0x15,
|
||||
Opcode::new(ASL, Some(ZeroPageX)) => 0x16,
|
||||
Opcode::new(CLC, None) => 0x18,
|
||||
Opcode::new(ORA, Some(AbsoluteY)) => 0x19,
|
||||
Opcode::new(ORA, Some(AbsoluteX)) => 0x1D,
|
||||
Opcode::new(ASL, Some(AbsoluteX)) => 0x1E,
|
||||
Opcode::new(ORA, Some(ZeroPageYIndirect)) => 0x11,
|
||||
Opcode::new(ORA, Some(ZeroPageX)) => 0x15,
|
||||
Opcode::new(ASL, Some(ZeroPageX)) => 0x16,
|
||||
Opcode::new(CLC, None) => 0x18,
|
||||
Opcode::new(ORA, Some(AbsoluteY)) => 0x19,
|
||||
Opcode::new(ORA, Some(AbsoluteX)) => 0x1D,
|
||||
Opcode::new(ASL, Some(AbsoluteX)) => 0x1E,
|
||||
Opcode::new(JSR, Some(Absolute)) => 0x20,
|
||||
Opcode::new(AND, Some(ZeroPageIndirectX)) => 0x21,
|
||||
Opcode::new(BIT, Some(ZeroPage)) => 0x24,
|
||||
Opcode::new(AND, Some(ZeroPage)) => 0x25,
|
||||
Opcode::new(ROL, Some(ZeroPage)) => 0x26,
|
||||
Opcode::new(PLP, None) => 0x28,
|
||||
Opcode::new(AND, Some(Immediate)) => 0x29,
|
||||
Opcode::new(ROL, Some(Accumulator)) => 0x2A,
|
||||
Opcode::new(BIT, Some(Absolute)) => 0x2C,
|
||||
Opcode::new(AND, Some(Absolute)) => 0x2D,
|
||||
Opcode::new(ROL, Some(Absolute)) => 0x2E,
|
||||
Opcode::new(AND, Some(ZeroPageIndirectX)) => 0x21,
|
||||
Opcode::new(BIT, Some(ZeroPage)) => 0x24,
|
||||
Opcode::new(AND, Some(ZeroPage)) => 0x25,
|
||||
Opcode::new(ROL, Some(ZeroPage)) => 0x26,
|
||||
Opcode::new(PLP, None) => 0x28,
|
||||
Opcode::new(AND, Some(Immediate)) => 0x29,
|
||||
Opcode::new(ROL, Some(Accumulator)) => 0x2A,
|
||||
Opcode::new(BIT, Some(Absolute)) => 0x2C,
|
||||
Opcode::new(AND, Some(Absolute)) => 0x2D,
|
||||
Opcode::new(ROL, Some(Absolute)) => 0x2E,
|
||||
Opcode::new(BMI, Some(Relative)) => 0x30,
|
||||
Opcode::new(AND, Some(ZeroPageYIndirect)) => 0x31,
|
||||
Opcode::new(AND, Some(ZeroPageX)) => 0x35,
|
||||
Opcode::new(ROL, Some(ZeroPageX)) => 0x36,
|
||||
Opcode::new(SEC, None) => 0x38,
|
||||
Opcode::new(AND, Some(AbsoluteY)) => 0x39,
|
||||
Opcode::new(AND, Some(AbsoluteX)) => 0x3D,
|
||||
Opcode::new(ROL, Some(AbsoluteX)) => 0x3E,
|
||||
Opcode::new(AND, Some(ZeroPageYIndirect)) => 0x31,
|
||||
Opcode::new(AND, Some(ZeroPageX)) => 0x35,
|
||||
Opcode::new(ROL, Some(ZeroPageX)) => 0x36,
|
||||
Opcode::new(SEC, None) => 0x38,
|
||||
Opcode::new(AND, Some(AbsoluteY)) => 0x39,
|
||||
Opcode::new(AND, Some(AbsoluteX)) => 0x3D,
|
||||
Opcode::new(ROL, Some(AbsoluteX)) => 0x3E,
|
||||
Opcode::new(RTI, None) => 0x40,
|
||||
Opcode::new(EOR, Some(ZeroPageIndirectX)) => 0x41,
|
||||
Opcode::new(EOR, Some(ZeroPage)) => 0x45,
|
||||
Opcode::new(LSR, Some(ZeroPage)) => 0x46,
|
||||
Opcode::new(PHA, None) => 0x48,
|
||||
Opcode::new(EOR, Some(Immediate)) => 0x49,
|
||||
Opcode::new(LSR, Some(Accumulator)) => 0x4A,
|
||||
Opcode::new(JMP, Some(Absolute)) => 0x4C,
|
||||
Opcode::new(EOR, Some(Absolute)) => 0x4D,
|
||||
Opcode::new(LSR, Some(Absolute)) => 0x4E,
|
||||
Opcode::new(EOR, Some(ZeroPageIndirectX)) => 0x41,
|
||||
Opcode::new(EOR, Some(ZeroPage)) => 0x45,
|
||||
Opcode::new(LSR, Some(ZeroPage)) => 0x46,
|
||||
Opcode::new(PHA, None) => 0x48,
|
||||
Opcode::new(EOR, Some(Immediate)) => 0x49,
|
||||
Opcode::new(LSR, Some(Accumulator)) => 0x4A,
|
||||
Opcode::new(JMP, Some(Absolute)) => 0x4C,
|
||||
Opcode::new(EOR, Some(Absolute)) => 0x4D,
|
||||
Opcode::new(LSR, Some(Absolute)) => 0x4E,
|
||||
Opcode::new(BVC, Some(Relative)) => 0x50,
|
||||
Opcode::new(EOR, Some(ZeroPageYIndirect)) => 0x51,
|
||||
Opcode::new(EOR, Some(ZeroPageX)) => 0x55,
|
||||
Opcode::new(LSR, Some(ZeroPageX)) => 0x56,
|
||||
Opcode::new(CLI, None) => 0x58,
|
||||
Opcode::new(EOR, Some(AbsoluteY)) => 0x59,
|
||||
Opcode::new(EOR, Some(AbsoluteX)) => 0x5D,
|
||||
Opcode::new(LSR, Some(AbsoluteX)) => 0x5E,
|
||||
Opcode::new(EOR, Some(ZeroPageYIndirect)) => 0x51,
|
||||
Opcode::new(EOR, Some(ZeroPageX)) => 0x55,
|
||||
Opcode::new(LSR, Some(ZeroPageX)) => 0x56,
|
||||
Opcode::new(CLI, None) => 0x58,
|
||||
Opcode::new(EOR, Some(AbsoluteY)) => 0x59,
|
||||
Opcode::new(EOR, Some(AbsoluteX)) => 0x5D,
|
||||
Opcode::new(LSR, Some(AbsoluteX)) => 0x5E,
|
||||
Opcode::new(RTS, None) => 0x60,
|
||||
Opcode::new(ADC, Some(ZeroPageIndirectX)) => 0x61,
|
||||
Opcode::new(ADC, Some(ZeroPage)) => 0x65,
|
||||
Opcode::new(ROR, Some(ZeroPage)) => 0x66,
|
||||
Opcode::new(PLA, None) => 0x68,
|
||||
Opcode::new(ADC, Some(Immediate)) => 0x69,
|
||||
Opcode::new(ROR, Some(Accumulator)) => 0x6A,
|
||||
Opcode::new(JMP, Some(AbsoluteIndirect)) => 0x6C,
|
||||
Opcode::new(ADC, Some(Absolute)) => 0x6D,
|
||||
Opcode::new(ROR, Some(Absolute)) => 0x6E,
|
||||
Opcode::new(ADC, Some(ZeroPageIndirectX)) => 0x61,
|
||||
Opcode::new(ADC, Some(ZeroPage)) => 0x65,
|
||||
Opcode::new(ROR, Some(ZeroPage)) => 0x66,
|
||||
Opcode::new(PLA, None) => 0x68,
|
||||
Opcode::new(ADC, Some(Immediate)) => 0x69,
|
||||
Opcode::new(ROR, Some(Accumulator)) => 0x6A,
|
||||
Opcode::new(JMP, Some(AbsoluteIndirect)) => 0x6C,
|
||||
Opcode::new(ADC, Some(Absolute)) => 0x6D,
|
||||
Opcode::new(ROR, Some(Absolute)) => 0x6E,
|
||||
Opcode::new(BVS, Some(Relative)) => 0x70,
|
||||
Opcode::new(ADC, Some(ZeroPageYIndirect)) => 0x71,
|
||||
Opcode::new(ADC, Some(ZeroPageX)) => 0x75,
|
||||
Opcode::new(ROR, Some(ZeroPageX)) => 0x76,
|
||||
Opcode::new(SEI, None) => 0x78,
|
||||
Opcode::new(ADC, Some(AbsoluteY)) => 0x79,
|
||||
Opcode::new(ADC, Some(AbsoluteX)) => 0x7D,
|
||||
Opcode::new(ROR, Some(AbsoluteX)) => 0x7E,
|
||||
Opcode::new(STA, Some(ZeroPageIndirectX)) => 0x81,
|
||||
Opcode::new(STY, Some(ZeroPage)) => 0x84,
|
||||
Opcode::new(STA, Some(ZeroPage)) => 0x85,
|
||||
Opcode::new(STX, Some(ZeroPage)) => 0x86,
|
||||
Opcode::new(DEY, None) => 0x88,
|
||||
Opcode::new(BIT, Some(Immediate)) => 0x89,
|
||||
Opcode::new(TXA, None) => 0x8A,
|
||||
Opcode::new(STY, Some(Absolute)) => 0x8C,
|
||||
Opcode::new(STA, Some(Absolute)) => 0x8D,
|
||||
Opcode::new(STX, Some(Absolute)) => 0x8E,
|
||||
Opcode::new(ADC, Some(ZeroPageYIndirect)) => 0x71,
|
||||
Opcode::new(ADC, Some(ZeroPageX)) => 0x75,
|
||||
Opcode::new(ROR, Some(ZeroPageX)) => 0x76,
|
||||
Opcode::new(SEI, None) => 0x78,
|
||||
Opcode::new(ADC, Some(AbsoluteY)) => 0x79,
|
||||
Opcode::new(ADC, Some(AbsoluteX)) => 0x7D,
|
||||
Opcode::new(ROR, Some(AbsoluteX)) => 0x7E,
|
||||
Opcode::new(STA, Some(ZeroPageIndirectX)) => 0x81,
|
||||
Opcode::new(STY, Some(ZeroPage)) => 0x84,
|
||||
Opcode::new(STA, Some(ZeroPage)) => 0x85,
|
||||
Opcode::new(STX, Some(ZeroPage)) => 0x86,
|
||||
Opcode::new(DEY, None) => 0x88,
|
||||
Opcode::new(BIT, Some(Immediate)) => 0x89,
|
||||
Opcode::new(TXA, None) => 0x8A,
|
||||
Opcode::new(STY, Some(Absolute)) => 0x8C,
|
||||
Opcode::new(STA, Some(Absolute)) => 0x8D,
|
||||
Opcode::new(STX, Some(Absolute)) => 0x8E,
|
||||
Opcode::new(BCC, Some(Relative)) => 0x90,
|
||||
Opcode::new(STA, Some(ZeroPageYIndirect)) => 0x91,
|
||||
Opcode::new(STY, Some(ZeroPageX)) => 0x94,
|
||||
Opcode::new(STA, Some(ZeroPageX)) => 0x95,
|
||||
Opcode::new(STX, Some(ZeroPageY)) => 0x96,
|
||||
Opcode::new(TYA, None) => 0x98,
|
||||
Opcode::new(STA, Some(AbsoluteY)) => 0x99,
|
||||
Opcode::new(TXS, None) => 0x9A,
|
||||
Opcode::new(STA, Some(AbsoluteX)) => 0x9D,
|
||||
Opcode::new(LDY, Some(Immediate)) => 0xA0,
|
||||
Opcode::new(LDA, Some(ZeroPageIndirectX)) => 0xA1,
|
||||
Opcode::new(LDX, Some(Immediate)) => 0xA2,
|
||||
Opcode::new(LDY, Some(ZeroPage)) => 0xA4,
|
||||
Opcode::new(LDA, Some(ZeroPage)) => 0xA5,
|
||||
Opcode::new(LDX, Some(ZeroPage)) => 0xA6,
|
||||
Opcode::new(TAY, None) => 0xA8,
|
||||
Opcode::new(LDA, Some(Immediate)) => 0xA9,
|
||||
Opcode::new(TAX, None) => 0xAA,
|
||||
Opcode::new(LDY, Some(Absolute)) => 0xAC,
|
||||
Opcode::new(LDA, Some(Absolute)) => 0xAD,
|
||||
Opcode::new(LDX, Some(Absolute)) => 0xAE,
|
||||
Opcode::new(STA, Some(ZeroPageYIndirect)) => 0x91,
|
||||
Opcode::new(STY, Some(ZeroPageX)) => 0x94,
|
||||
Opcode::new(STA, Some(ZeroPageX)) => 0x95,
|
||||
Opcode::new(STX, Some(ZeroPageY)) => 0x96,
|
||||
Opcode::new(TYA, None) => 0x98,
|
||||
Opcode::new(STA, Some(AbsoluteY)) => 0x99,
|
||||
Opcode::new(TXS, None) => 0x9A,
|
||||
Opcode::new(STA, Some(AbsoluteX)) => 0x9D,
|
||||
Opcode::new(LDY, Some(Immediate)) => 0xA0,
|
||||
Opcode::new(LDA, Some(ZeroPageIndirectX)) => 0xA1,
|
||||
Opcode::new(LDX, Some(Immediate)) => 0xA2,
|
||||
Opcode::new(LDY, Some(ZeroPage)) => 0xA4,
|
||||
Opcode::new(LDA, Some(ZeroPage)) => 0xA5,
|
||||
Opcode::new(LDX, Some(ZeroPage)) => 0xA6,
|
||||
Opcode::new(TAY, None) => 0xA8,
|
||||
Opcode::new(LDA, Some(Immediate)) => 0xA9,
|
||||
Opcode::new(TAX, None) => 0xAA,
|
||||
Opcode::new(LDY, Some(Absolute)) => 0xAC,
|
||||
Opcode::new(LDA, Some(Absolute)) => 0xAD,
|
||||
Opcode::new(LDX, Some(Absolute)) => 0xAE,
|
||||
Opcode::new(BCS, Some(Relative)) => 0xB0,
|
||||
Opcode::new(LDA, Some(ZeroPageYIndirect)) => 0xB1,
|
||||
Opcode::new(LDY, Some(ZeroPageX)) => 0xB4,
|
||||
Opcode::new(LDA, Some(ZeroPageX)) => 0xB5,
|
||||
Opcode::new(LDX, Some(ZeroPageY)) => 0xB6,
|
||||
Opcode::new(CLV, None) => 0xB8,
|
||||
Opcode::new(LDA, Some(AbsoluteY)) => 0xB9,
|
||||
Opcode::new(TSX, None) => 0xBA,
|
||||
Opcode::new(LDY, Some(AbsoluteX)) => 0xBC,
|
||||
Opcode::new(LDA, Some(AbsoluteX)) => 0xBD,
|
||||
Opcode::new(LDX, Some(AbsoluteY)) => 0xBE,
|
||||
Opcode::new(LDA, Some(ZeroPageYIndirect)) => 0xB1,
|
||||
Opcode::new(LDY, Some(ZeroPageX)) => 0xB4,
|
||||
Opcode::new(LDA, Some(ZeroPageX)) => 0xB5,
|
||||
Opcode::new(LDX, Some(ZeroPageY)) => 0xB6,
|
||||
Opcode::new(CLV, None) => 0xB8,
|
||||
Opcode::new(LDA, Some(AbsoluteY)) => 0xB9,
|
||||
Opcode::new(TSX, None) => 0xBA,
|
||||
Opcode::new(LDY, Some(AbsoluteX)) => 0xBC,
|
||||
Opcode::new(LDA, Some(AbsoluteX)) => 0xBD,
|
||||
Opcode::new(LDX, Some(AbsoluteY)) => 0xBE,
|
||||
Opcode::new(CPY, Some(Immediate)) => 0xC0,
|
||||
Opcode::new(CMP, Some(ZeroPageIndirectX)) => 0xC1,
|
||||
Opcode::new(CPY, Some(ZeroPage)) => 0xC4,
|
||||
Opcode::new(CMP, Some(ZeroPage)) => 0xC5,
|
||||
Opcode::new(DEC, Some(ZeroPage)) => 0xC6,
|
||||
Opcode::new(INY, None) => 0xC8,
|
||||
Opcode::new(CMP, Some(Immediate)) => 0xC9,
|
||||
Opcode::new(DEX, None) => 0xCA,
|
||||
Opcode::new(CPY, Some(Absolute)) => 0xCC,
|
||||
Opcode::new(CMP, Some(Absolute)) => 0xCD,
|
||||
Opcode::new(DEC, Some(Absolute)) => 0xCE,
|
||||
Opcode::new(CMP, Some(ZeroPageIndirectX)) => 0xC1,
|
||||
Opcode::new(CPY, Some(ZeroPage)) => 0xC4,
|
||||
Opcode::new(CMP, Some(ZeroPage)) => 0xC5,
|
||||
Opcode::new(DEC, Some(ZeroPage)) => 0xC6,
|
||||
Opcode::new(INY, None) => 0xC8,
|
||||
Opcode::new(CMP, Some(Immediate)) => 0xC9,
|
||||
Opcode::new(DEX, None) => 0xCA,
|
||||
Opcode::new(CPY, Some(Absolute)) => 0xCC,
|
||||
Opcode::new(CMP, Some(Absolute)) => 0xCD,
|
||||
Opcode::new(DEC, Some(Absolute)) => 0xCE,
|
||||
Opcode::new(BNE, Some(Relative)) => 0xD0,
|
||||
Opcode::new(CMP, Some(ZeroPageYIndirect)) => 0xD1,
|
||||
Opcode::new(CMP, Some(ZeroPageX)) => 0xD5,
|
||||
Opcode::new(DEC, Some(ZeroPageX)) => 0xD6,
|
||||
Opcode::new(CLD, None) => 0xD8,
|
||||
Opcode::new(CMP, Some(AbsoluteY)) => 0xD9,
|
||||
Opcode::new(CMP, Some(AbsoluteX)) => 0xDD,
|
||||
Opcode::new(DEC, Some(AbsoluteX)) => 0xDE,
|
||||
Opcode::new(CMP, Some(ZeroPageYIndirect)) => 0xD1,
|
||||
Opcode::new(CMP, Some(ZeroPageX)) => 0xD5,
|
||||
Opcode::new(DEC, Some(ZeroPageX)) => 0xD6,
|
||||
Opcode::new(CLD, None) => 0xD8,
|
||||
Opcode::new(CMP, Some(AbsoluteY)) => 0xD9,
|
||||
Opcode::new(CMP, Some(AbsoluteX)) => 0xDD,
|
||||
Opcode::new(DEC, Some(AbsoluteX)) => 0xDE,
|
||||
Opcode::new(CPX, Some(Immediate)) => 0xE0,
|
||||
Opcode::new(SBC, Some(ZeroPageIndirectX)) => 0xE1,
|
||||
Opcode::new(CPX, Some(ZeroPage)) => 0xE4,
|
||||
Opcode::new(SBC, Some(ZeroPage)) => 0xE5,
|
||||
Opcode::new(INC, Some(ZeroPage)) => 0xE6,
|
||||
Opcode::new(INX, None) => 0xE8,
|
||||
Opcode::new(SBC, Some(Immediate)) => 0xE9,
|
||||
Opcode::new(NOP, None) => 0xEA,
|
||||
Opcode::new(CPX, Some(Absolute)) => 0xEC,
|
||||
Opcode::new(SBC, Some(Absolute)) => 0xED,
|
||||
Opcode::new(INC, Some(Absolute)) => 0xEE,
|
||||
Opcode::new(SBC, Some(ZeroPageIndirectX)) => 0xE1,
|
||||
Opcode::new(CPX, Some(ZeroPage)) => 0xE4,
|
||||
Opcode::new(SBC, Some(ZeroPage)) => 0xE5,
|
||||
Opcode::new(INC, Some(ZeroPage)) => 0xE6,
|
||||
Opcode::new(INX, None) => 0xE8,
|
||||
Opcode::new(SBC, Some(Immediate)) => 0xE9,
|
||||
Opcode::new(NOP, None) => 0xEA,
|
||||
Opcode::new(CPX, Some(Absolute)) => 0xEC,
|
||||
Opcode::new(SBC, Some(Absolute)) => 0xED,
|
||||
Opcode::new(INC, Some(Absolute)) => 0xEE,
|
||||
Opcode::new(BEQ, Some(Relative)) => 0xF0,
|
||||
Opcode::new(SBC, Some(ZeroPageYIndirect)) => 0xF1,
|
||||
Opcode::new(SBC, Some(ZeroPageX)) => 0xF5,
|
||||
Opcode::new(INC, Some(ZeroPageX)) => 0xF6,
|
||||
Opcode::new(SED, None) => 0xF8,
|
||||
Opcode::new(SBC, Some(AbsoluteY)) => 0xF9,
|
||||
Opcode::new(SBC, Some(AbsoluteX)) => 0xFD,
|
||||
Opcode::new(INC, Some(AbsoluteX)) => 0xFE,
|
||||
Opcode::new(SBC, Some(ZeroPageYIndirect)) => 0xF1,
|
||||
Opcode::new(SBC, Some(ZeroPageX)) => 0xF5,
|
||||
Opcode::new(INC, Some(ZeroPageX)) => 0xF6,
|
||||
Opcode::new(SED, None) => 0xF8,
|
||||
Opcode::new(SBC, Some(AbsoluteY)) => 0xF9,
|
||||
Opcode::new(SBC, Some(AbsoluteX)) => 0xFD,
|
||||
Opcode::new(INC, Some(AbsoluteX)) => 0xFE,
|
||||
}
|
||||
|
11
src/lib.rs
11
src/lib.rs
@ -4,10 +4,13 @@
|
||||
#![forbid(unsafe_code)]
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
pub mod state;
|
||||
pub mod instructions;
|
||||
pub mod emulation;
|
||||
pub mod instructions;
|
||||
pub mod state;
|
||||
|
||||
pub use instructions::{Opcode, Instruction, AddressMode};
|
||||
pub use emulation::{
|
||||
DefaultReadCallback, DefaultWriteCallback, Emulator, FunctionReadCallback,
|
||||
FunctionWriteCallback, ReadCallback, WriteCallback,
|
||||
};
|
||||
pub use instructions::{AddressMode, Instruction, Opcode};
|
||||
pub use state::{State, Status};
|
||||
pub use emulation::{Emulator, ReadCallback, WriteCallback, DefaultReadCallback, DefaultWriteCallback, FunctionReadCallback, FunctionWriteCallback};
|
||||
|
@ -4,8 +4,8 @@ extern crate std;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use {
|
||||
serde::{Serialize, Deserialize},
|
||||
serde_with::{As, Bytes}
|
||||
serde::{Deserialize, Serialize},
|
||||
serde_with::{As, Bytes},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, core::hash::Hash)]
|
||||
@ -39,7 +39,7 @@ pub struct State {
|
||||
/// but grows the struct's size considerably.
|
||||
/// Consider storing this struct on the heap if this is undesirable and you have one.
|
||||
#[cfg_attr(feature = "serde", serde(with = "As::<Bytes>"))]
|
||||
pub memory: [u8; 256 * 256]
|
||||
pub memory: [u8; 256 * 256],
|
||||
}
|
||||
|
||||
#[allow(clippy::missing_fields_in_debug)]
|
||||
@ -66,7 +66,7 @@ impl Default for State {
|
||||
stack_pointer: 0xFF,
|
||||
status: Status::default(),
|
||||
memory: [0; 256 * 256],
|
||||
_padding: 0
|
||||
_padding: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ fn all_suite_a() -> Result<(), usize> {
|
||||
if trap_number != 0xFF {
|
||||
eprintln!("!!! ENTERED TRAP !!!");
|
||||
eprintln!("{:02x?}", emulator.state);
|
||||
eprintln!("Failed test: {trap_number}", );
|
||||
eprintln!("Failed test: {trap_number}",);
|
||||
return Err(0);
|
||||
}
|
||||
break;
|
||||
@ -57,18 +57,18 @@ fn functional_test() -> Result<(), usize> {
|
||||
}
|
||||
eprintln!("----------------------------[STACK]-----------------------------");
|
||||
for i in 0..16 {
|
||||
eprintln!("{:02x?}", &emulator.state.memory[0x100 + (i * 16)..0x100 + ((i + 1) * 16)])
|
||||
eprintln!(
|
||||
"{:02x?}",
|
||||
&emulator.state.memory[0x100 + (i * 16)..0x100 + ((i + 1) * 16)]
|
||||
)
|
||||
}
|
||||
return Err(0);
|
||||
}
|
||||
if needs_interrupt {
|
||||
let vector = u16::from_le_bytes([
|
||||
emulator.read(0xFFFE),
|
||||
emulator.read(0xFFFF)
|
||||
]);
|
||||
let vector = u16::from_le_bytes([emulator.read(0xFFFE), emulator.read(0xFFFF)]);
|
||||
eprintln!("[MASKABLE INTERRUPT, GOING TO IRQ VECTOR @ {vector:02X}]");
|
||||
// Go to interrupt vector
|
||||
emulator.state.program_counter = vector;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user