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:
parent
0749b1798b
commit
93a39980e4
208
src/cpu.rs
208
src/cpu.rs
@ -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() {
|
||||||
|
@ -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]
|
||||||
|
@ -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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user