1
0
mirror of https://github.com/mre/mos6502.git synced 2025-02-20 09:29:02 +00:00

Add Default impls

This commit is contained in:
Matthias Endler 2021-01-28 23:34:41 +01:00
parent 0749b1798b
commit 93a39980e4
3 changed files with 147 additions and 109 deletions

View File

@ -37,6 +37,12 @@ pub struct CPU {
pub memory: Memory, pub memory: Memory,
} }
impl Default for CPU {
fn default() -> Self {
Self::new()
}
}
impl CPU { impl CPU {
pub fn new() -> CPU { pub fn new() -> CPU {
CPU { CPU {
@ -515,115 +521,125 @@ impl CPU {
); );
} }
fn add_with_carry(&mut self, value: i8) { fn add_with_carry(&mut self, value: i8) {
let a_before: i8 = self.registers.accumulator; let a_before: i8 = self.registers.accumulator;
let c_before: i8 = if self.registers.status.contains(Status::PS_CARRY) { let c_before: i8 = if self.registers.status.contains(Status::PS_CARRY) {
1 1
} else { } else {
0 0
}; };
let a_after: i8 = a_before.wrapping_add(c_before).wrapping_add(value); let a_after: i8 = a_before.wrapping_add(c_before).wrapping_add(value);
debug_assert_eq!( debug_assert_eq!(
a_after as u8, a_after as u8,
a_before.wrapping_add(c_before).wrapping_add(value) as u8 a_before.wrapping_add(c_before).wrapping_add(value) as u8
); );
let bcd1: i8 = if (a_after & 0x0f) as u8 > 0x09 { let bcd1: i8 = if (a_after & 0x0f) as u8 > 0x09 {
0x06 0x06
} else { } else {
0x00 0x00
}; };
let bcd2: i8 = if (a_after.wrapping_add(bcd1) as u8 & 0xf0) as u8 > 0x90 { let bcd2: i8 = if (a_after.wrapping_add(bcd1) as u8 & 0xf0) as u8 > 0x90 {
0x60 0x60
} else { } else {
0x00 0x00
}; };
let result: i8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) { let result: i8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
a_after.wrapping_add(bcd1).wrapping_add(bcd2) a_after.wrapping_add(bcd1).wrapping_add(bcd2)
} else { } else {
a_after a_after
}; };
let did_carry = (result as u8) < (a_before as u8); let did_carry = (result as u8) < (a_before as u8);
let did_overflow = (a_before < 0 && value < 0 && a_after >= 0) let did_overflow = (a_before < 0 && value < 0 && a_after >= 0)
|| (a_before > 0 && value > 0 && a_after <= 0); || (a_before > 0 && value > 0 && a_after <= 0);
let mask = Status::PS_CARRY | Status::PS_OVERFLOW; let mask = Status::PS_CARRY | Status::PS_OVERFLOW;
self.registers.status.set_with_mask( mask, Status::new(StatusArgs { carry: did_carry, overflow: did_overflow, ..StatusArgs::none() }),); self.registers.status.set_with_mask(
mask,
Status::new(StatusArgs {
carry: did_carry,
overflow: did_overflow,
..StatusArgs::none()
}),
);
self.load_accumulator(result); self.load_accumulator(result);
debug!("accumulator: {}", self.registers.accumulator); debug!("accumulator: {}", self.registers.accumulator);
} }
fn and(&mut self, value: i8) { fn and(&mut self, value: i8) {
let a_after = self.registers.accumulator & value; let a_after = self.registers.accumulator & value;
self.load_accumulator(a_after); self.load_accumulator(a_after);
} }
fn subtract_with_carry(&mut self, value: i8) { fn subtract_with_carry(&mut self, value: i8) {
// A - M - (1 - C) // A - M - (1 - C)
// nc -- 'not carry' // nc -- 'not carry'
let nc: i8 = if self.registers.status.contains(Status::PS_CARRY) { let nc: i8 = if self.registers.status.contains(Status::PS_CARRY) {
0 0
} else { } else {
1 1
}; };
let a_before: i8 = self.registers.accumulator; let a_before: i8 = self.registers.accumulator;
let a_after = a_before.wrapping_sub(value).wrapping_sub(nc); let a_after = a_before.wrapping_sub(value).wrapping_sub(nc);
// The overflow flag is set on two's-complement overflow. // The overflow flag is set on two's-complement overflow.
// //
// range of A is -128 to 127 // range of A is -128 to 127
// range of - M - (1 - C) is -128 to 128 // range of - M - (1 - C) is -128 to 128
// -(127 + 1) to -(-128 + 0) // -(127 + 1) to -(-128 + 0)
// //
let over = let over =
((nc == 0 && value < 0) || (nc == 1 && value < -1)) && a_before >= 0 && a_after < 0; ((nc == 0 && value < 0) || (nc == 1 && value < -1)) && a_before >= 0 && a_after < 0;
let under = (a_before < 0) && (-value - nc < 0) && a_after >= 0; let under = (a_before < 0) && (-value - nc < 0) && a_after >= 0;
let did_overflow = over || under; let did_overflow = over || under;
let mask = Status::PS_CARRY | Status::PS_OVERFLOW; let mask = Status::PS_CARRY | Status::PS_OVERFLOW;
let bcd1: i8 = if (a_before & 0x0f).wrapping_sub(nc) < (value & 0x0f) { let bcd1: i8 = if (a_before & 0x0f).wrapping_sub(nc) < (value & 0x0f) {
0x06 0x06
} else { } else {
0x00 0x00
}; };
let bcd2: i8 = if (a_after.wrapping_sub(bcd1) as u8 & 0xf0) as u8 > 0x90 { let bcd2: i8 = if (a_after.wrapping_sub(bcd1) as u8 & 0xf0) as u8 > 0x90 {
0x60 0x60
} else { } else {
0x00 0x00
}; };
let result: i8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) { let result: i8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
a_after.wrapping_sub(bcd1).wrapping_sub(bcd2) a_after.wrapping_sub(bcd1).wrapping_sub(bcd2)
} else { } else {
a_after a_after
}; };
// The carry flag is set on unsigned overflow. // The carry flag is set on unsigned overflow.
let did_carry = (result as u8) > (a_before as u8); let did_carry = (result as u8) > (a_before as u8);
self.registers.status.set_with_mask( self.registers.status.set_with_mask(
mask, mask,
Status::new(StatusArgs { carry: did_carry, overflow: did_overflow, ..StatusArgs::none() }), Status::new(StatusArgs {
); carry: did_carry,
overflow: did_overflow,
..StatusArgs::none()
}),
);
self.load_accumulator(result);
self.load_accumulator(result); }
}
fn decrement_memory(&mut self, addr: Address) { fn decrement_memory(&mut self, addr: Address) {
let value_new = self.memory.get_byte(addr).wrapping_sub(1); let value_new = self.memory.get_byte(addr).wrapping_sub(1);
@ -779,52 +795,54 @@ mod tests {
use super::*; use super::*;
use num::range_inclusive; use num::range_inclusive;
#[test] #[test]
fn decimal_add_test() { fn decimal_add_test() {
let mut cpu = CPU::new(); let mut cpu = CPU::new();
cpu.registers.status.or(Status::PS_DECIMAL_MODE); cpu.registers.status.or(Status::PS_DECIMAL_MODE);
cpu.add_with_carry(0x09); cpu.add_with_carry(0x09);
assert_eq!(cpu.registers.accumulator, 0x09); assert_eq!(cpu.registers.accumulator, 0x09);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false); assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false); assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false); assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false); assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
cpu.add_with_carry(0x43); cpu.add_with_carry(0x43);
assert_eq!(cpu.registers.accumulator, 0x52); assert_eq!(cpu.registers.accumulator, 0x52);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false); assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false); assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false); assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false); assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
cpu.add_with_carry(0x48); cpu.add_with_carry(0x48);
assert_eq!(cpu.registers.accumulator, 0x00); assert_eq!(cpu.registers.accumulator, 0x00);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true); assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), true); assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), true);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false); assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), true); assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), true);
} }
#[test] #[test]
fn decimal_subtract_test() { fn decimal_subtract_test() {
let mut cpu = CPU::new(); let mut cpu = CPU::new();
cpu.registers.status.or(Status::PS_DECIMAL_MODE | Status::PS_CARRY); cpu.registers
.status
.or(Status::PS_DECIMAL_MODE | Status::PS_CARRY);
cpu.registers.accumulator = 0; cpu.registers.accumulator = 0;
cpu.subtract_with_carry(0x48); cpu.subtract_with_carry(0x48);
assert_eq!(cpu.registers.accumulator as u8, 0x52); assert_eq!(cpu.registers.accumulator as u8, 0x52);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true); assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false); assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false); assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false); assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
cpu.subtract_with_carry(0x43); cpu.subtract_with_carry(0x43);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false); assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false); assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false); assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false); assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
} }
#[test] #[test]
fn add_with_carry_test() { fn add_with_carry_test() {

View File

@ -54,9 +54,17 @@ pub struct Memory {
bytes: [u8; MEMORY_SIZE], bytes: [u8; MEMORY_SIZE],
} }
impl Default for Memory {
fn default() -> Self {
Self::new()
}
}
impl Memory { impl Memory {
pub fn new() -> Memory { pub fn new() -> Memory {
Memory { bytes: [0; MEMORY_SIZE] } Memory {
bytes: [0; MEMORY_SIZE],
}
} }
pub fn get_byte(&self, address: Address) -> u8 { pub fn get_byte(&self, address: Address) -> u8 {
@ -101,7 +109,10 @@ mod tests {
fn test_memory_set_bytes() { fn test_memory_set_bytes() {
let mut memory = Memory::new(); let mut memory = Memory::new();
memory.set_bytes(Address(0x0100), &[1, 2, 3, 4, 5]); memory.set_bytes(Address(0x0100), &[1, 2, 3, 4, 5]);
assert_eq!(memory.get_slice(Address(0x00FF), AddressDiff(7)), &[0, 1, 2, 3, 4, 5, 0]); assert_eq!(
memory.get_slice(Address(0x00FF), AddressDiff(7)),
&[0, 1, 2, 3, 4, 5, 0]
);
} }
#[test] #[test]

View File

@ -26,7 +26,7 @@
// POSSIBILITY OF SUCH DAMAGE. // POSSIBILITY OF SUCH DAMAGE.
use address::{Address, AddressDiff}; use address::{Address, AddressDiff};
use memory::{STACK_ADDRESS_LO, STACK_ADDRESS_HI}; use memory::{STACK_ADDRESS_HI, STACK_ADDRESS_LO};
// Useful for constructing Status instances // Useful for constructing Status instances
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -88,15 +88,18 @@ impl Status {
}) })
} }
pub fn new(StatusArgs { negative, pub fn new(
overflow, StatusArgs {
unused, negative,
brk, overflow,
decimal_mode, unused,
disable_interrupts, brk,
zero, decimal_mode,
carry }: StatusArgs) -> Status disable_interrupts,
{ zero,
carry,
}: StatusArgs,
) -> Status {
let mut out = Status::empty(); let mut out = Status::empty();
if negative { if negative {
@ -169,6 +172,12 @@ pub struct Registers {
pub status: Status, pub status: Status,
} }
impl Default for Registers {
fn default() -> Self {
Self::new()
}
}
impl Registers { impl Registers {
pub fn new() -> Registers { pub fn new() -> Registers {
// TODO akeeton: Revisit these defaults. // TODO akeeton: Revisit these defaults.