1
0
mirror of https://github.com/mre/mos6502.git synced 2024-06-13 00:29:33 +00:00

Merge branch 'master' into incdec

This commit is contained in:
omarandlorraine 2022-10-21 09:10:18 +01:00 committed by GitHub
commit 32f925feb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 153 additions and 218 deletions

View File

@ -20,7 +20,6 @@ Source: [Wikipedia](https://en.wikipedia.org/wiki/MOS_Technology_6502)
## How to use this library ## How to use this library
```rust ```rust
use mos6502::address::Address;
use mos6502::cpu; use mos6502::cpu;
fn main() { fn main() {
@ -52,9 +51,9 @@ fn main() {
let mut cpu = cpu::CPU::new(); let mut cpu = cpu::CPU::new();
cpu.memory.set_bytes(Address(0x00), &zero_page_data); cpu.memory.set_bytes(0x00, &zero_page_data);
cpu.memory.set_bytes(Address(0x10), &program); cpu.memory.set_bytes(0x10, &program);
cpu.registers.program_counter = Address(0x10); cpu.registers.program_counter = 0x10;
cpu.run(); cpu.run();

View File

@ -1,5 +1,5 @@
extern crate mos6502; extern crate mos6502;
use mos6502::address::Address;
use mos6502::cpu; use mos6502::cpu;
fn main() { fn main() {
@ -35,9 +35,9 @@ fn main() {
let mut cpu = cpu::CPU::new(); let mut cpu = cpu::CPU::new();
cpu.memory.set_bytes(Address(0x00), &zero_page_data); cpu.memory.set_bytes(0x00, &zero_page_data);
cpu.memory.set_bytes(Address(0x10), &program); cpu.memory.set_bytes(0x10, &program);
cpu.registers.program_counter = Address(0x10); cpu.registers.program_counter = 0x10;
cpu.run(); cpu.run();

View File

@ -30,9 +30,6 @@ extern crate mos6502;
#[cfg(not(test))] #[cfg(not(test))]
use mos6502::cpu; use mos6502::cpu;
#[cfg(not(test))]
use mos6502::address::Address;
#[cfg(not(test))] #[cfg(not(test))]
fn main() { fn main() {
let mut cpu = cpu::CPU::new(); let mut cpu = cpu::CPU::new();
@ -94,11 +91,11 @@ fn main() {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, // ADC IndirectIndexedY target 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, // ADC IndirectIndexedY target
]; ];
cpu.memory.set_bytes(Address(0x0000), &zero_page_data); cpu.memory.set_bytes(0x0000, &zero_page_data);
cpu.memory.set_bytes(Address(0x4000), &program); cpu.memory.set_bytes(0x4000, &program);
cpu.memory.set_bytes(Address(0x8000), &data); cpu.memory.set_bytes(0x8000, &data);
cpu.registers.program_counter = Address(0x4000); cpu.registers.program_counter = 0x4000;
cpu.run(); cpu.run();

View File

@ -1,91 +0,0 @@
// Copyright (C) 2014 The 6502-rs Developers
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the names of the copyright holders nor the names of any
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
use core::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, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct AddressDiff(pub i32);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Address(pub u16);
impl Add<AddressDiff> for Address {
type Output = Address;
fn add(self, AddressDiff(rhs): AddressDiff) -> Address {
let Address(lhs) = self;
Address(((i32::from(lhs)) + rhs) as u16)
}
}
impl Add for AddressDiff {
type Output = AddressDiff;
fn add(self, AddressDiff(rhs): AddressDiff) -> AddressDiff {
let AddressDiff(lhs) = self;
AddressDiff(lhs + rhs)
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct CheckedAddressDiff(u16);
impl Add<CheckedAddressDiff> for Address {
type Output = Address;
fn add(self, CheckedAddressDiff(rhs): CheckedAddressDiff) -> Address {
let Address(lhs) = self;
// We probably don't want to overflow when doing arithmetic in our own
// code.
debug_assert!(lhs.checked_add(rhs).is_some());
Address(lhs + rhs)
}
}
impl Address {
pub fn to_u16(self) -> u16 {
self.0
}
pub fn to_usize(self) -> usize {
self.to_u16() as usize
}
pub fn get_page_number(self) -> u8 {
(self.to_u16() & 0xff00 >> 8) as u8
}
pub fn get_offset(self) -> u8 {
(self.to_u16() & 0x00ff) as u8
}
}

View File

@ -25,7 +25,6 @@
// 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 crate::address::{Address, AddressDiff};
use crate::instruction::{self, DecodedInstr, Instruction, OpInput}; use crate::instruction::{self, DecodedInstr, Instruction, OpInput};
use crate::memory::Memory; use crate::memory::Memory;
use crate::registers::{Registers, StackPointer, Status, StatusArgs}; use crate::registers::{Registers, StackPointer, Status, StatusArgs};
@ -60,15 +59,16 @@ impl CPU {
match instruction::OPCODES[x as usize] { match instruction::OPCODES[x as usize] {
Some((instr, am)) => { Some((instr, am)) => {
let extra_bytes = am.extra_bytes(); let extra_bytes = am.extra_bytes();
let num_bytes = AddressDiff(1) + extra_bytes; let num_bytes = extra_bytes + 1;
let data_start = self.registers.program_counter + AddressDiff(1); let data_start = self.registers.program_counter.wrapping_add(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 + num_bytes; self.registers.program_counter =
self.registers.program_counter.wrapping_add(num_bytes);
Some((instr, am_out)) Some((instr, am_out))
} }
@ -110,17 +110,17 @@ impl CPU {
} }
(Instruction::BCC, OpInput::UseRelative(rel)) => { (Instruction::BCC, OpInput::UseRelative(rel)) => {
let addr = self.registers.program_counter + AddressDiff(i32::from(rel)); let addr = self.registers.program_counter.wrapping_add(rel);
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 + AddressDiff(i32::from(rel)); let addr = self.registers.program_counter.wrapping_add(rel);
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 + AddressDiff(i32::from(rel)); let addr = self.registers.program_counter.wrapping_add(rel);
self.branch_if_equal(addr); self.branch_if_equal(addr);
} }
@ -150,23 +150,23 @@ impl CPU {
} }
(Instruction::BMI, OpInput::UseRelative(rel)) => { (Instruction::BMI, OpInput::UseRelative(rel)) => {
let addr = self.registers.program_counter + AddressDiff(i32::from(rel)); let addr = self.registers.program_counter.wrapping_add(rel);
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 + AddressDiff(i32::from(rel)); let addr = self.registers.program_counter.wrapping_add(rel);
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 + AddressDiff(i32::from(rel)); let addr = self.registers.program_counter.wrapping_add(rel);
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 + AddressDiff(i32::from(rel)); let addr = self.registers.program_counter.wrapping_add(rel);
self.branch_if_overflow_set(addr); self.branch_if_overflow_set(addr);
} }
@ -706,47 +706,47 @@ impl CPU {
); );
} }
fn jump(&mut self, addr: Address) { fn jump(&mut self, addr: u16) {
self.registers.program_counter = addr; self.registers.program_counter = addr;
} }
fn branch_if_carry_clear(&mut self, addr: Address) { fn branch_if_carry_clear(&mut self, addr: u16) {
if !self.registers.status.contains(Status::PS_CARRY) { if !self.registers.status.contains(Status::PS_CARRY) {
self.registers.program_counter = addr; self.registers.program_counter = addr;
} }
} }
fn branch_if_carry_set(&mut self, addr: Address) { fn branch_if_carry_set(&mut self, addr: u16) {
if self.registers.status.contains(Status::PS_CARRY) { if self.registers.status.contains(Status::PS_CARRY) {
self.registers.program_counter = addr; self.registers.program_counter = addr;
} }
} }
fn branch_if_equal(&mut self, addr: Address) { fn branch_if_equal(&mut self, addr: u16) {
if self.registers.status.contains(Status::PS_ZERO) { if self.registers.status.contains(Status::PS_ZERO) {
self.registers.program_counter = addr; self.registers.program_counter = addr;
} }
} }
fn branch_if_minus(&mut self, addr: Address) { fn branch_if_minus(&mut self, addr: u16) {
if self.registers.status.contains(Status::PS_NEGATIVE) { if self.registers.status.contains(Status::PS_NEGATIVE) {
self.registers.program_counter = addr; self.registers.program_counter = addr;
} }
} }
fn branch_if_positive(&mut self, addr: Address) { fn branch_if_positive(&mut self, addr: u16) {
if !self.registers.status.contains(Status::PS_NEGATIVE) { if !self.registers.status.contains(Status::PS_NEGATIVE) {
self.registers.program_counter = addr; self.registers.program_counter = addr;
} }
} }
fn branch_if_overflow_clear(&mut self, addr: Address) { fn branch_if_overflow_clear(&mut self, addr: u16) {
if !self.registers.status.contains(Status::PS_OVERFLOW) { if !self.registers.status.contains(Status::PS_OVERFLOW) {
self.registers.program_counter = addr; self.registers.program_counter = addr;
} }
} }
fn branch_if_overflow_set(&mut self, addr: Address) { fn branch_if_overflow_set(&mut self, addr: u16) {
if self.registers.status.contains(Status::PS_OVERFLOW) { if self.registers.status.contains(Status::PS_OVERFLOW) {
self.registers.program_counter = addr; self.registers.program_counter = addr;
} }
@ -808,13 +808,13 @@ impl CPU {
} }
fn push_on_stack(&mut self, val: u8) { fn push_on_stack(&mut self, val: u8) {
let addr = self.registers.stack_pointer.to_address(); let addr = self.registers.stack_pointer.to_u16();
self.memory.set_byte(addr, val); self.memory.set_byte(addr, val);
self.registers.stack_pointer.decrement(); self.registers.stack_pointer.decrement();
} }
fn pull_from_stack(&mut self) -> u8 { fn pull_from_stack(&mut self) -> u8 {
let addr = self.registers.stack_pointer.to_address(); let addr = self.registers.stack_pointer.to_u16();
let out = self.memory.get_byte(addr); let out = self.memory.get_byte(addr);
self.registers.stack_pointer.increment(); self.registers.stack_pointer.increment();
out out
@ -1057,7 +1057,7 @@ mod tests {
#[test] #[test]
fn decrement_memory_test() { fn decrement_memory_test() {
let mut cpu = CPU::new(); let mut cpu = CPU::new();
let addr = Address(0xA1B2); let addr: u16 = 0xA1B2;
cpu.memory.set_byte(addr, 5); cpu.memory.set_byte(addr, 5);
@ -1197,7 +1197,7 @@ mod tests {
#[test] #[test]
fn jump_test() { fn jump_test() {
let mut cpu = CPU::new(); let mut cpu = CPU::new();
let addr = Address(0xA1B1); let addr: u16 = 0xA1B1;
cpu.jump(addr); cpu.jump(addr);
assert_eq!(cpu.registers.program_counter, addr); assert_eq!(cpu.registers.program_counter, addr);
@ -1208,12 +1208,12 @@ mod tests {
let mut cpu = CPU::new(); let mut cpu = CPU::new();
cpu.execute_instruction((Instruction::SEC, OpInput::UseImplied)); cpu.execute_instruction((Instruction::SEC, OpInput::UseImplied));
cpu.branch_if_carry_clear(Address(0xABCD)); cpu.branch_if_carry_clear(0xABCD);
assert_eq!(cpu.registers.program_counter, Address(0)); assert_eq!(cpu.registers.program_counter, (0));
cpu.execute_instruction((Instruction::CLC, OpInput::UseImplied)); cpu.execute_instruction((Instruction::CLC, OpInput::UseImplied));
cpu.branch_if_carry_clear(Address(0xABCD)); cpu.branch_if_carry_clear(0xABCD);
assert_eq!(cpu.registers.program_counter, Address(0xABCD)); assert_eq!(cpu.registers.program_counter, (0xABCD));
} }
#[test] #[test]
@ -1221,24 +1221,24 @@ mod tests {
let mut cpu = CPU::new(); let mut cpu = CPU::new();
cpu.execute_instruction((Instruction::CLC, OpInput::UseImplied)); cpu.execute_instruction((Instruction::CLC, OpInput::UseImplied));
cpu.branch_if_carry_set(Address(0xABCD)); cpu.branch_if_carry_set(0xABCD);
assert_eq!(cpu.registers.program_counter, Address(0)); assert_eq!(cpu.registers.program_counter, (0));
cpu.execute_instruction((Instruction::SEC, OpInput::UseImplied)); cpu.execute_instruction((Instruction::SEC, OpInput::UseImplied));
cpu.branch_if_carry_set(Address(0xABCD)); cpu.branch_if_carry_set(0xABCD);
assert_eq!(cpu.registers.program_counter, Address(0xABCD)); assert_eq!(cpu.registers.program_counter, (0xABCD));
} }
#[test] #[test]
fn branch_if_equal_test() { fn branch_if_equal_test() {
let mut cpu = CPU::new(); let mut cpu = CPU::new();
cpu.branch_if_equal(Address(0xABCD)); cpu.branch_if_equal(0xABCD);
assert_eq!(cpu.registers.program_counter, Address(0)); assert_eq!(cpu.registers.program_counter, (0));
cpu.registers.status.or(Status::PS_ZERO); cpu.registers.status.or(Status::PS_ZERO);
cpu.branch_if_equal(Address(0xABCD)); cpu.branch_if_equal(0xABCD);
assert_eq!(cpu.registers.program_counter, Address(0xABCD)); assert_eq!(cpu.registers.program_counter, (0xABCD));
} }
#[test] #[test]
@ -1247,9 +1247,9 @@ mod tests {
let mut cpu = CPU::new(); let mut cpu = CPU::new();
let registers_before = cpu.registers; let registers_before = cpu.registers;
cpu.branch_if_minus(Address(0xABCD)); cpu.branch_if_minus(0xABCD);
assert_eq!(cpu.registers, registers_before); assert_eq!(cpu.registers, registers_before);
assert_eq!(cpu.registers.program_counter, Address(0)); assert_eq!(cpu.registers.program_counter, (0));
} }
{ {
@ -1258,9 +1258,9 @@ mod tests {
cpu.registers.status.or(Status::PS_NEGATIVE); cpu.registers.status.or(Status::PS_NEGATIVE);
let registers_before = cpu.registers; let registers_before = cpu.registers;
cpu.branch_if_minus(Address(0xABCD)); cpu.branch_if_minus(0xABCD);
assert_eq!(cpu.registers.status, registers_before.status); assert_eq!(cpu.registers.status, registers_before.status);
assert_eq!(cpu.registers.program_counter, Address(0xABCD)); assert_eq!(cpu.registers.program_counter, (0xABCD));
} }
} }
@ -1269,12 +1269,12 @@ mod tests {
let mut cpu = CPU::new(); let mut cpu = CPU::new();
cpu.registers.status.insert(Status::PS_NEGATIVE); cpu.registers.status.insert(Status::PS_NEGATIVE);
cpu.branch_if_positive(Address(0xABCD)); cpu.branch_if_positive(0xABCD);
assert_eq!(cpu.registers.program_counter, Address(0)); assert_eq!(cpu.registers.program_counter, (0));
cpu.registers.status.remove(Status::PS_NEGATIVE); cpu.registers.status.remove(Status::PS_NEGATIVE);
cpu.branch_if_positive(Address(0xABCD)); cpu.branch_if_positive(0xABCD);
assert_eq!(cpu.registers.program_counter, Address(0xABCD)); assert_eq!(cpu.registers.program_counter, (0xABCD));
} }
#[test] #[test]
@ -1282,24 +1282,34 @@ mod tests {
let mut cpu = CPU::new(); let mut cpu = CPU::new();
cpu.registers.status.insert(Status::PS_OVERFLOW); cpu.registers.status.insert(Status::PS_OVERFLOW);
cpu.branch_if_overflow_clear(Address(0xABCD)); cpu.branch_if_overflow_clear(0xABCD);
assert_eq!(cpu.registers.program_counter, Address(0)); assert_eq!(cpu.registers.program_counter, (0));
cpu.registers.status.remove(Status::PS_OVERFLOW); cpu.registers.status.remove(Status::PS_OVERFLOW);
cpu.branch_if_overflow_clear(Address(0xABCD)); cpu.branch_if_overflow_clear(0xABCD);
assert_eq!(cpu.registers.program_counter, Address(0xABCD)); assert_eq!(cpu.registers.program_counter, (0xABCD));
}
#[test]
fn branch_across_end_of_address_space() {
let mut cpu = CPU::new();
cpu.registers.program_counter = 0xffff;
cpu.registers.status.insert(Status::PS_OVERFLOW);
cpu.branch_if_overflow_set(0xABCD);
assert_eq!(cpu.registers.program_counter, (0xABCD));
} }
#[test] #[test]
fn branch_if_overflow_set_test() { fn branch_if_overflow_set_test() {
let mut cpu = CPU::new(); let mut cpu = CPU::new();
cpu.branch_if_overflow_set(Address(0xABCD)); cpu.branch_if_overflow_set(0xABCD);
assert_eq!(cpu.registers.program_counter, Address(0)); assert_eq!(cpu.registers.program_counter, (0));
cpu.registers.status.insert(Status::PS_OVERFLOW); cpu.registers.status.insert(Status::PS_OVERFLOW);
cpu.branch_if_overflow_set(Address(0xABCD)); cpu.branch_if_overflow_set(0xABCD);
assert_eq!(cpu.registers.program_counter, Address(0xABCD)); assert_eq!(cpu.registers.program_counter, (0xABCD));
} }
#[cfg(test)] #[cfg(test)]

View File

@ -25,8 +25,6 @@
// 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 crate::address::Address;
use crate::address::AddressDiff;
use crate::cpu::CPU; use crate::cpu::CPU;
// Abbreviations // Abbreviations
@ -113,8 +111,8 @@ pub enum Instruction {
pub enum OpInput { pub enum OpInput {
UseImplied, UseImplied,
UseImmediate(u8), UseImmediate(u8),
UseRelative(i8), UseRelative(u16),
UseAddress(Address), UseAddress(u16),
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -136,16 +134,19 @@ pub enum AddressingMode {
// zero page address) plus Y register // zero page address) plus Y register
} }
fn arr_to_addr(arr: &[u8]) -> Address { fn xextend(x: u8) -> u16 {
u16::from(x)
}
fn arr_to_addr(arr: &[u8]) -> u16 {
debug_assert!(arr.len() == 2); debug_assert!(arr.len() == 2);
let x = u16::from(arr[0]) + (u16::from(arr[1]) << 8usize); u16::from(arr[0]) + (u16::from(arr[1]) << 8usize)
Address(x)
} }
impl AddressingMode { impl AddressingMode {
pub fn extra_bytes(self) -> AddressDiff { pub fn extra_bytes(self) -> u16 {
let x = match self { match self {
AddressingMode::Accumulator => 0, AddressingMode::Accumulator => 0,
AddressingMode::Implied => 0, AddressingMode::Implied => 0,
AddressingMode::Immediate => 1, AddressingMode::Immediate => 1,
@ -159,15 +160,11 @@ impl AddressingMode {
AddressingMode::Indirect => 2, AddressingMode::Indirect => 2,
AddressingMode::IndexedIndirectX => 1, AddressingMode::IndexedIndirectX => 1,
AddressingMode::IndirectIndexedY => 1, AddressingMode::IndirectIndexedY => 1,
}; }
AddressDiff(x)
} }
pub fn process(self, cpu: &CPU, arr: &[u8]) -> OpInput { pub fn process(self, cpu: &CPU, arr: &[u8]) -> OpInput {
debug_assert!({ debug_assert!(arr.len() == self.extra_bytes() as usize);
let AddressDiff(x) = self.extra_bytes();
arr.len() == x as usize
});
let x = cpu.registers.index_x as u8; let x = cpu.registers.index_x as u8;
let y = cpu.registers.index_y as u8; let y = cpu.registers.index_y as u8;
@ -187,24 +184,29 @@ impl AddressingMode {
// Use [u8, ..1] from instruction // Use [u8, ..1] from instruction
// Interpret as zero page address // Interpret as zero page address
// (Output: an 8-bit zero-page address) // (Output: an 8-bit zero-page address)
OpInput::UseAddress(Address(u16::from(arr[0]))) OpInput::UseAddress(u16::from(arr[0]))
} }
AddressingMode::ZeroPageX => { AddressingMode::ZeroPageX => {
// Use [u8, ..1] from instruction // Use [u8, ..1] from instruction
// Add to X register (as u8 -- the final address is in 0-page) // Add to X register (as u8 -- the final address is in 0-page)
// (Output: an 8-bit zero-page address) // (Output: an 8-bit zero-page address)
OpInput::UseAddress(Address(u16::from(arr[0] + x))) OpInput::UseAddress(u16::from(arr[0].wrapping_add(x)))
} }
AddressingMode::ZeroPageY => { AddressingMode::ZeroPageY => {
// Use [u8, ..1] from instruction // Use [u8, ..1] from instruction
// Add to Y register (as u8 -- the final address is in 0-page) // Add to Y register (as u8 -- the final address is in 0-page)
// (Output: an 8-bit zero-page address) // (Output: an 8-bit zero-page address)
OpInput::UseAddress(Address(u16::from(arr[0] + y))) OpInput::UseAddress(u16::from(arr[0].wrapping_add(y)))
} }
AddressingMode::Relative => { AddressingMode::Relative => {
// Use [u8, ..1] from instruction // Use [u8, ..1] from instruction
// (interpret as relative...) // (interpret as relative...)
OpInput::UseRelative(arr[0] as i8) // (This is sign extended to a 16-but data type, but an unsigned one: u16. It's a
// little weird, but it's so we can add the PC and the offset easily)
let offset = arr[0];
let sign_extend = if offset & 0x80 == 0x80 { 0xffu8 } else { 0x0 };
let rel = u16::from_le_bytes([offset, sign_extend]);
OpInput::UseRelative(rel)
} }
AddressingMode::Absolute => { AddressingMode::Absolute => {
// Use [u8, ..2] from instruction as address // Use [u8, ..2] from instruction as address
@ -214,18 +216,18 @@ impl AddressingMode {
AddressingMode::AbsoluteX => { AddressingMode::AbsoluteX => {
// Use [u8, ..2] from instruction as address, add X // Use [u8, ..2] from instruction as address, add X
// (Output: a 16-bit address) // (Output: a 16-bit address)
OpInput::UseAddress(arr_to_addr(arr) + AddressDiff(i32::from(x))) OpInput::UseAddress(arr_to_addr(arr).wrapping_add(xextend(x)))
} }
AddressingMode::AbsoluteY => { AddressingMode::AbsoluteY => {
// Use [u8, ..2] from instruction as address, add Y // Use [u8, ..2] from instruction as address, add Y
// (Output: a 16-bit address) // (Output: a 16-bit address)
OpInput::UseAddress(arr_to_addr(arr) + AddressDiff(i32::from(y))) OpInput::UseAddress(arr_to_addr(arr).wrapping_add(xextend(y)))
} }
AddressingMode::Indirect => { AddressingMode::Indirect => {
// Use [u8, ..2] from instruction as an address. Interpret the // Use [u8, ..2] from instruction as an address. Interpret the
// two bytes starting at that address as an address. // two bytes starting at that address as an address.
// (Output: a 16-bit address) // (Output: a 16-bit address)
let slice = memory.get_slice(arr_to_addr(arr), AddressDiff(2)); let slice = memory.get_slice(arr_to_addr(arr), 2);
OpInput::UseAddress(arr_to_addr(slice)) OpInput::UseAddress(arr_to_addr(slice))
} }
AddressingMode::IndexedIndirectX => { AddressingMode::IndexedIndirectX => {
@ -233,8 +235,8 @@ impl AddressingMode {
// Add to X register with 0-page wraparound, like ZeroPageX. // Add to X register with 0-page wraparound, like ZeroPageX.
// This is where the absolute (16-bit) target address is stored. // This is where the absolute (16-bit) target address is stored.
// (Output: a 16-bit address) // (Output: a 16-bit address)
let start = arr[0] + x; let start = arr[0].wrapping_add(x);
let slice = memory.get_slice(Address(u16::from(start)), AddressDiff(2)); let slice = memory.get_slice(u16::from(start), 2);
OpInput::UseAddress(arr_to_addr(slice)) OpInput::UseAddress(arr_to_addr(slice))
} }
AddressingMode::IndirectIndexedY => { AddressingMode::IndirectIndexedY => {
@ -243,8 +245,8 @@ impl AddressingMode {
// Add Y register to this address to get the final address // Add Y register to this address to get the final address
// (Output: a 16-bit address) // (Output: a 16-bit address)
let start = arr[0]; let start = arr[0];
let slice = memory.get_slice(Address(u16::from(start)), AddressDiff(2)); let slice = memory.get_slice(u16::from(start), 2);
OpInput::UseAddress(arr_to_addr(slice) + AddressDiff(i32::from(y))) OpInput::UseAddress(arr_to_addr(slice).wrapping_add(xextend(y)))
} }
} }
} }
@ -766,3 +768,26 @@ pub static OPCODES: [Option<(Instruction, AddressingMode)>; 256] = [
/*0xFF*/ /*0xFF*/
None, None,
]; ];
#[cfg(test)]
mod tests {
#[test]
fn zeropage_wrap_around() {
use crate::instruction::AddressingMode;
use crate::instruction::OpInput;
use crate::instruction::CPU;
let mut cpu = CPU::new();
cpu.registers.index_x = 9;
assert!(matches!(
AddressingMode::ZeroPageX.process(&cpu, &[10]),
OpInput::UseAddress(19)
));
assert!(matches!(
AddressingMode::ZeroPageX.process(&cpu, &[250]),
OpInput::UseAddress(3)
));
}
}

View File

@ -35,7 +35,6 @@ extern crate num;
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
pub mod address;
pub mod cpu; pub mod cpu;
pub mod instruction; pub mod instruction;
pub mod memory; pub mod memory;

View File

@ -25,8 +25,6 @@
// 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 crate::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.
// Address range type? // Address range type?
// //
@ -39,12 +37,12 @@ use crate::address::{Address, AddressDiff};
const ADDR_LO_BARE: u16 = 0x0000; const ADDR_LO_BARE: u16 = 0x0000;
const ADDR_HI_BARE: u16 = 0xFFFF; const ADDR_HI_BARE: u16 = 0xFFFF;
pub const MEMORY_ADDRESS_LO: Address = Address(ADDR_LO_BARE); pub const MEMORY_ADDRESS_LO: u16 = ADDR_LO_BARE;
pub const MEMORY_ADDRESS_HI: Address = Address(ADDR_HI_BARE); pub const MEMORY_ADDRESS_HI: u16 = ADDR_HI_BARE;
pub const STACK_ADDRESS_LO: Address = Address(0x0100); pub const STACK_ADDRESS_LO: u16 = 0x0100;
pub const STACK_ADDRESS_HI: Address = Address(0x01FF); pub const STACK_ADDRESS_HI: u16 = 0x01FF;
pub const IRQ_INTERRUPT_VECTOR_LO: Address = Address(0xFFFE); pub const IRQ_INTERRUPT_VECTOR_LO: u16 = 0xFFFE;
pub const IRQ_INTERRUPT_VECTOR_HI: Address = Address(0xFFFF); pub const IRQ_INTERRUPT_VECTOR_HI: u16 = 0xFFFF;
const MEMORY_SIZE: usize = (ADDR_HI_BARE - ADDR_LO_BARE) as usize + 1usize; const MEMORY_SIZE: usize = (ADDR_HI_BARE - ADDR_LO_BARE) as usize + 1usize;
@ -67,28 +65,31 @@ impl Memory {
} }
} }
pub fn get_byte(&self, address: Address) -> u8 { pub fn get_byte(&self, address: u16) -> u8 {
self.bytes[address.to_usize()] self.bytes[address as usize]
} }
pub fn get_byte_mut_ref(&mut self, address: Address) -> &mut u8 { pub fn get_byte_mut_ref(&mut self, address: u16) -> &mut u8 {
&mut self.bytes[address.to_usize()] &mut self.bytes[address as usize]
} }
pub fn get_slice(&self, start: Address, diff: AddressDiff) -> &[u8] { pub fn get_slice(&self, start: u16, diff: u16) -> &[u8] {
&self.bytes[start.to_usize()..(start + diff).to_usize()] let orig: usize = start.into();
let end = orig + diff as usize;
&self.bytes[orig..end]
} }
// Sets the byte at the given address to the given value and returns the // Sets the byte at the given address to the given value and returns the
// previous value at the address. // previous value at the address.
pub fn set_byte(&mut self, address: Address, value: u8) -> u8 { pub fn set_byte(&mut self, address: u16, value: u8) -> u8 {
let old_value = self.get_byte(address); let old_value = self.get_byte(address);
self.bytes[address.to_usize()] = value; self.bytes[address as usize] = value;
old_value old_value
} }
pub fn set_bytes(&mut self, start: Address, values: &[u8]) { pub fn set_bytes(&mut self, start: u16, values: &[u8]) {
let start = start.to_usize(); let start = start as usize;
// This panics if the range is invalid // This panics if the range is invalid
let end = start + values.len(); let end = start + values.len();
@ -96,8 +97,8 @@ impl Memory {
self.bytes[start..end].copy_from_slice(values); self.bytes[start..end].copy_from_slice(values);
} }
pub fn is_stack_address(address: Address) -> bool { pub fn is_stack_address(address: u16) -> bool {
(STACK_ADDRESS_LO..=STACK_ADDRESS_HI).contains(&address) address > 0xff && address < 0x200
} }
} }
@ -108,17 +109,14 @@ mod tests {
#[test] #[test]
fn test_memory_set_bytes() { fn test_memory_set_bytes() {
let mut memory = Memory::new(); let mut memory = Memory::new();
memory.set_bytes(Address(0x0100), &[1, 2, 3, 4, 5]); memory.set_bytes(0x0100, &[1, 2, 3, 4, 5]);
assert_eq!( assert_eq!(memory.get_slice(0x00FF, 7), &[0, 1, 2, 3, 4, 5, 0]);
memory.get_slice(Address(0x00FF), AddressDiff(7)),
&[0, 1, 2, 3, 4, 5, 0]
);
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn test_memory_overflow_panic() { fn test_memory_overflow_panic() {
let mut memory = Memory::new(); let mut memory = Memory::new();
memory.set_bytes(Address(0xFFFE), &[1, 2, 3]); memory.set_bytes(0xFFFE, &[1, 2, 3]);
} }
} }

View File

@ -25,9 +25,6 @@
// 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 crate::address::{Address, AddressDiff};
use crate::memory::{STACK_ADDRESS_HI, STACK_ADDRESS_LO};
// Useful for constructing Status instances // Useful for constructing Status instances
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct StatusArgs { pub struct StatusArgs {
@ -147,8 +144,9 @@ impl Status {
pub struct StackPointer(pub u8); pub struct StackPointer(pub u8);
impl StackPointer { impl StackPointer {
pub fn to_address(self) -> Address { pub fn to_u16(self) -> u16 {
STACK_ADDRESS_LO + AddressDiff(i32::from(self.0)) let StackPointer(val) = self;
u16::from_le_bytes([val, 0x01])
} }
pub fn decrement(&mut self) { pub fn decrement(&mut self) {
@ -166,7 +164,7 @@ pub struct Registers {
pub index_x: u8, pub index_x: u8,
pub index_y: u8, pub index_y: u8,
pub stack_pointer: StackPointer, pub stack_pointer: StackPointer,
pub program_counter: Address, pub program_counter: u16,
pub status: Status, pub status: Status,
} }
@ -183,8 +181,8 @@ impl Registers {
accumulator: 0, accumulator: 0,
index_x: 0, index_x: 0,
index_y: 0, index_y: 0,
stack_pointer: StackPointer(STACK_ADDRESS_HI.get_offset()), stack_pointer: StackPointer(0),
program_counter: Address(0), program_counter: 0,
status: Status::default(), status: Status::default(),
} }
} }