mirror of
https://github.com/mre/mos6502.git
synced 2024-11-21 22:31:44 +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>
|
||||
Andrew Keeton <andrewrkeeton@gmail.com>
|
||||
Johannes Muenzel <jmuenzel@gmail.com>
|
||||
Matthias Endler <matthias-endler@gmx.net>
|
@ -39,5 +39,6 @@ name = "emu6502"
|
||||
name = "emu6502"
|
||||
|
||||
[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
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
use std::num::Int;
|
||||
use std::ops::Add;
|
||||
|
||||
// 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
|
||||
// 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);
|
||||
|
||||
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct Address(pub u16);
|
||||
|
||||
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);
|
||||
|
||||
impl Add<CheckedAddressDiff> for Address {
|
||||
@ -77,7 +76,7 @@ impl Add<CheckedAddressDiff> for Address {
|
||||
impl Address {
|
||||
pub fn to_u16(&self) -> u16 {
|
||||
match *self {
|
||||
Address(address_) => address_
|
||||
Address(address_) => address_,
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,4 +92,3 @@ impl Address {
|
||||
(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
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#![feature(core)]
|
||||
#![feature(hash)]
|
||||
#![feature(rustc_private)]
|
||||
|
||||
// Needed for debug! / log! macros
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
extern crate num;
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_bitflags;
|
||||
extern crate bitflags;
|
||||
|
||||
pub mod address;
|
||||
pub mod instruction;
|
||||
pub mod machine;
|
||||
pub mod memory;
|
||||
pub mod range_incl;
|
||||
pub mod registers;
|
||||
|
324
src/machine.rs
324
src/machine.rs
@ -31,22 +31,21 @@ use address::{Address, AddressDiff};
|
||||
use instruction;
|
||||
use instruction::{DecodedInstr, Instruction, OpInput};
|
||||
use memory::Memory;
|
||||
use range_incl::range_incl;
|
||||
use registers::{Registers, StackPointer, Status, StatusArgs};
|
||||
use registers::{PS_NEGATIVE, PS_DECIMAL_MODE, PS_OVERFLOW, PS_ZERO, PS_CARRY,
|
||||
PS_DISABLE_INTERRUPTS};
|
||||
|
||||
#[derive(Copy)]
|
||||
#[derive(Clone)]
|
||||
pub struct Machine {
|
||||
pub registers: Registers,
|
||||
pub memory: Memory
|
||||
pub memory: Memory,
|
||||
}
|
||||
|
||||
impl Machine {
|
||||
pub fn new() -> Machine {
|
||||
Machine {
|
||||
registers: Registers::new(),
|
||||
memory: Memory::new()
|
||||
memory: Memory::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,19 +61,17 @@ impl Machine {
|
||||
let extra_bytes = am.extra_bytes();
|
||||
let num_bytes = AddressDiff(1) + extra_bytes;
|
||||
|
||||
let data_start = self.registers.program_counter
|
||||
+ AddressDiff(1);
|
||||
let data_start = self.registers.program_counter + AddressDiff(1);
|
||||
|
||||
let slice = self.memory.get_slice(data_start, extra_bytes);
|
||||
let am_out = am.process(self, slice);
|
||||
|
||||
// Increment program counter
|
||||
self.registers.program_counter =
|
||||
self.registers.program_counter + num_bytes;
|
||||
self.registers.program_counter = self.registers.program_counter + num_bytes;
|
||||
|
||||
Some((instr, am_out))
|
||||
}
|
||||
_ => None
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,32 +98,29 @@ impl Machine {
|
||||
(Instruction::ASL, OpInput::UseImplied) => {
|
||||
// Accumulator mode
|
||||
let mut val = self.registers.accumulator as u8;
|
||||
Machine::shift_left_with_flags(&mut val,
|
||||
&mut self.registers.status);
|
||||
Machine::shift_left_with_flags(&mut val, &mut self.registers.status);
|
||||
self.registers.accumulator = val as i8;
|
||||
|
||||
}
|
||||
(Instruction::ASL, OpInput::UseAddress(addr)) => {
|
||||
Machine::shift_left_with_flags(
|
||||
self.memory.get_byte_mut_ref(addr),
|
||||
&mut self.registers.status);
|
||||
&mut self.registers.status,
|
||||
);
|
||||
}
|
||||
|
||||
(Instruction::BCC, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||
self.branch_if_carry_clear(addr);
|
||||
}
|
||||
|
||||
(Instruction::BCS, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||
self.branch_if_carry_set(addr);
|
||||
}
|
||||
|
||||
(Instruction::BEQ, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||
self.branch_if_equal(addr);
|
||||
}
|
||||
|
||||
@ -146,34 +140,33 @@ impl Machine {
|
||||
|
||||
self.registers.status.set_with_mask(
|
||||
PS_ZERO | PS_NEGATIVE | PS_OVERFLOW,
|
||||
Status::new(StatusArgs { zero: is_zero,
|
||||
Status::new(StatusArgs {
|
||||
zero: is_zero,
|
||||
negative: bit7,
|
||||
overflow: bit6,
|
||||
..StatusArgs::none() } ));
|
||||
..StatusArgs::none()
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
(Instruction::BMI, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||
debug!("branch if minus relative. address: {:?}", addr);
|
||||
self.branch_if_minus(addr);
|
||||
}
|
||||
|
||||
(Instruction::BPL, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||
self.branch_if_positive(addr);
|
||||
}
|
||||
|
||||
(Instruction::BVC, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||
self.branch_if_overflow_clear(addr);
|
||||
}
|
||||
|
||||
(Instruction::BVS, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
let addr = self.registers.program_counter + AddressDiff(rel as i32);
|
||||
self.branch_if_overflow_set(addr);
|
||||
}
|
||||
|
||||
@ -214,9 +207,7 @@ impl Machine {
|
||||
self.compare_with_y_register(val);
|
||||
}
|
||||
|
||||
(Instruction::DEC, OpInput::UseAddress(addr)) => {
|
||||
self.decrement_memory(addr)
|
||||
}
|
||||
(Instruction::DEC, OpInput::UseAddress(addr)) => self.decrement_memory(addr),
|
||||
|
||||
(Instruction::DEX, OpInput::UseImplied) => {
|
||||
self.dec_x();
|
||||
@ -246,9 +237,7 @@ impl Machine {
|
||||
self.load_y_register(y);
|
||||
}
|
||||
|
||||
(Instruction::JMP, OpInput::UseAddress(addr)) => {
|
||||
self.jump(addr)
|
||||
}
|
||||
(Instruction::JMP, OpInput::UseAddress(addr)) => self.jump(addr),
|
||||
|
||||
(Instruction::LDA, OpInput::UseImmediate(val)) => {
|
||||
debug!("load A immediate: {}", val);
|
||||
@ -283,14 +272,14 @@ impl Machine {
|
||||
(Instruction::LSR, OpInput::UseImplied) => {
|
||||
// Accumulator mode
|
||||
let mut val = self.registers.accumulator as u8;
|
||||
Machine::shift_right_with_flags(&mut val,
|
||||
&mut self.registers.status);
|
||||
Machine::shift_right_with_flags(&mut val, &mut self.registers.status);
|
||||
self.registers.accumulator = val as i8;
|
||||
}
|
||||
(Instruction::LSR, OpInput::UseAddress(addr)) => {
|
||||
Machine::shift_right_with_flags(
|
||||
self.memory.get_byte_mut_ref(addr),
|
||||
&mut self.registers.status);
|
||||
&mut self.registers.status,
|
||||
);
|
||||
}
|
||||
|
||||
(Instruction::ORA, OpInput::UseImmediate(val)) => {
|
||||
@ -328,26 +317,26 @@ impl Machine {
|
||||
(Instruction::ROL, OpInput::UseImplied) => {
|
||||
// Accumulator mode
|
||||
let mut val = self.registers.accumulator as u8;
|
||||
Machine::rotate_left_with_flags(&mut val,
|
||||
&mut self.registers.status);
|
||||
Machine::rotate_left_with_flags(&mut val, &mut self.registers.status);
|
||||
self.registers.accumulator = val as i8;
|
||||
}
|
||||
(Instruction::ROL, OpInput::UseAddress(addr)) => {
|
||||
Machine::rotate_left_with_flags(
|
||||
self.memory.get_byte_mut_ref(addr),
|
||||
&mut self.registers.status);
|
||||
&mut self.registers.status,
|
||||
);
|
||||
}
|
||||
(Instruction::ROR, OpInput::UseImplied) => {
|
||||
// Accumulator mode
|
||||
let mut val = self.registers.accumulator as u8;
|
||||
Machine::rotate_right_with_flags(&mut val,
|
||||
&mut self.registers.status);
|
||||
Machine::rotate_right_with_flags(&mut val, &mut self.registers.status);
|
||||
self.registers.accumulator = val as i8;
|
||||
}
|
||||
(Instruction::ROR, OpInput::UseAddress(addr)) => {
|
||||
Machine::rotate_right_with_flags(
|
||||
self.memory.get_byte_mut_ref(addr),
|
||||
&mut self.registers.status);
|
||||
&mut self.registers.status,
|
||||
);
|
||||
}
|
||||
|
||||
(Instruction::SBC, OpInput::UseImmediate(val)) => {
|
||||
@ -356,8 +345,7 @@ impl Machine {
|
||||
}
|
||||
(Instruction::SBC, OpInput::UseAddress(addr)) => {
|
||||
let val = self.memory.get_byte(addr) as i8;
|
||||
debug!("subtract with carry. address: {:?}. value: {}",
|
||||
addr, val);
|
||||
debug!("subtract with carry. address: {:?}. value: {}", addr, val);
|
||||
self.subtract_with_carry(val);
|
||||
}
|
||||
|
||||
@ -414,8 +402,10 @@ impl Machine {
|
||||
debug!("NOP instruction");
|
||||
}
|
||||
(_, _) => {
|
||||
debug!("attempting to execute unimplemented or invalid \
|
||||
instruction");
|
||||
debug!(
|
||||
"attempting to execute unimplemented or invalid \
|
||||
instruction"
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -425,7 +415,7 @@ impl Machine {
|
||||
if let Some(decoded_instr) = self.fetch_next_and_decode() {
|
||||
self.execute_instruction(decoded_instr);
|
||||
} else {
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -436,9 +426,12 @@ impl Machine {
|
||||
|
||||
status.set_with_mask(
|
||||
PS_ZERO | PS_NEGATIVE,
|
||||
Status::new(StatusArgs { zero: is_zero,
|
||||
Status::new(StatusArgs {
|
||||
zero: is_zero,
|
||||
negative: is_negative,
|
||||
..StatusArgs::none() } ));
|
||||
..StatusArgs::none()
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
fn shift_left_with_flags(p_val: &mut u8, status: &mut Status) {
|
||||
@ -448,8 +441,11 @@ impl Machine {
|
||||
*p_val = shifted;
|
||||
status.set_with_mask(
|
||||
PS_CARRY,
|
||||
Status::new(StatusArgs { carry: is_bit_7_set,
|
||||
..StatusArgs::none() } ));
|
||||
Status::new(StatusArgs {
|
||||
carry: is_bit_7_set,
|
||||
..StatusArgs::none()
|
||||
}),
|
||||
);
|
||||
Machine::set_flags_from_i8(status, *p_val as i8);
|
||||
}
|
||||
|
||||
@ -459,8 +455,11 @@ impl Machine {
|
||||
*p_val = *p_val >> 1;
|
||||
status.set_with_mask(
|
||||
PS_CARRY,
|
||||
Status::new(StatusArgs { carry: is_bit_0_set,
|
||||
..StatusArgs::none() } ));
|
||||
Status::new(StatusArgs {
|
||||
carry: is_bit_0_set,
|
||||
..StatusArgs::none()
|
||||
}),
|
||||
);
|
||||
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 };
|
||||
status.set_with_mask(
|
||||
PS_CARRY,
|
||||
Status::new(StatusArgs { carry: is_bit_7_set,
|
||||
..StatusArgs::none() } ));
|
||||
Status::new(StatusArgs {
|
||||
carry: is_bit_7_set,
|
||||
..StatusArgs::none()
|
||||
}),
|
||||
);
|
||||
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 };
|
||||
status.set_with_mask(
|
||||
PS_CARRY,
|
||||
Status::new(StatusArgs { carry: is_bit_0_set,
|
||||
..StatusArgs::none() } ));
|
||||
Status::new(StatusArgs {
|
||||
carry: is_bit_0_set,
|
||||
..StatusArgs::none()
|
||||
}),
|
||||
);
|
||||
Machine::set_flags_from_i8(status, *p_val as i8);
|
||||
}
|
||||
|
||||
@ -496,21 +501,27 @@ impl Machine {
|
||||
}
|
||||
|
||||
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,
|
||||
value);
|
||||
value,
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
value);
|
||||
value,
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
value);
|
||||
value,
|
||||
);
|
||||
}
|
||||
|
||||
fn add_with_carry(&mut self, value: i8) {
|
||||
@ -519,25 +530,33 @@ impl Machine {
|
||||
debug!("binary-coded decimal not implemented for add_with_carry");
|
||||
} else {
|
||||
let a_before: i8 = self.registers.accumulator;
|
||||
let c_before: i8 = if self.registers.status.contains(PS_CARRY)
|
||||
{ 1 } else { 0 };
|
||||
let a_after: i8 = a_before + c_before + value;
|
||||
let c_before: i8 = if self.registers.status.contains(PS_CARRY) {
|
||||
1
|
||||
} 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
|
||||
+ value as u8);
|
||||
debug_assert_eq!(
|
||||
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_overflow =
|
||||
(a_before < 0 && value < 0 && a_after >= 0)
|
||||
|| (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);
|
||||
|
||||
let mask = PS_CARRY | PS_OVERFLOW;
|
||||
|
||||
self.registers.status.set_with_mask(mask,
|
||||
Status::new(StatusArgs { carry: did_carry,
|
||||
self.registers.status.set_with_mask(
|
||||
mask,
|
||||
Status::new(StatusArgs {
|
||||
carry: did_carry,
|
||||
overflow: did_overflow,
|
||||
..StatusArgs::none() } ));
|
||||
..StatusArgs::none()
|
||||
}),
|
||||
);
|
||||
|
||||
self.load_accumulator(a_after);
|
||||
|
||||
@ -553,18 +572,23 @@ impl Machine {
|
||||
// TODO: Implement binary-coded decimal
|
||||
fn subtract_with_carry(&mut self, value: i8) {
|
||||
if self.registers.status.contains(PS_DECIMAL_MODE) {
|
||||
debug!("binary-coded decimal not implemented for \
|
||||
subtract_with_carry");
|
||||
debug!(
|
||||
"binary-coded decimal not implemented for \
|
||||
subtract_with_carry"
|
||||
);
|
||||
} else {
|
||||
// A - M - (1 - C)
|
||||
|
||||
// nc -- 'not carry'
|
||||
let nc: i8 = if self.registers.status.contains(PS_CARRY)
|
||||
{ 0 } else { 1 };
|
||||
let nc: i8 = if self.registers.status.contains(PS_CARRY) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
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.
|
||||
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
|
||||
// -(127 + 1) to -(-128 + 0)
|
||||
//
|
||||
let over = ((nc == 0 && value < 0) || (nc == 1 && value < -1))
|
||||
&& a_before >= 0
|
||||
&& a_after < 0;
|
||||
let over = ((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 mask = PS_CARRY | PS_OVERFLOW;
|
||||
|
||||
self.registers.status.set_with_mask(mask,
|
||||
Status::new(StatusArgs { carry: did_carry,
|
||||
self.registers.status.set_with_mask(
|
||||
mask,
|
||||
Status::new(StatusArgs {
|
||||
carry: did_carry,
|
||||
overflow: did_overflow,
|
||||
..StatusArgs::none() } ));
|
||||
..StatusArgs::none()
|
||||
}),
|
||||
);
|
||||
|
||||
self.load_accumulator(a_after);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -605,9 +631,12 @@ impl Machine {
|
||||
|
||||
self.registers.status.set_with_mask(
|
||||
PS_NEGATIVE | PS_ZERO,
|
||||
Status::new(StatusArgs { negative: is_negative,
|
||||
Status::new(StatusArgs {
|
||||
negative: is_negative,
|
||||
zero: is_zero,
|
||||
..StatusArgs::none() } ));
|
||||
..StatusArgs::none()
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
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 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) {
|
||||
if r as u8 >= val as u8 {
|
||||
self.registers.status.insert(PS_CARRY);
|
||||
@ -681,7 +710,7 @@ impl Machine {
|
||||
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 {
|
||||
self.registers.status.insert(PS_NEGATIVE);
|
||||
} else {
|
||||
@ -732,11 +761,20 @@ impl Machine {
|
||||
|
||||
impl std::fmt::Debug for Machine {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "Machine Dump:\n\nAccumulator: {}",
|
||||
self.registers.accumulator)
|
||||
write!(
|
||||
f,
|
||||
"Machine Dump:\n\nAccumulator: {}",
|
||||
self.registers.accumulator
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use num::range_inclusive;
|
||||
|
||||
#[test]
|
||||
fn add_with_carry_test() {
|
||||
let mut machine = Machine::new();
|
||||
@ -934,40 +972,32 @@ fn logical_shift_right_test() {
|
||||
// Testing UseImplied version (which targets the accumulator) only, for now
|
||||
|
||||
let mut machine = Machine::new();
|
||||
machine.execute_instruction((Instruction::LDA,
|
||||
OpInput::UseImmediate(0)));
|
||||
machine.execute_instruction((Instruction::LSR,
|
||||
OpInput::UseImplied));
|
||||
machine.execute_instruction((Instruction::LDA, OpInput::UseImmediate(0)));
|
||||
machine.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||
assert_eq!(machine.registers.accumulator, 0);
|
||||
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_NEGATIVE), false);
|
||||
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
machine.execute_instruction((Instruction::LDA,
|
||||
OpInput::UseImmediate(1)));
|
||||
machine.execute_instruction((Instruction::LSR,
|
||||
OpInput::UseImplied));
|
||||
machine.execute_instruction((Instruction::LDA, OpInput::UseImmediate(1)));
|
||||
machine.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||
assert_eq!(machine.registers.accumulator, 0);
|
||||
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_NEGATIVE), false);
|
||||
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
machine.execute_instruction((Instruction::LDA,
|
||||
OpInput::UseImmediate(255)));
|
||||
machine.execute_instruction((Instruction::LSR,
|
||||
OpInput::UseImplied));
|
||||
machine.execute_instruction((Instruction::LDA, OpInput::UseImmediate(255)));
|
||||
machine.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||
assert_eq!(machine.registers.accumulator, 0x7F);
|
||||
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_NEGATIVE), false);
|
||||
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
machine.execute_instruction((Instruction::LDA,
|
||||
OpInput::UseImmediate(254)));
|
||||
machine.execute_instruction((Instruction::LSR,
|
||||
OpInput::UseImplied));
|
||||
machine.execute_instruction((Instruction::LDA, OpInput::UseImmediate(254)));
|
||||
machine.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||
assert_eq!(machine.registers.accumulator, 0x7F);
|
||||
assert_eq!(machine.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(machine.registers.status.contains(PS_ZERO), false);
|
||||
@ -1129,16 +1159,13 @@ fn branch_if_overflow_set_test() {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn compare_test_helper<F> (
|
||||
compare: &mut F,
|
||||
load_instruction: Instruction
|
||||
) where F: FnMut(&mut Machine, u8)
|
||||
fn compare_test_helper<F>(compare: &mut F, load_instruction: Instruction)
|
||||
where
|
||||
F: FnMut(&mut Machine, u8),
|
||||
{
|
||||
let mut machine = Machine::new();
|
||||
|
||||
machine.execute_instruction(
|
||||
(load_instruction, OpInput::UseImmediate(127))
|
||||
);
|
||||
machine.execute_instruction((load_instruction, OpInput::UseImmediate(127)));
|
||||
|
||||
compare(&mut machine, 127);
|
||||
assert!(machine.registers.status.contains(PS_ZERO));
|
||||
@ -1146,9 +1173,7 @@ fn compare_test_helper<F> (
|
||||
assert!(!machine.registers.status.contains(PS_NEGATIVE));
|
||||
|
||||
|
||||
machine.execute_instruction(
|
||||
(load_instruction, OpInput::UseImmediate(127))
|
||||
);
|
||||
machine.execute_instruction((load_instruction, OpInput::UseImmediate(127)));
|
||||
|
||||
compare(&mut machine, 1);
|
||||
assert!(!machine.registers.status.contains(PS_ZERO));
|
||||
@ -1156,9 +1181,7 @@ fn compare_test_helper<F> (
|
||||
assert!(!machine.registers.status.contains(PS_NEGATIVE));
|
||||
|
||||
|
||||
machine.execute_instruction(
|
||||
(load_instruction, OpInput::UseImmediate(1))
|
||||
);
|
||||
machine.execute_instruction((load_instruction, OpInput::UseImmediate(1)));
|
||||
|
||||
compare(&mut machine, 2);
|
||||
assert!(!machine.registers.status.contains(PS_ZERO));
|
||||
@ -1166,31 +1189,25 @@ fn compare_test_helper<F> (
|
||||
assert!(machine.registers.status.contains(PS_NEGATIVE));
|
||||
|
||||
|
||||
machine.execute_instruction(
|
||||
(load_instruction, OpInput::UseImmediate(20))
|
||||
);
|
||||
machine.execute_instruction((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_CARRY));
|
||||
assert!(!machine.registers.status.contains(PS_NEGATIVE));
|
||||
|
||||
|
||||
machine.execute_instruction(
|
||||
(load_instruction, OpInput::UseImmediate(1))
|
||||
);
|
||||
machine.execute_instruction((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_CARRY));
|
||||
assert!(!machine.registers.status.contains(PS_NEGATIVE));
|
||||
|
||||
|
||||
machine.execute_instruction(
|
||||
(load_instruction, OpInput::UseImmediate(127))
|
||||
);
|
||||
machine.execute_instruction((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_CARRY));
|
||||
assert!(machine.registers.status.contains(PS_NEGATIVE));
|
||||
@ -1199,30 +1216,24 @@ fn compare_test_helper<F> (
|
||||
#[test]
|
||||
fn compare_with_a_register_test() {
|
||||
compare_test_helper(
|
||||
&mut |machine: &mut Machine, val: u8| {
|
||||
machine.compare_with_a_register(val);
|
||||
},
|
||||
Instruction::LDA
|
||||
&mut |machine: &mut Machine, val: u8| { machine.compare_with_a_register(val); },
|
||||
Instruction::LDA,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_with_x_register_test() {
|
||||
compare_test_helper(
|
||||
&mut |machine: &mut Machine, val: u8| {
|
||||
machine.compare_with_x_register(val);
|
||||
},
|
||||
Instruction::LDX
|
||||
&mut |machine: &mut Machine, val: u8| { machine.compare_with_x_register(val); },
|
||||
Instruction::LDX,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_with_y_register_test() {
|
||||
compare_test_helper(
|
||||
&mut |machine: &mut Machine, val: u8| {
|
||||
machine.compare_with_y_register(val);
|
||||
},
|
||||
Instruction::LDY
|
||||
&mut |machine: &mut Machine, val: u8| { machine.compare_with_y_register(val); },
|
||||
Instruction::LDY,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1230,11 +1241,9 @@ fn compare_with_y_register_test() {
|
||||
fn exclusive_or_test() {
|
||||
let mut machine = Machine::new();
|
||||
|
||||
for a_before in range_incl(0u8, 255u8) {
|
||||
for val in range_incl(0u8, 255u8) {
|
||||
machine.execute_instruction(
|
||||
(Instruction::LDA, OpInput::UseImmediate(a_before))
|
||||
);
|
||||
for a_before in range_inclusive(0u8, 255u8) {
|
||||
for val in range_inclusive(0u8, 255u8) {
|
||||
machine.execute_instruction((Instruction::LDA, OpInput::UseImmediate(a_before)));
|
||||
|
||||
machine.exclusive_or(val);
|
||||
|
||||
@ -1260,11 +1269,9 @@ fn exclusive_or_test() {
|
||||
fn inclusive_or_test() {
|
||||
let mut machine = Machine::new();
|
||||
|
||||
for a_before in range_incl(0u8, 255u8) {
|
||||
for val in range_incl(0u8, 255u8) {
|
||||
machine.execute_instruction(
|
||||
(Instruction::LDA, OpInput::UseImmediate(a_before))
|
||||
);
|
||||
for a_before in range_inclusive(0u8, 255u8) {
|
||||
for val in range_inclusive(0u8, 255u8) {
|
||||
machine.execute_instruction((Instruction::LDA, OpInput::UseImmediate(a_before)));
|
||||
|
||||
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
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
use std::iter::repeat;
|
||||
use address::{Address, AddressDiff};
|
||||
|
||||
// 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_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`?
|
||||
#[derive(Copy)]
|
||||
#[derive(Clone)]
|
||||
pub struct Memory {
|
||||
bytes: [u8; MEMORY_SIZE]
|
||||
bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl 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 {
|
||||
@ -67,8 +68,7 @@ impl Memory {
|
||||
&mut self.bytes[address.to_usize()]
|
||||
}
|
||||
|
||||
pub fn get_slice(&self, Address(start): Address,
|
||||
AddressDiff(diff): AddressDiff) -> &[u8] {
|
||||
pub fn get_slice(&self, Address(start): Address, AddressDiff(diff): AddressDiff) -> &[u8] {
|
||||
let start = start as usize;
|
||||
let diff = diff as usize;
|
||||
let end = start + diff;
|
||||
@ -100,4 +100,3 @@ impl Memory {
|
||||
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};
|
||||
|
||||
// Useful for constructing Status instances
|
||||
#[derive(Copy)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct StatusArgs {
|
||||
pub negative: bool,
|
||||
pub overflow: bool,
|
||||
@ -43,31 +43,32 @@ pub struct StatusArgs {
|
||||
|
||||
impl StatusArgs {
|
||||
pub fn none() -> StatusArgs {
|
||||
StatusArgs { negative: false,
|
||||
StatusArgs {
|
||||
negative: false,
|
||||
overflow: false,
|
||||
unused: false,
|
||||
brk: false,
|
||||
decimal_mode: false,
|
||||
disable_interrupts: false,
|
||||
zero: false,
|
||||
carry: false, }
|
||||
carry: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub bitflags! {
|
||||
#[derive(Debug)]
|
||||
flags Status: u8 {
|
||||
const PS_NEGATIVE = 0b10000000,
|
||||
const PS_OVERFLOW = 0b01000000,
|
||||
const PS_UNUSED = 0b00100000, // JAM: Should this exist?
|
||||
bitflags! {
|
||||
pub struct Status: u8 {
|
||||
const PS_NEGATIVE = 0b10000000;
|
||||
const PS_OVERFLOW = 0b01000000;
|
||||
const PS_UNUSED = 0b00100000; // JAM: Should this exist?
|
||||
// (note that it affects the
|
||||
// behavior of things like
|
||||
// from_bits_truncate)
|
||||
const PS_BRK = 0b00010000,
|
||||
const PS_DECIMAL_MODE = 0b00001000,
|
||||
const PS_DISABLE_INTERRUPTS = 0b00000100,
|
||||
const PS_ZERO = 0b00000010,
|
||||
const PS_CARRY = 0b00000001,
|
||||
const PS_BRK = 0b00010000;
|
||||
const PS_DECIMAL_MODE = 0b00001000;
|
||||
const PS_DISABLE_INTERRUPTS = 0b00000100;
|
||||
const PS_ZERO = 0b00000010;
|
||||
const PS_CARRY = 0b00000001;
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,14 +76,16 @@ impl Status {
|
||||
pub fn default() -> Status {
|
||||
// TODO akeeton: Revisit these defaults.
|
||||
|
||||
Status::new(StatusArgs { negative: false,
|
||||
Status::new(StatusArgs {
|
||||
negative: false,
|
||||
overflow: false,
|
||||
unused: true,
|
||||
brk: false,
|
||||
decimal_mode: false,
|
||||
disable_interrupts: true,
|
||||
zero: false,
|
||||
carry: false, } )
|
||||
carry: false,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new(StatusArgs { negative,
|
||||
@ -96,14 +99,30 @@ impl Status {
|
||||
{
|
||||
let mut out = Status::empty();
|
||||
|
||||
if negative { out = out | PS_NEGATIVE }
|
||||
if overflow { out = out | PS_OVERFLOW }
|
||||
if unused { 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 }
|
||||
if negative {
|
||||
out = out | PS_NEGATIVE
|
||||
}
|
||||
if overflow {
|
||||
out = out | PS_OVERFLOW
|
||||
}
|
||||
if unused {
|
||||
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
|
||||
}
|
||||
@ -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);
|
||||
|
||||
impl StackPointer {
|
||||
pub fn to_address(&self) -> Address
|
||||
{
|
||||
pub fn to_address(&self) -> Address {
|
||||
let StackPointer(sp) = *self;
|
||||
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 accumulator: i8,
|
||||
pub index_x: i8,
|
||||
pub index_y: i8,
|
||||
pub stack_pointer: StackPointer,
|
||||
pub program_counter: Address,
|
||||
pub status: Status
|
||||
pub status: Status,
|
||||
}
|
||||
|
||||
impl Registers {
|
||||
@ -163,8 +181,7 @@ impl Registers {
|
||||
index_y: 0,
|
||||
stack_pointer: StackPointer(STACK_ADDRESS_HI.get_offset()),
|
||||
program_counter: Address(0),
|
||||
status: Status::default()
|
||||
status: Status::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user