1
0
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:
Matthias Endler 2017-08-01 09:55:45 +02:00
parent 82e2cac30c
commit 0a3f628168
9 changed files with 1346 additions and 1107 deletions

View File

@ -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>

View File

@ -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"

View File

@ -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

View File

@ -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;

View File

@ -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() {
} }
} }
} }
}

View File

@ -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
} }
} }

View File

@ -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
}
}
}
}

View File

@ -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(),
} }
} }
} }