mirror of
https://github.com/mre/mos6502.git
synced 2024-11-15 13:05:33 +00:00
Implement rest of shifts/rotates, and push/pull for accumulator and flags
This commit is contained in:
parent
40fe0a2ad4
commit
99abf0aa53
@ -27,9 +27,13 @@
|
|||||||
|
|
||||||
extern crate emu6502;
|
extern crate emu6502;
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
use emu6502::machine;
|
use emu6502::machine;
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
use emu6502::address::Address;
|
use emu6502::address::Address;
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut machine = machine::Machine::new();
|
let mut machine = machine::Machine::new();
|
||||||
|
|
||||||
|
119
src/machine.rs
119
src/machine.rs
@ -88,6 +88,20 @@ impl Machine {
|
|||||||
self.add_with_carry(val);
|
self.add_with_carry(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(instruction::ASL, instruction::UseImplied) => {
|
||||||
|
// Accumulator mode
|
||||||
|
let mut val = self.registers.accumulator as u8;
|
||||||
|
Machine::shift_left_with_flags(&mut val,
|
||||||
|
&mut self.registers.status);
|
||||||
|
self.registers.accumulator = val as i8;
|
||||||
|
|
||||||
|
}
|
||||||
|
(instruction::ASL, instruction::UseAddress(addr)) => {
|
||||||
|
Machine::shift_left_with_flags(
|
||||||
|
self.memory.get_byte_mut_ref(addr),
|
||||||
|
&mut self.registers.status);
|
||||||
|
}
|
||||||
|
|
||||||
(instruction::BIT, instruction::UseAddress(addr)) => {
|
(instruction::BIT, instruction::UseAddress(addr)) => {
|
||||||
let a: u8 = self.registers.accumulator as u8;
|
let a: u8 = self.registers.accumulator as u8;
|
||||||
let m: u8 = self.memory.get_byte(addr);
|
let m: u8 = self.memory.get_byte(addr);
|
||||||
@ -201,6 +215,55 @@ impl Machine {
|
|||||||
&mut self.registers.status);
|
&mut self.registers.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(instruction::PHA, instruction::UseImplied) => {
|
||||||
|
// Push accumulator
|
||||||
|
let val = self.registers.accumulator as u8;
|
||||||
|
self.push_on_stack(val);
|
||||||
|
}
|
||||||
|
(instruction::PHP, instruction::UseImplied) => {
|
||||||
|
// Push status
|
||||||
|
let val = self.registers.status.bits();
|
||||||
|
self.push_on_stack(val);
|
||||||
|
}
|
||||||
|
(instruction::PLA, instruction::UseImplied) => {
|
||||||
|
// Pull accumulator
|
||||||
|
let val: u8 = self.pull_from_stack();
|
||||||
|
self.registers.accumulator = val as i8;
|
||||||
|
}
|
||||||
|
(instruction::PLP, instruction::UseImplied) => {
|
||||||
|
// Pull status
|
||||||
|
let val: u8 = self.pull_from_stack();
|
||||||
|
// The `truncate` here won't do anything because we have a
|
||||||
|
// constant for the single unused flags bit. This probably
|
||||||
|
// corresponds to the behavior of the 6502...? FIXME: verify
|
||||||
|
self.registers.status = Status::from_bits_truncate(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
(instruction::ROL, instruction::UseImplied) => {
|
||||||
|
// Accumulator mode
|
||||||
|
let mut val = self.registers.accumulator as u8;
|
||||||
|
Machine::rotate_left_with_flags(&mut val,
|
||||||
|
&mut self.registers.status);
|
||||||
|
self.registers.accumulator = val as i8;
|
||||||
|
}
|
||||||
|
(instruction::ROL, instruction::UseAddress(addr)) => {
|
||||||
|
Machine::rotate_left_with_flags(
|
||||||
|
self.memory.get_byte_mut_ref(addr),
|
||||||
|
&mut self.registers.status);
|
||||||
|
}
|
||||||
|
(instruction::ROR, instruction::UseImplied) => {
|
||||||
|
// Accumulator mode
|
||||||
|
let mut val = self.registers.accumulator as u8;
|
||||||
|
Machine::rotate_right_with_flags(&mut val,
|
||||||
|
&mut self.registers.status);
|
||||||
|
self.registers.accumulator = val as i8;
|
||||||
|
}
|
||||||
|
(instruction::ROR, instruction::UseAddress(addr)) => {
|
||||||
|
Machine::rotate_right_with_flags(
|
||||||
|
self.memory.get_byte_mut_ref(addr),
|
||||||
|
&mut self.registers.status);
|
||||||
|
}
|
||||||
|
|
||||||
(instruction::SBC, instruction::UseImmediate(val)) => {
|
(instruction::SBC, instruction::UseImmediate(val)) => {
|
||||||
debug!("subtract with carry immediate: {}", val);
|
debug!("subtract with carry immediate: {}", val);
|
||||||
self.subtract_with_carry(val as i8);
|
self.subtract_with_carry(val as i8);
|
||||||
@ -292,12 +355,51 @@ impl Machine {
|
|||||||
..StatusArgs::none() } ));
|
..StatusArgs::none() } ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn shift_left_with_flags(p_val: &mut u8, status: &mut Status) {
|
||||||
|
let mask = 1 << 7;
|
||||||
|
let is_bit_7_set = (*p_val & mask) == mask;
|
||||||
|
let shifted = (*p_val & !(1 << 7)) << 1;
|
||||||
|
*p_val = shifted;
|
||||||
|
status.set_with_mask(
|
||||||
|
PS_CARRY,
|
||||||
|
Status::new(StatusArgs { carry: is_bit_7_set,
|
||||||
|
..StatusArgs::none() } ));
|
||||||
|
Machine::set_flags_from_i8(status, *p_val as i8);
|
||||||
|
}
|
||||||
|
|
||||||
fn shift_right_with_flags(p_val: &mut u8, status: &mut Status) {
|
fn shift_right_with_flags(p_val: &mut u8, status: &mut Status) {
|
||||||
let bit0 = *p_val & 1;
|
let mask = 1;
|
||||||
|
let is_bit_0_set = (*p_val & mask) == mask;
|
||||||
*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: bit0 == 1,
|
Status::new(StatusArgs { carry: is_bit_0_set,
|
||||||
|
..StatusArgs::none() } ));
|
||||||
|
Machine::set_flags_from_i8(status, *p_val as i8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotate_left_with_flags(p_val: &mut u8, status: &mut Status) {
|
||||||
|
let is_carry_set = status.contains(PS_CARRY);
|
||||||
|
let mask = 1 << 7;
|
||||||
|
let is_bit_7_set = (*p_val & mask) == mask;
|
||||||
|
let shifted = (*p_val & !(1 << 7)) << 1;
|
||||||
|
*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() } ));
|
||||||
|
Machine::set_flags_from_i8(status, *p_val as i8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotate_right_with_flags(p_val: &mut u8, status: &mut Status) {
|
||||||
|
let is_carry_set = status.contains(PS_CARRY);
|
||||||
|
let mask = 1;
|
||||||
|
let is_bit_0_set = (*p_val & mask) == mask;
|
||||||
|
let shifted = *p_val >> 1;
|
||||||
|
*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() } ));
|
..StatusArgs::none() } ));
|
||||||
Machine::set_flags_from_i8(status, *p_val as i8);
|
Machine::set_flags_from_i8(status, *p_val as i8);
|
||||||
}
|
}
|
||||||
@ -431,6 +533,19 @@ impl Machine {
|
|||||||
self.registers.program_counter = addr;
|
self.registers.program_counter = addr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn push_on_stack(&mut self, val: u8) {
|
||||||
|
let addr = self.registers.stack_pointer.to_address();
|
||||||
|
self.memory.set_byte(addr, val);
|
||||||
|
self.registers.stack_pointer.decrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pull_from_stack(&mut self) -> u8 {
|
||||||
|
let addr = self.registers.stack_pointer.to_address();
|
||||||
|
let out = self.memory.get_byte(addr);
|
||||||
|
self.registers.stack_pointer.increment();
|
||||||
|
out
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Show for Machine {
|
impl std::fmt::Show for Machine {
|
||||||
|
@ -59,6 +59,9 @@ pub bitflags! {
|
|||||||
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
|
||||||
|
// behavior of things like
|
||||||
|
// 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,
|
||||||
@ -121,10 +124,23 @@ impl Status {
|
|||||||
pub struct StackPointer(pub u8);
|
pub struct StackPointer(pub u8);
|
||||||
|
|
||||||
impl StackPointer {
|
impl StackPointer {
|
||||||
pub fn to_address(&StackPointer(sp): &StackPointer) -> Address
|
pub fn to_address(&self) -> Address
|
||||||
{
|
{
|
||||||
|
let StackPointer(sp) = *self;
|
||||||
STACK_ADDRESS_LO + AddressDiff(sp as i32)
|
STACK_ADDRESS_LO + AddressDiff(sp as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JAM: FIXME: Should we prevent overflow here? What would a 6502 do?
|
||||||
|
|
||||||
|
pub fn decrement(&mut self) {
|
||||||
|
let StackPointer(val) = *self;
|
||||||
|
*self = StackPointer(val - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increment(&mut self) {
|
||||||
|
let StackPointer(val) = *self;
|
||||||
|
*self = StackPointer(val + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq, Eq, Show)]
|
#[deriving(PartialEq, Eq, Show)]
|
||||||
|
Loading…
Reference in New Issue
Block a user