mirror of
https://github.com/mre/mos6502.git
synced 2024-12-26 23:29:23 +00:00
Fix compilation with latest rustc
This commit is contained in:
parent
82e2cac30c
commit
0a3f628168
@ -3,3 +3,4 @@
|
|||||||
Alex Weisberger <alex.m.weisberger@gmail.com>
|
Alex Weisberger <alex.m.weisberger@gmail.com>
|
||||||
Andrew Keeton <andrewrkeeton@gmail.com>
|
Andrew Keeton <andrewrkeeton@gmail.com>
|
||||||
Johannes Muenzel <jmuenzel@gmail.com>
|
Johannes Muenzel <jmuenzel@gmail.com>
|
||||||
|
Matthias Endler <matthias-endler@gmx.net>
|
@ -39,5 +39,6 @@ name = "emu6502"
|
|||||||
name = "emu6502"
|
name = "emu6502"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.2.3"
|
bitflags = "0.9.1"
|
||||||
|
log = "0.3.8"
|
||||||
|
num = "0.1"
|
||||||
|
@ -25,16 +25,15 @@
|
|||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
use std::num::Int;
|
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
|
|
||||||
// The idea here is that it doesn't make sense to add two addresses, but it
|
// The idea here is that it doesn't make sense to add two addresses, but it
|
||||||
// does make sense to add an address and an "address-difference". (If this
|
// does make sense to add an address and an "address-difference". (If this
|
||||||
// is too annoying to work with we should let it go.)
|
// is too annoying to work with we should let it go.)
|
||||||
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
pub struct AddressDiff(pub i32);
|
pub struct AddressDiff(pub i32);
|
||||||
|
|
||||||
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
pub struct Address(pub u16);
|
pub struct Address(pub u16);
|
||||||
|
|
||||||
impl Add<AddressDiff> for Address {
|
impl Add<AddressDiff> for Address {
|
||||||
@ -57,7 +56,7 @@ impl Add for AddressDiff {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct CheckedAddressDiff(u16);
|
pub struct CheckedAddressDiff(u16);
|
||||||
|
|
||||||
impl Add<CheckedAddressDiff> for Address {
|
impl Add<CheckedAddressDiff> for Address {
|
||||||
@ -77,7 +76,7 @@ impl Add<CheckedAddressDiff> for Address {
|
|||||||
impl Address {
|
impl Address {
|
||||||
pub fn to_u16(&self) -> u16 {
|
pub fn to_u16(&self) -> u16 {
|
||||||
match *self {
|
match *self {
|
||||||
Address(address_) => address_
|
Address(address_) => address_,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,4 +92,3 @@ impl Address {
|
|||||||
(self.to_u16() & 0x00ff) as u8
|
(self.to_u16() & 0x00ff) as u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -25,20 +25,17 @@
|
|||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#![feature(core)]
|
|
||||||
#![feature(hash)]
|
|
||||||
#![feature(rustc_private)]
|
|
||||||
|
|
||||||
// Needed for debug! / log! macros
|
// Needed for debug! / log! macros
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
|
extern crate num;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustc_bitflags;
|
extern crate bitflags;
|
||||||
|
|
||||||
pub mod address;
|
pub mod address;
|
||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
pub mod machine;
|
pub mod machine;
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
pub mod range_incl;
|
|
||||||
pub mod registers;
|
pub mod registers;
|
||||||
|
324
src/machine.rs
324
src/machine.rs
@ -31,22 +31,21 @@ use address::{Address, AddressDiff};
|
|||||||
use instruction;
|
use instruction;
|
||||||
use instruction::{DecodedInstr, Instruction, OpInput};
|
use instruction::{DecodedInstr, Instruction, OpInput};
|
||||||
use memory::Memory;
|
use memory::Memory;
|
||||||
use range_incl::range_incl;
|
|
||||||
use registers::{Registers, StackPointer, Status, StatusArgs};
|
use registers::{Registers, StackPointer, Status, StatusArgs};
|
||||||
use registers::{PS_NEGATIVE, PS_DECIMAL_MODE, PS_OVERFLOW, PS_ZERO, PS_CARRY,
|
use registers::{PS_NEGATIVE, PS_DECIMAL_MODE, PS_OVERFLOW, PS_ZERO, PS_CARRY,
|
||||||
PS_DISABLE_INTERRUPTS};
|
PS_DISABLE_INTERRUPTS};
|
||||||
|
|
||||||
#[derive(Copy)]
|
#[derive(Clone)]
|
||||||
pub struct Machine {
|
pub struct Machine {
|
||||||
pub registers: Registers,
|
pub registers: Registers,
|
||||||
pub memory: Memory
|
pub memory: Memory,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
pub fn new() -> Machine {
|
pub fn new() -> Machine {
|
||||||
Machine {
|
Machine {
|
||||||
registers: Registers::new(),
|
registers: Registers::new(),
|
||||||
memory: Memory::new()
|
memory: Memory::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,19 +61,17 @@ impl Machine {
|
|||||||
let extra_bytes = am.extra_bytes();
|
let extra_bytes = am.extra_bytes();
|
||||||
let num_bytes = AddressDiff(1) + extra_bytes;
|
let num_bytes = AddressDiff(1) + extra_bytes;
|
||||||
|
|
||||||
let data_start = self.registers.program_counter
|
let data_start = self.registers.program_counter + AddressDiff(1);
|
||||||
+ AddressDiff(1);
|
|
||||||
|
|
||||||
let slice = self.memory.get_slice(data_start, extra_bytes);
|
let slice = self.memory.get_slice(data_start, extra_bytes);
|
||||||
let am_out = am.process(self, slice);
|
let am_out = am.process(self, slice);
|
||||||
|
|
||||||
// Increment program counter
|
// Increment program counter
|
||||||
self.registers.program_counter =
|
self.registers.program_counter = self.registers.program_counter + num_bytes;
|
||||||
self.registers.program_counter + num_bytes;
|
|
||||||
|
|
||||||
Some((instr, am_out))
|
Some((instr, am_out))
|
||||||
}
|
}
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,32 +98,29 @@ impl Machine {
|
|||||||
(Instruction::ASL, OpInput::UseImplied) => {
|
(Instruction::ASL, OpInput::UseImplied) => {
|
||||||
// Accumulator mode
|
// Accumulator mode
|
||||||
let mut val = self.registers.accumulator as u8;
|
let mut val = self.registers.accumulator as u8;
|
||||||
Machine::shift_left_with_flags(&mut val,
|
Machine::shift_left_with_flags(&mut val, &mut self.registers.status);
|
||||||
&mut self.registers.status);
|
|
||||||
self.registers.accumulator = val as i8;
|
self.registers.accumulator = val as i8;
|
||||||
|
|
||||||
}
|
}
|
||||||
(Instruction::ASL, OpInput::UseAddress(addr)) => {
|
(Instruction::ASL, OpInput::UseAddress(addr)) => {
|
||||||
Machine::shift_left_with_flags(
|
Machine::shift_left_with_flags(
|
||||||
self.memory.get_byte_mut_ref(addr),
|
self.memory.get_byte_mut_ref(addr),
|
||||||
&mut self.registers.status);
|
&mut self.registers.status,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Instruction::BCC, OpInput::UseRelative(rel)) => {
|
(Instruction::BCC, OpInput::UseRelative(rel)) => {
|
||||||
let addr = self.registers.program_counter
|
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||||
+ AddressDiff(rel as i32);
|
|
||||||
self.branch_if_carry_clear(addr);
|
self.branch_if_carry_clear(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Instruction::BCS, OpInput::UseRelative(rel)) => {
|
(Instruction::BCS, OpInput::UseRelative(rel)) => {
|
||||||
let addr = self.registers.program_counter
|
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||||
+ AddressDiff(rel as i32);
|
|
||||||
self.branch_if_carry_set(addr);
|
self.branch_if_carry_set(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Instruction::BEQ, OpInput::UseRelative(rel)) => {
|
(Instruction::BEQ, OpInput::UseRelative(rel)) => {
|
||||||
let addr = self.registers.program_counter
|
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||||
+ AddressDiff(rel as i32);
|
|
||||||
self.branch_if_equal(addr);
|
self.branch_if_equal(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,34 +140,33 @@ impl Machine {
|
|||||||
|
|
||||||
self.registers.status.set_with_mask(
|
self.registers.status.set_with_mask(
|
||||||
PS_ZERO | PS_NEGATIVE | PS_OVERFLOW,
|
PS_ZERO | PS_NEGATIVE | PS_OVERFLOW,
|
||||||
Status::new(StatusArgs { zero: is_zero,
|
Status::new(StatusArgs {
|
||||||
|
zero: is_zero,
|
||||||
negative: bit7,
|
negative: bit7,
|
||||||
overflow: bit6,
|
overflow: bit6,
|
||||||
..StatusArgs::none() } ));
|
..StatusArgs::none()
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Instruction::BMI, OpInput::UseRelative(rel)) => {
|
(Instruction::BMI, OpInput::UseRelative(rel)) => {
|
||||||
let addr = self.registers.program_counter
|
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||||
+ AddressDiff(rel as i32);
|
|
||||||
debug!("branch if minus relative. address: {:?}", addr);
|
debug!("branch if minus relative. address: {:?}", addr);
|
||||||
self.branch_if_minus(addr);
|
self.branch_if_minus(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Instruction::BPL, OpInput::UseRelative(rel)) => {
|
(Instruction::BPL, OpInput::UseRelative(rel)) => {
|
||||||
let addr = self.registers.program_counter
|
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||||
+ AddressDiff(rel as i32);
|
|
||||||
self.branch_if_positive(addr);
|
self.branch_if_positive(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Instruction::BVC, OpInput::UseRelative(rel)) => {
|
(Instruction::BVC, OpInput::UseRelative(rel)) => {
|
||||||
let addr = self.registers.program_counter
|
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||||
+ AddressDiff(rel as i32);
|
|
||||||
self.branch_if_overflow_clear(addr);
|
self.branch_if_overflow_clear(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Instruction::BVS, OpInput::UseRelative(rel)) => {
|
(Instruction::BVS, OpInput::UseRelative(rel)) => {
|
||||||
let addr = self.registers.program_counter
|
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||||
+ AddressDiff(rel as i32);
|
|
||||||
self.branch_if_overflow_set(addr);
|
self.branch_if_overflow_set(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,9 +207,7 @@ impl Machine {
|
|||||||
self.compare_with_y_register(val);
|
self.compare_with_y_register(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Instruction::DEC, OpInput::UseAddress(addr)) => {
|
(Instruction::DEC, OpInput::UseAddress(addr)) => self.decrement_memory(addr),
|
||||||
self.decrement_memory(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
(Instruction::DEX, OpInput::UseImplied) => {
|
(Instruction::DEX, OpInput::UseImplied) => {
|
||||||
self.dec_x();
|
self.dec_x();
|
||||||
@ -246,9 +237,7 @@ impl Machine {
|
|||||||
self.load_y_register(y);
|
self.load_y_register(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Instruction::JMP, OpInput::UseAddress(addr)) => {
|
(Instruction::JMP, OpInput::UseAddress(addr)) => self.jump(addr),
|
||||||
self.jump(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
(Instruction::LDA, OpInput::UseImmediate(val)) => {
|
(Instruction::LDA, OpInput::UseImmediate(val)) => {
|
||||||
debug!("load A immediate: {}", val);
|
debug!("load A immediate: {}", val);
|
||||||
@ -283,14 +272,14 @@ impl Machine {
|
|||||||
(Instruction::LSR, OpInput::UseImplied) => {
|
(Instruction::LSR, OpInput::UseImplied) => {
|
||||||
// Accumulator mode
|
// Accumulator mode
|
||||||
let mut val = self.registers.accumulator as u8;
|
let mut val = self.registers.accumulator as u8;
|
||||||
Machine::shift_right_with_flags(&mut val,
|
Machine::shift_right_with_flags(&mut val, &mut self.registers.status);
|
||||||
&mut self.registers.status);
|
|
||||||
self.registers.accumulator = val as i8;
|
self.registers.accumulator = val as i8;
|
||||||
}
|
}
|
||||||
(Instruction::LSR, OpInput::UseAddress(addr)) => {
|
(Instruction::LSR, OpInput::UseAddress(addr)) => {
|
||||||
Machine::shift_right_with_flags(
|
Machine::shift_right_with_flags(
|
||||||
self.memory.get_byte_mut_ref(addr),
|
self.memory.get_byte_mut_ref(addr),
|
||||||
&mut self.registers.status);
|
&mut self.registers.status,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Instruction::ORA, OpInput::UseImmediate(val)) => {
|
(Instruction::ORA, OpInput::UseImmediate(val)) => {
|
||||||
@ -328,26 +317,26 @@ impl Machine {
|
|||||||
(Instruction::ROL, OpInput::UseImplied) => {
|
(Instruction::ROL, OpInput::UseImplied) => {
|
||||||
// Accumulator mode
|
// Accumulator mode
|
||||||
let mut val = self.registers.accumulator as u8;
|
let mut val = self.registers.accumulator as u8;
|
||||||
Machine::rotate_left_with_flags(&mut val,
|
Machine::rotate_left_with_flags(&mut val, &mut self.registers.status);
|
||||||
&mut self.registers.status);
|
|
||||||
self.registers.accumulator = val as i8;
|
self.registers.accumulator = val as i8;
|
||||||
}
|
}
|
||||||
(Instruction::ROL, OpInput::UseAddress(addr)) => {
|
(Instruction::ROL, OpInput::UseAddress(addr)) => {
|
||||||
Machine::rotate_left_with_flags(
|
Machine::rotate_left_with_flags(
|
||||||
self.memory.get_byte_mut_ref(addr),
|
self.memory.get_byte_mut_ref(addr),
|
||||||
&mut self.registers.status);
|
&mut self.registers.status,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
(Instruction::ROR, OpInput::UseImplied) => {
|
(Instruction::ROR, OpInput::UseImplied) => {
|
||||||
// Accumulator mode
|
// Accumulator mode
|
||||||
let mut val = self.registers.accumulator as u8;
|
let mut val = self.registers.accumulator as u8;
|
||||||
Machine::rotate_right_with_flags(&mut val,
|
Machine::rotate_right_with_flags(&mut val, &mut self.registers.status);
|
||||||
&mut self.registers.status);
|
|
||||||
self.registers.accumulator = val as i8;
|
self.registers.accumulator = val as i8;
|
||||||
}
|
}
|
||||||
(Instruction::ROR, OpInput::UseAddress(addr)) => {
|
(Instruction::ROR, OpInput::UseAddress(addr)) => {
|
||||||
Machine::rotate_right_with_flags(
|
Machine::rotate_right_with_flags(
|
||||||
self.memory.get_byte_mut_ref(addr),
|
self.memory.get_byte_mut_ref(addr),
|
||||||
&mut self.registers.status);
|
&mut self.registers.status,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Instruction::SBC, OpInput::UseImmediate(val)) => {
|
(Instruction::SBC, OpInput::UseImmediate(val)) => {
|
||||||
@ -356,8 +345,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
(Instruction::SBC, OpInput::UseAddress(addr)) => {
|
(Instruction::SBC, OpInput::UseAddress(addr)) => {
|
||||||
let val = self.memory.get_byte(addr) as i8;
|
let val = self.memory.get_byte(addr) as i8;
|
||||||
debug!("subtract with carry. address: {:?}. value: {}",
|
debug!("subtract with carry. address: {:?}. value: {}", addr, val);
|
||||||
addr, val);
|
|
||||||
self.subtract_with_carry(val);
|
self.subtract_with_carry(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,8 +402,10 @@ impl Machine {
|
|||||||
debug!("NOP instruction");
|
debug!("NOP instruction");
|
||||||
}
|
}
|
||||||
(_, _) => {
|
(_, _) => {
|
||||||
debug!("attempting to execute unimplemented or invalid \
|
debug!(
|
||||||
instruction");
|
"attempting to execute unimplemented or invalid \
|
||||||
|
instruction"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -425,7 +415,7 @@ impl Machine {
|
|||||||
if let Some(decoded_instr) = self.fetch_next_and_decode() {
|
if let Some(decoded_instr) = self.fetch_next_and_decode() {
|
||||||
self.execute_instruction(decoded_instr);
|
self.execute_instruction(decoded_instr);
|
||||||
} else {
|
} else {
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -436,9 +426,12 @@ impl Machine {
|
|||||||
|
|
||||||
status.set_with_mask(
|
status.set_with_mask(
|
||||||
PS_ZERO | PS_NEGATIVE,
|
PS_ZERO | PS_NEGATIVE,
|
||||||
Status::new(StatusArgs { zero: is_zero,
|
Status::new(StatusArgs {
|
||||||
|
zero: is_zero,
|
||||||
negative: is_negative,
|
negative: is_negative,
|
||||||
..StatusArgs::none() } ));
|
..StatusArgs::none()
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shift_left_with_flags(p_val: &mut u8, status: &mut Status) {
|
fn shift_left_with_flags(p_val: &mut u8, status: &mut Status) {
|
||||||
@ -448,8 +441,11 @@ impl Machine {
|
|||||||
*p_val = shifted;
|
*p_val = shifted;
|
||||||
status.set_with_mask(
|
status.set_with_mask(
|
||||||
PS_CARRY,
|
PS_CARRY,
|
||||||
Status::new(StatusArgs { carry: is_bit_7_set,
|
Status::new(StatusArgs {
|
||||||
..StatusArgs::none() } ));
|
carry: is_bit_7_set,
|
||||||
|
..StatusArgs::none()
|
||||||
|
}),
|
||||||
|
);
|
||||||
Machine::set_flags_from_i8(status, *p_val as i8);
|
Machine::set_flags_from_i8(status, *p_val as i8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,8 +455,11 @@ impl Machine {
|
|||||||
*p_val = *p_val >> 1;
|
*p_val = *p_val >> 1;
|
||||||
status.set_with_mask(
|
status.set_with_mask(
|
||||||
PS_CARRY,
|
PS_CARRY,
|
||||||
Status::new(StatusArgs { carry: is_bit_0_set,
|
Status::new(StatusArgs {
|
||||||
..StatusArgs::none() } ));
|
carry: is_bit_0_set,
|
||||||
|
..StatusArgs::none()
|
||||||
|
}),
|
||||||
|
);
|
||||||
Machine::set_flags_from_i8(status, *p_val as i8);
|
Machine::set_flags_from_i8(status, *p_val as i8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,8 +471,11 @@ impl Machine {
|
|||||||
*p_val = shifted + if is_carry_set { 1 } else { 0 };
|
*p_val = shifted + if is_carry_set { 1 } else { 0 };
|
||||||
status.set_with_mask(
|
status.set_with_mask(
|
||||||
PS_CARRY,
|
PS_CARRY,
|
||||||
Status::new(StatusArgs { carry: is_bit_7_set,
|
Status::new(StatusArgs {
|
||||||
..StatusArgs::none() } ));
|
carry: is_bit_7_set,
|
||||||
|
..StatusArgs::none()
|
||||||
|
}),
|
||||||
|
);
|
||||||
Machine::set_flags_from_i8(status, *p_val as i8);
|
Machine::set_flags_from_i8(status, *p_val as i8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,8 +487,11 @@ impl Machine {
|
|||||||
*p_val = shifted + if is_carry_set { 1 << 7 } else { 0 };
|
*p_val = shifted + if is_carry_set { 1 << 7 } else { 0 };
|
||||||
status.set_with_mask(
|
status.set_with_mask(
|
||||||
PS_CARRY,
|
PS_CARRY,
|
||||||
Status::new(StatusArgs { carry: is_bit_0_set,
|
Status::new(StatusArgs {
|
||||||
..StatusArgs::none() } ));
|
carry: is_bit_0_set,
|
||||||
|
..StatusArgs::none()
|
||||||
|
}),
|
||||||
|
);
|
||||||
Machine::set_flags_from_i8(status, *p_val as i8);
|
Machine::set_flags_from_i8(status, *p_val as i8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,21 +501,27 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load_x_register(&mut self, value: i8) {
|
fn load_x_register(&mut self, value: i8) {
|
||||||
Machine::set_i8_with_flags(&mut self.registers.index_x,
|
Machine::set_i8_with_flags(
|
||||||
|
&mut self.registers.index_x,
|
||||||
&mut self.registers.status,
|
&mut self.registers.status,
|
||||||
value);
|
value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_y_register(&mut self, value: i8) {
|
fn load_y_register(&mut self, value: i8) {
|
||||||
Machine::set_i8_with_flags(&mut self.registers.index_y,
|
Machine::set_i8_with_flags(
|
||||||
|
&mut self.registers.index_y,
|
||||||
&mut self.registers.status,
|
&mut self.registers.status,
|
||||||
value);
|
value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_accumulator(&mut self, value: i8) {
|
fn load_accumulator(&mut self, value: i8) {
|
||||||
Machine::set_i8_with_flags(&mut self.registers.accumulator,
|
Machine::set_i8_with_flags(
|
||||||
|
&mut self.registers.accumulator,
|
||||||
&mut self.registers.status,
|
&mut self.registers.status,
|
||||||
value);
|
value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_with_carry(&mut self, value: i8) {
|
fn add_with_carry(&mut self, value: i8) {
|
||||||
@ -519,25 +530,33 @@ impl Machine {
|
|||||||
debug!("binary-coded decimal not implemented for add_with_carry");
|
debug!("binary-coded decimal not implemented for add_with_carry");
|
||||||
} else {
|
} else {
|
||||||
let a_before: i8 = self.registers.accumulator;
|
let a_before: i8 = self.registers.accumulator;
|
||||||
let c_before: i8 = if self.registers.status.contains(PS_CARRY)
|
let c_before: i8 = if self.registers.status.contains(PS_CARRY) {
|
||||||
{ 1 } else { 0 };
|
1
|
||||||
let a_after: i8 = a_before + c_before + value;
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
let a_after: i8 = a_before.wrapping_add(c_before).wrapping_add(value);
|
||||||
|
|
||||||
debug_assert_eq!(a_after as u8, a_before as u8 + c_before as u8
|
debug_assert_eq!(
|
||||||
+ value as u8);
|
a_after as u8,
|
||||||
|
a_before.wrapping_add(c_before).wrapping_add(value) as u8
|
||||||
|
);
|
||||||
|
|
||||||
let did_carry = (a_after as u8) < (a_before as u8);
|
let did_carry = (a_after as u8) < (a_before as u8);
|
||||||
|
|
||||||
let did_overflow =
|
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);
|
||||||
|| (a_before > 0 && value > 0 && a_after <= 0);
|
|
||||||
|
|
||||||
let mask = PS_CARRY | PS_OVERFLOW;
|
let mask = PS_CARRY | PS_OVERFLOW;
|
||||||
|
|
||||||
self.registers.status.set_with_mask(mask,
|
self.registers.status.set_with_mask(
|
||||||
Status::new(StatusArgs { carry: did_carry,
|
mask,
|
||||||
|
Status::new(StatusArgs {
|
||||||
|
carry: did_carry,
|
||||||
overflow: did_overflow,
|
overflow: did_overflow,
|
||||||
..StatusArgs::none() } ));
|
..StatusArgs::none()
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
self.load_accumulator(a_after);
|
self.load_accumulator(a_after);
|
||||||
|
|
||||||
@ -553,18 +572,23 @@ impl Machine {
|
|||||||
// TODO: Implement binary-coded decimal
|
// TODO: Implement binary-coded decimal
|
||||||
fn subtract_with_carry(&mut self, value: i8) {
|
fn subtract_with_carry(&mut self, value: i8) {
|
||||||
if self.registers.status.contains(PS_DECIMAL_MODE) {
|
if self.registers.status.contains(PS_DECIMAL_MODE) {
|
||||||
debug!("binary-coded decimal not implemented for \
|
debug!(
|
||||||
subtract_with_carry");
|
"binary-coded decimal not implemented for \
|
||||||
|
subtract_with_carry"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// A - M - (1 - C)
|
// A - M - (1 - C)
|
||||||
|
|
||||||
// nc -- 'not carry'
|
// nc -- 'not carry'
|
||||||
let nc: i8 = if self.registers.status.contains(PS_CARRY)
|
let nc: i8 = if self.registers.status.contains(PS_CARRY) {
|
||||||
{ 0 } else { 1 };
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
};
|
||||||
|
|
||||||
let a_before: i8 = self.registers.accumulator;
|
let a_before: i8 = self.registers.accumulator;
|
||||||
|
|
||||||
let a_after = a_before - value - nc;
|
let a_after = a_before.wrapping_sub(value).wrapping_sub(nc);
|
||||||
|
|
||||||
// The carry flag is set on unsigned overflow.
|
// The carry flag is set on unsigned overflow.
|
||||||
let did_carry = (a_after as u8) > (a_before as u8);
|
let did_carry = (a_after as u8) > (a_before as u8);
|
||||||
@ -575,28 +599,30 @@ impl Machine {
|
|||||||
// 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 = ((nc == 0 && value < 0) || (nc == 1 && value < -1))
|
let over = ((nc == 0 && value < 0) || (nc == 1 && value < -1)) && a_before >= 0 &&
|
||||||
&& a_before >= 0
|
a_after < 0;
|
||||||
&& a_after < 0;
|
|
||||||
|
|
||||||
let under = (a_before < 0) && (-value - nc < 0)
|
let under = (a_before < 0) && (-value - nc < 0) && a_after >= 0;
|
||||||
&& a_after >= 0;
|
|
||||||
|
|
||||||
let did_overflow = over || under;
|
let did_overflow = over || under;
|
||||||
|
|
||||||
let mask = PS_CARRY | PS_OVERFLOW;
|
let mask = PS_CARRY | PS_OVERFLOW;
|
||||||
|
|
||||||
self.registers.status.set_with_mask(mask,
|
self.registers.status.set_with_mask(
|
||||||
Status::new(StatusArgs { carry: did_carry,
|
mask,
|
||||||
|
Status::new(StatusArgs {
|
||||||
|
carry: did_carry,
|
||||||
overflow: did_overflow,
|
overflow: did_overflow,
|
||||||
..StatusArgs::none() } ));
|
..StatusArgs::none()
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
self.load_accumulator(a_after);
|
self.load_accumulator(a_after);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrement_memory(&mut self, addr: Address) {
|
fn decrement_memory(&mut self, addr: Address) {
|
||||||
let value_new = self.memory.get_byte(addr) - 1;
|
let value_new = self.memory.get_byte(addr).wrapping_sub(1);
|
||||||
|
|
||||||
self.memory.set_byte(addr, value_new);
|
self.memory.set_byte(addr, value_new);
|
||||||
|
|
||||||
@ -605,9 +631,12 @@ impl Machine {
|
|||||||
|
|
||||||
self.registers.status.set_with_mask(
|
self.registers.status.set_with_mask(
|
||||||
PS_NEGATIVE | PS_ZERO,
|
PS_NEGATIVE | PS_ZERO,
|
||||||
Status::new(StatusArgs { negative: is_negative,
|
Status::new(StatusArgs {
|
||||||
|
negative: is_negative,
|
||||||
zero: is_zero,
|
zero: is_zero,
|
||||||
..StatusArgs::none() } ));
|
..StatusArgs::none()
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dec_x(&mut self) {
|
fn dec_x(&mut self) {
|
||||||
@ -667,7 +696,7 @@ impl Machine {
|
|||||||
// If the C flag is 0, then A (unsigned) < NUM (unsigned) and BCC will branch
|
// If the C flag is 0, then A (unsigned) < NUM (unsigned) and BCC will branch
|
||||||
// If the C flag is 1, then A (unsigned) >= NUM (unsigned) and BCS will branch
|
// If the C flag is 1, then A (unsigned) >= NUM (unsigned) and BCS will branch
|
||||||
// ...
|
// ...
|
||||||
// The N flag contains most significant bit of the of the subtraction result.
|
// The N flag contains most significant bit of the subtraction result.
|
||||||
fn compare(&mut self, r: i8, val: u8) {
|
fn compare(&mut self, r: i8, val: u8) {
|
||||||
if r as u8 >= val as u8 {
|
if r as u8 >= val as u8 {
|
||||||
self.registers.status.insert(PS_CARRY);
|
self.registers.status.insert(PS_CARRY);
|
||||||
@ -681,7 +710,7 @@ impl Machine {
|
|||||||
self.registers.status.remove(PS_ZERO);
|
self.registers.status.remove(PS_ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
let diff: i8 = (r as i8) - (val as i8);
|
let diff: i8 = r.wrapping_sub(val as i8);
|
||||||
if diff < 0 {
|
if diff < 0 {
|
||||||
self.registers.status.insert(PS_NEGATIVE);
|
self.registers.status.insert(PS_NEGATIVE);
|
||||||
} else {
|
} else {
|
||||||
@ -732,11 +761,20 @@ impl Machine {
|
|||||||
|
|
||||||
impl std::fmt::Debug for Machine {
|
impl std::fmt::Debug for Machine {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
write!(f, "Machine Dump:\n\nAccumulator: {}",
|
write!(
|
||||||
self.registers.accumulator)
|
f,
|
||||||
|
"Machine Dump:\n\nAccumulator: {}",
|
||||||
|
self.registers.accumulator
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use num::range_inclusive;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_with_carry_test() {
|
fn add_with_carry_test() {
|
||||||
let mut machine = Machine::new();
|
let mut machine = Machine::new();
|
||||||
@ -934,40 +972,32 @@ fn logical_shift_right_test() {
|
|||||||
// Testing UseImplied version (which targets the accumulator) only, for now
|
// Testing UseImplied version (which targets the accumulator) only, for now
|
||||||
|
|
||||||
let mut machine = Machine::new();
|
let mut machine = Machine::new();
|
||||||
machine.execute_instruction((Instruction::LDA,
|
machine.execute_instruction((Instruction::LDA, OpInput::UseImmediate(0)));
|
||||||
OpInput::UseImmediate(0)));
|
machine.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||||
machine.execute_instruction((Instruction::LSR,
|
|
||||||
OpInput::UseImplied));
|
|
||||||
assert_eq!(machine.registers.accumulator, 0);
|
assert_eq!(machine.registers.accumulator, 0);
|
||||||
assert_eq!(machine.registers.status.contains(PS_CARRY), false);
|
assert_eq!(machine.registers.status.contains(PS_CARRY), false);
|
||||||
assert_eq!(machine.registers.status.contains(PS_ZERO), true);
|
assert_eq!(machine.registers.status.contains(PS_ZERO), true);
|
||||||
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false);
|
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false);
|
||||||
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
|
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
|
||||||
|
|
||||||
machine.execute_instruction((Instruction::LDA,
|
machine.execute_instruction((Instruction::LDA, OpInput::UseImmediate(1)));
|
||||||
OpInput::UseImmediate(1)));
|
machine.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||||
machine.execute_instruction((Instruction::LSR,
|
|
||||||
OpInput::UseImplied));
|
|
||||||
assert_eq!(machine.registers.accumulator, 0);
|
assert_eq!(machine.registers.accumulator, 0);
|
||||||
assert_eq!(machine.registers.status.contains(PS_CARRY), true);
|
assert_eq!(machine.registers.status.contains(PS_CARRY), true);
|
||||||
assert_eq!(machine.registers.status.contains(PS_ZERO), true);
|
assert_eq!(machine.registers.status.contains(PS_ZERO), true);
|
||||||
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false);
|
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false);
|
||||||
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
|
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
|
||||||
|
|
||||||
machine.execute_instruction((Instruction::LDA,
|
machine.execute_instruction((Instruction::LDA, OpInput::UseImmediate(255)));
|
||||||
OpInput::UseImmediate(255)));
|
machine.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||||
machine.execute_instruction((Instruction::LSR,
|
|
||||||
OpInput::UseImplied));
|
|
||||||
assert_eq!(machine.registers.accumulator, 0x7F);
|
assert_eq!(machine.registers.accumulator, 0x7F);
|
||||||
assert_eq!(machine.registers.status.contains(PS_CARRY), true);
|
assert_eq!(machine.registers.status.contains(PS_CARRY), true);
|
||||||
assert_eq!(machine.registers.status.contains(PS_ZERO), false);
|
assert_eq!(machine.registers.status.contains(PS_ZERO), false);
|
||||||
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false);
|
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false);
|
||||||
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
|
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
|
||||||
|
|
||||||
machine.execute_instruction((Instruction::LDA,
|
machine.execute_instruction((Instruction::LDA, OpInput::UseImmediate(254)));
|
||||||
OpInput::UseImmediate(254)));
|
machine.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||||
machine.execute_instruction((Instruction::LSR,
|
|
||||||
OpInput::UseImplied));
|
|
||||||
assert_eq!(machine.registers.accumulator, 0x7F);
|
assert_eq!(machine.registers.accumulator, 0x7F);
|
||||||
assert_eq!(machine.registers.status.contains(PS_CARRY), false);
|
assert_eq!(machine.registers.status.contains(PS_CARRY), false);
|
||||||
assert_eq!(machine.registers.status.contains(PS_ZERO), false);
|
assert_eq!(machine.registers.status.contains(PS_ZERO), false);
|
||||||
@ -1129,16 +1159,13 @@ fn branch_if_overflow_set_test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn compare_test_helper<F> (
|
fn compare_test_helper<F>(compare: &mut F, load_instruction: Instruction)
|
||||||
compare: &mut F,
|
where
|
||||||
load_instruction: Instruction
|
F: FnMut(&mut Machine, u8),
|
||||||
) where F: FnMut(&mut Machine, u8)
|
|
||||||
{
|
{
|
||||||
let mut machine = Machine::new();
|
let mut machine = Machine::new();
|
||||||
|
|
||||||
machine.execute_instruction(
|
machine.execute_instruction((load_instruction, OpInput::UseImmediate(127)));
|
||||||
(load_instruction, OpInput::UseImmediate(127))
|
|
||||||
);
|
|
||||||
|
|
||||||
compare(&mut machine, 127);
|
compare(&mut machine, 127);
|
||||||
assert!(machine.registers.status.contains(PS_ZERO));
|
assert!(machine.registers.status.contains(PS_ZERO));
|
||||||
@ -1146,9 +1173,7 @@ fn compare_test_helper<F> (
|
|||||||
assert!(!machine.registers.status.contains(PS_NEGATIVE));
|
assert!(!machine.registers.status.contains(PS_NEGATIVE));
|
||||||
|
|
||||||
|
|
||||||
machine.execute_instruction(
|
machine.execute_instruction((load_instruction, OpInput::UseImmediate(127)));
|
||||||
(load_instruction, OpInput::UseImmediate(127))
|
|
||||||
);
|
|
||||||
|
|
||||||
compare(&mut machine, 1);
|
compare(&mut machine, 1);
|
||||||
assert!(!machine.registers.status.contains(PS_ZERO));
|
assert!(!machine.registers.status.contains(PS_ZERO));
|
||||||
@ -1156,9 +1181,7 @@ fn compare_test_helper<F> (
|
|||||||
assert!(!machine.registers.status.contains(PS_NEGATIVE));
|
assert!(!machine.registers.status.contains(PS_NEGATIVE));
|
||||||
|
|
||||||
|
|
||||||
machine.execute_instruction(
|
machine.execute_instruction((load_instruction, OpInput::UseImmediate(1)));
|
||||||
(load_instruction, OpInput::UseImmediate(1))
|
|
||||||
);
|
|
||||||
|
|
||||||
compare(&mut machine, 2);
|
compare(&mut machine, 2);
|
||||||
assert!(!machine.registers.status.contains(PS_ZERO));
|
assert!(!machine.registers.status.contains(PS_ZERO));
|
||||||
@ -1166,31 +1189,25 @@ fn compare_test_helper<F> (
|
|||||||
assert!(machine.registers.status.contains(PS_NEGATIVE));
|
assert!(machine.registers.status.contains(PS_NEGATIVE));
|
||||||
|
|
||||||
|
|
||||||
machine.execute_instruction(
|
machine.execute_instruction((load_instruction, OpInput::UseImmediate(20)));
|
||||||
(load_instruction, OpInput::UseImmediate(20))
|
|
||||||
);
|
|
||||||
|
|
||||||
compare(&mut machine, -50);
|
compare(&mut machine, -50i8 as u8);
|
||||||
assert!(!machine.registers.status.contains(PS_ZERO));
|
assert!(!machine.registers.status.contains(PS_ZERO));
|
||||||
assert!(!machine.registers.status.contains(PS_CARRY));
|
assert!(!machine.registers.status.contains(PS_CARRY));
|
||||||
assert!(!machine.registers.status.contains(PS_NEGATIVE));
|
assert!(!machine.registers.status.contains(PS_NEGATIVE));
|
||||||
|
|
||||||
|
|
||||||
machine.execute_instruction(
|
machine.execute_instruction((load_instruction, OpInput::UseImmediate(1)));
|
||||||
(load_instruction, OpInput::UseImmediate(1))
|
|
||||||
);
|
|
||||||
|
|
||||||
compare(&mut machine, -1);
|
compare(&mut machine, -1i8 as u8);
|
||||||
assert!(!machine.registers.status.contains(PS_ZERO));
|
assert!(!machine.registers.status.contains(PS_ZERO));
|
||||||
assert!(!machine.registers.status.contains(PS_CARRY));
|
assert!(!machine.registers.status.contains(PS_CARRY));
|
||||||
assert!(!machine.registers.status.contains(PS_NEGATIVE));
|
assert!(!machine.registers.status.contains(PS_NEGATIVE));
|
||||||
|
|
||||||
|
|
||||||
machine.execute_instruction(
|
machine.execute_instruction((load_instruction, OpInput::UseImmediate(127)));
|
||||||
(load_instruction, OpInput::UseImmediate(127))
|
|
||||||
);
|
|
||||||
|
|
||||||
compare(&mut machine, -128);
|
compare(&mut machine, -128i8 as u8);
|
||||||
assert!(!machine.registers.status.contains(PS_ZERO));
|
assert!(!machine.registers.status.contains(PS_ZERO));
|
||||||
assert!(!machine.registers.status.contains(PS_CARRY));
|
assert!(!machine.registers.status.contains(PS_CARRY));
|
||||||
assert!(machine.registers.status.contains(PS_NEGATIVE));
|
assert!(machine.registers.status.contains(PS_NEGATIVE));
|
||||||
@ -1199,30 +1216,24 @@ fn compare_test_helper<F> (
|
|||||||
#[test]
|
#[test]
|
||||||
fn compare_with_a_register_test() {
|
fn compare_with_a_register_test() {
|
||||||
compare_test_helper(
|
compare_test_helper(
|
||||||
&mut |machine: &mut Machine, val: u8| {
|
&mut |machine: &mut Machine, val: u8| { machine.compare_with_a_register(val); },
|
||||||
machine.compare_with_a_register(val);
|
Instruction::LDA,
|
||||||
},
|
|
||||||
Instruction::LDA
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_with_x_register_test() {
|
fn compare_with_x_register_test() {
|
||||||
compare_test_helper(
|
compare_test_helper(
|
||||||
&mut |machine: &mut Machine, val: u8| {
|
&mut |machine: &mut Machine, val: u8| { machine.compare_with_x_register(val); },
|
||||||
machine.compare_with_x_register(val);
|
Instruction::LDX,
|
||||||
},
|
|
||||||
Instruction::LDX
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_with_y_register_test() {
|
fn compare_with_y_register_test() {
|
||||||
compare_test_helper(
|
compare_test_helper(
|
||||||
&mut |machine: &mut Machine, val: u8| {
|
&mut |machine: &mut Machine, val: u8| { machine.compare_with_y_register(val); },
|
||||||
machine.compare_with_y_register(val);
|
Instruction::LDY,
|
||||||
},
|
|
||||||
Instruction::LDY
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1230,11 +1241,9 @@ fn compare_with_y_register_test() {
|
|||||||
fn exclusive_or_test() {
|
fn exclusive_or_test() {
|
||||||
let mut machine = Machine::new();
|
let mut machine = Machine::new();
|
||||||
|
|
||||||
for a_before in range_incl(0u8, 255u8) {
|
for a_before in range_inclusive(0u8, 255u8) {
|
||||||
for val in range_incl(0u8, 255u8) {
|
for val in range_inclusive(0u8, 255u8) {
|
||||||
machine.execute_instruction(
|
machine.execute_instruction((Instruction::LDA, OpInput::UseImmediate(a_before)));
|
||||||
(Instruction::LDA, OpInput::UseImmediate(a_before))
|
|
||||||
);
|
|
||||||
|
|
||||||
machine.exclusive_or(val);
|
machine.exclusive_or(val);
|
||||||
|
|
||||||
@ -1260,11 +1269,9 @@ fn exclusive_or_test() {
|
|||||||
fn inclusive_or_test() {
|
fn inclusive_or_test() {
|
||||||
let mut machine = Machine::new();
|
let mut machine = Machine::new();
|
||||||
|
|
||||||
for a_before in range_incl(0u8, 255u8) {
|
for a_before in range_inclusive(0u8, 255u8) {
|
||||||
for val in range_incl(0u8, 255u8) {
|
for val in range_inclusive(0u8, 255u8) {
|
||||||
machine.execute_instruction(
|
machine.execute_instruction((Instruction::LDA, OpInput::UseImmediate(a_before)));
|
||||||
(Instruction::LDA, OpInput::UseImmediate(a_before))
|
|
||||||
);
|
|
||||||
|
|
||||||
machine.inclusive_or(val);
|
machine.inclusive_or(val);
|
||||||
|
|
||||||
@ -1285,3 +1292,4 @@ fn inclusive_or_test() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
use std::iter::repeat;
|
||||||
use address::{Address, AddressDiff};
|
use address::{Address, AddressDiff};
|
||||||
|
|
||||||
// JAM: We can probably come up with a better way to represent address ranges.
|
// JAM: We can probably come up with a better way to represent address ranges.
|
||||||
@ -46,17 +47,17 @@ pub const STACK_ADDRESS_HI: Address = Address(0x01FF);
|
|||||||
pub const IRQ_INTERRUPT_VECTOR_LO: Address = Address(0xFFFE);
|
pub const IRQ_INTERRUPT_VECTOR_LO: Address = Address(0xFFFE);
|
||||||
pub const IRQ_INTERRUPT_VECTOR_HI: Address = Address(0xFFFF);
|
pub const IRQ_INTERRUPT_VECTOR_HI: Address = Address(0xFFFF);
|
||||||
|
|
||||||
const MEMORY_SIZE: usize = (ADDR_HI_BARE - ADDR_LO_BARE) as usize + 1us;
|
const MEMORY_SIZE: usize = (ADDR_HI_BARE - ADDR_LO_BARE) as usize + 1usize;
|
||||||
|
|
||||||
// FIXME: Should this use indirection for `bytes`?
|
// FIXME: Should this use indirection for `bytes`?
|
||||||
#[derive(Copy)]
|
#[derive(Clone)]
|
||||||
pub struct Memory {
|
pub struct Memory {
|
||||||
bytes: [u8; MEMORY_SIZE]
|
bytes: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
pub fn new() -> Memory {
|
pub fn new() -> Memory {
|
||||||
Memory { bytes: [0; MEMORY_SIZE] }
|
Memory { bytes: repeat(0).take(MEMORY_SIZE).collect() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_byte(&self, address: Address) -> u8 {
|
pub fn get_byte(&self, address: Address) -> u8 {
|
||||||
@ -67,8 +68,7 @@ impl Memory {
|
|||||||
&mut self.bytes[address.to_usize()]
|
&mut self.bytes[address.to_usize()]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_slice(&self, Address(start): Address,
|
pub fn get_slice(&self, Address(start): Address, AddressDiff(diff): AddressDiff) -> &[u8] {
|
||||||
AddressDiff(diff): AddressDiff) -> &[u8] {
|
|
||||||
let start = start as usize;
|
let start = start as usize;
|
||||||
let diff = diff as usize;
|
let diff = diff as usize;
|
||||||
let end = start + diff;
|
let end = start + diff;
|
||||||
@ -100,4 +100,3 @@ impl Memory {
|
|||||||
STACK_ADDRESS_LO <= *address && *address <= STACK_ADDRESS_HI
|
STACK_ADDRESS_LO <= *address && *address <= STACK_ADDRESS_HI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
use std::num::Int;
|
|
||||||
|
|
||||||
pub struct RangeIncl<T: Int> {
|
|
||||||
state: Option<T>,
|
|
||||||
end: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn range_incl<T: Int>(begin: T, end: T) -> RangeIncl<T> {
|
|
||||||
RangeIncl { state: Some(begin), end: end }
|
|
||||||
}
|
|
||||||
|
|
||||||
trait One : Int {
|
|
||||||
fn my_one(_: Option<Self>) -> Self {
|
|
||||||
Int::one()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T> One for T where T: Int {}
|
|
||||||
|
|
||||||
impl<T: Int> Iterator for RangeIncl<T> {
|
|
||||||
type Item = T;
|
|
||||||
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
|
||||||
match self.state {
|
|
||||||
Some(current) => {
|
|
||||||
self.state =
|
|
||||||
if current == self.end { None }
|
|
||||||
else { Some(current + One::my_one(None::<T>)) };
|
|
||||||
Some(current)
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -29,7 +29,7 @@ use address::{Address, AddressDiff};
|
|||||||
use memory::{STACK_ADDRESS_LO, STACK_ADDRESS_HI};
|
use memory::{STACK_ADDRESS_LO, STACK_ADDRESS_HI};
|
||||||
|
|
||||||
// Useful for constructing Status instances
|
// Useful for constructing Status instances
|
||||||
#[derive(Copy)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct StatusArgs {
|
pub struct StatusArgs {
|
||||||
pub negative: bool,
|
pub negative: bool,
|
||||||
pub overflow: bool,
|
pub overflow: bool,
|
||||||
@ -43,31 +43,32 @@ pub struct StatusArgs {
|
|||||||
|
|
||||||
impl StatusArgs {
|
impl StatusArgs {
|
||||||
pub fn none() -> StatusArgs {
|
pub fn none() -> StatusArgs {
|
||||||
StatusArgs { negative: false,
|
StatusArgs {
|
||||||
|
negative: false,
|
||||||
overflow: false,
|
overflow: false,
|
||||||
unused: false,
|
unused: false,
|
||||||
brk: false,
|
brk: false,
|
||||||
decimal_mode: false,
|
decimal_mode: false,
|
||||||
disable_interrupts: false,
|
disable_interrupts: false,
|
||||||
zero: false,
|
zero: false,
|
||||||
carry: false, }
|
carry: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub bitflags! {
|
bitflags! {
|
||||||
#[derive(Debug)]
|
pub struct Status: u8 {
|
||||||
flags Status: u8 {
|
const PS_NEGATIVE = 0b10000000;
|
||||||
const PS_NEGATIVE = 0b10000000,
|
const PS_OVERFLOW = 0b01000000;
|
||||||
const PS_OVERFLOW = 0b01000000,
|
const PS_UNUSED = 0b00100000; // JAM: Should this exist?
|
||||||
const PS_UNUSED = 0b00100000, // JAM: Should this exist?
|
|
||||||
// (note that it affects the
|
// (note that it affects the
|
||||||
// behavior of things like
|
// behavior of things like
|
||||||
// from_bits_truncate)
|
// from_bits_truncate)
|
||||||
const PS_BRK = 0b00010000,
|
const PS_BRK = 0b00010000;
|
||||||
const PS_DECIMAL_MODE = 0b00001000,
|
const PS_DECIMAL_MODE = 0b00001000;
|
||||||
const PS_DISABLE_INTERRUPTS = 0b00000100,
|
const PS_DISABLE_INTERRUPTS = 0b00000100;
|
||||||
const PS_ZERO = 0b00000010,
|
const PS_ZERO = 0b00000010;
|
||||||
const PS_CARRY = 0b00000001,
|
const PS_CARRY = 0b00000001;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,14 +76,16 @@ impl Status {
|
|||||||
pub fn default() -> Status {
|
pub fn default() -> Status {
|
||||||
// TODO akeeton: Revisit these defaults.
|
// TODO akeeton: Revisit these defaults.
|
||||||
|
|
||||||
Status::new(StatusArgs { negative: false,
|
Status::new(StatusArgs {
|
||||||
|
negative: false,
|
||||||
overflow: false,
|
overflow: false,
|
||||||
unused: true,
|
unused: true,
|
||||||
brk: false,
|
brk: false,
|
||||||
decimal_mode: false,
|
decimal_mode: false,
|
||||||
disable_interrupts: true,
|
disable_interrupts: true,
|
||||||
zero: false,
|
zero: false,
|
||||||
carry: false, } )
|
carry: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(StatusArgs { negative,
|
pub fn new(StatusArgs { negative,
|
||||||
@ -96,14 +99,30 @@ impl Status {
|
|||||||
{
|
{
|
||||||
let mut out = Status::empty();
|
let mut out = Status::empty();
|
||||||
|
|
||||||
if negative { out = out | PS_NEGATIVE }
|
if negative {
|
||||||
if overflow { out = out | PS_OVERFLOW }
|
out = out | PS_NEGATIVE
|
||||||
if unused { out = out | PS_UNUSED }
|
}
|
||||||
if brk { out = out | PS_BRK }
|
if overflow {
|
||||||
if decimal_mode { out = out | PS_DECIMAL_MODE }
|
out = out | PS_OVERFLOW
|
||||||
if disable_interrupts { out = out | PS_DISABLE_INTERRUPTS }
|
}
|
||||||
if zero { out = out | PS_ZERO }
|
if unused {
|
||||||
if carry { out = out | PS_CARRY }
|
out = out | PS_UNUSED
|
||||||
|
}
|
||||||
|
if brk {
|
||||||
|
out = out | PS_BRK
|
||||||
|
}
|
||||||
|
if decimal_mode {
|
||||||
|
out = out | PS_DECIMAL_MODE
|
||||||
|
}
|
||||||
|
if disable_interrupts {
|
||||||
|
out = out | PS_DISABLE_INTERRUPTS
|
||||||
|
}
|
||||||
|
if zero {
|
||||||
|
out = out | PS_ZERO
|
||||||
|
}
|
||||||
|
if carry {
|
||||||
|
out = out | PS_CARRY
|
||||||
|
}
|
||||||
|
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
@ -121,12 +140,11 @@ impl Status {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
pub struct StackPointer(pub u8);
|
pub struct StackPointer(pub u8);
|
||||||
|
|
||||||
impl StackPointer {
|
impl StackPointer {
|
||||||
pub fn to_address(&self) -> Address
|
pub fn to_address(&self) -> Address {
|
||||||
{
|
|
||||||
let StackPointer(sp) = *self;
|
let StackPointer(sp) = *self;
|
||||||
STACK_ADDRESS_LO + AddressDiff(sp as i32)
|
STACK_ADDRESS_LO + AddressDiff(sp as i32)
|
||||||
}
|
}
|
||||||
@ -144,14 +162,14 @@ impl StackPointer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct Registers {
|
pub struct Registers {
|
||||||
pub accumulator: i8,
|
pub accumulator: i8,
|
||||||
pub index_x: i8,
|
pub index_x: i8,
|
||||||
pub index_y: i8,
|
pub index_y: i8,
|
||||||
pub stack_pointer: StackPointer,
|
pub stack_pointer: StackPointer,
|
||||||
pub program_counter: Address,
|
pub program_counter: Address,
|
||||||
pub status: Status
|
pub status: Status,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Registers {
|
impl Registers {
|
||||||
@ -163,8 +181,7 @@ impl Registers {
|
|||||||
index_y: 0,
|
index_y: 0,
|
||||||
stack_pointer: StackPointer(STACK_ADDRESS_HI.get_offset()),
|
stack_pointer: StackPointer(STACK_ADDRESS_HI.get_offset()),
|
||||||
program_counter: Address(0),
|
program_counter: Address(0),
|
||||||
status: Status::default()
|
status: Status::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user