1
0
mirror of https://github.com/mre/mos6502.git synced 2024-11-28 07:49:19 +00:00

Merge pull request #53 from mre/addrfix

Proper wrap-around for address calculations
This commit is contained in:
omarandlorraine 2022-10-21 09:09:21 +01:00 committed by GitHub
commit 8850934023
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 154 additions and 219 deletions

View File

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

View File

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

View File

@ -30,9 +30,6 @@ extern crate mos6502;
#[cfg(not(test))]
use mos6502::cpu;
#[cfg(not(test))]
use mos6502::address::Address;
#[cfg(not(test))]
fn main() {
let mut cpu = cpu::CPU::new();
@ -94,11 +91,11 @@ fn main() {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, // ADC IndirectIndexedY target
];
cpu.memory.set_bytes(Address(0x0000), &zero_page_data);
cpu.memory.set_bytes(Address(0x4000), &program);
cpu.memory.set_bytes(Address(0x8000), &data);
cpu.memory.set_bytes(0x0000, &zero_page_data);
cpu.memory.set_bytes(0x4000, &program);
cpu.memory.set_bytes(0x8000, &data);
cpu.registers.program_counter = Address(0x4000);
cpu.registers.program_counter = 0x4000;
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
// POSSIBILITY OF SUCH DAMAGE.
use crate::address::{Address, AddressDiff};
use crate::instruction::{self, DecodedInstr, Instruction, OpInput};
use crate::memory::Memory;
use crate::registers::{Registers, StackPointer, Status, StatusArgs};
@ -60,15 +59,16 @@ impl CPU {
match instruction::OPCODES[x as usize] {
Some((instr, am)) => {
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 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.wrapping_add(num_bytes);
Some((instr, am_out))
}
@ -110,17 +110,17 @@ impl CPU {
}
(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);
}
(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);
}
(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);
}
@ -150,23 +150,23 @@ impl CPU {
}
(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);
self.branch_if_minus(addr);
}
(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);
}
(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);
}
(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);
}
@ -648,7 +648,7 @@ impl CPU {
self.load_accumulator(result);
}
fn decrement_memory(&mut self, addr: Address) {
fn decrement_memory(&mut self, addr: u16) {
let value_new = self.memory.get_byte(addr).wrapping_sub(1);
self.memory.set_byte(addr, value_new);
@ -671,47 +671,47 @@ impl CPU {
self.load_x_register(val - 1);
}
fn jump(&mut self, addr: Address) {
fn jump(&mut self, addr: u16) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
self.registers.program_counter = addr;
}
@ -773,13 +773,13 @@ impl CPU {
}
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.registers.stack_pointer.decrement();
}
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);
self.registers.stack_pointer.increment();
out
@ -1022,7 +1022,7 @@ mod tests {
#[test]
fn decrement_memory_test() {
let mut cpu = CPU::new();
let addr = Address(0xA1B2);
let addr: u16 = 0xA1B2;
cpu.memory.set_byte(addr, 5);
@ -1135,7 +1135,7 @@ mod tests {
#[test]
fn jump_test() {
let mut cpu = CPU::new();
let addr = Address(0xA1B1);
let addr: u16 = 0xA1B1;
cpu.jump(addr);
assert_eq!(cpu.registers.program_counter, addr);
@ -1146,12 +1146,12 @@ mod tests {
let mut cpu = CPU::new();
cpu.execute_instruction((Instruction::SEC, OpInput::UseImplied));
cpu.branch_if_carry_clear(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0));
cpu.branch_if_carry_clear(0xABCD);
assert_eq!(cpu.registers.program_counter, (0));
cpu.execute_instruction((Instruction::CLC, OpInput::UseImplied));
cpu.branch_if_carry_clear(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
cpu.branch_if_carry_clear(0xABCD);
assert_eq!(cpu.registers.program_counter, (0xABCD));
}
#[test]
@ -1159,24 +1159,24 @@ mod tests {
let mut cpu = CPU::new();
cpu.execute_instruction((Instruction::CLC, OpInput::UseImplied));
cpu.branch_if_carry_set(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0));
cpu.branch_if_carry_set(0xABCD);
assert_eq!(cpu.registers.program_counter, (0));
cpu.execute_instruction((Instruction::SEC, OpInput::UseImplied));
cpu.branch_if_carry_set(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
cpu.branch_if_carry_set(0xABCD);
assert_eq!(cpu.registers.program_counter, (0xABCD));
}
#[test]
fn branch_if_equal_test() {
let mut cpu = CPU::new();
cpu.branch_if_equal(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0));
cpu.branch_if_equal(0xABCD);
assert_eq!(cpu.registers.program_counter, (0));
cpu.registers.status.or(Status::PS_ZERO);
cpu.branch_if_equal(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
cpu.branch_if_equal(0xABCD);
assert_eq!(cpu.registers.program_counter, (0xABCD));
}
#[test]
@ -1185,9 +1185,9 @@ mod tests {
let mut cpu = CPU::new();
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.program_counter, Address(0));
assert_eq!(cpu.registers.program_counter, (0));
}
{
@ -1196,9 +1196,9 @@ mod tests {
cpu.registers.status.or(Status::PS_NEGATIVE);
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.program_counter, Address(0xABCD));
assert_eq!(cpu.registers.program_counter, (0xABCD));
}
}
@ -1207,12 +1207,12 @@ mod tests {
let mut cpu = CPU::new();
cpu.registers.status.insert(Status::PS_NEGATIVE);
cpu.branch_if_positive(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0));
cpu.branch_if_positive(0xABCD);
assert_eq!(cpu.registers.program_counter, (0));
cpu.registers.status.remove(Status::PS_NEGATIVE);
cpu.branch_if_positive(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
cpu.branch_if_positive(0xABCD);
assert_eq!(cpu.registers.program_counter, (0xABCD));
}
#[test]
@ -1220,24 +1220,34 @@ mod tests {
let mut cpu = CPU::new();
cpu.registers.status.insert(Status::PS_OVERFLOW);
cpu.branch_if_overflow_clear(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0));
cpu.branch_if_overflow_clear(0xABCD);
assert_eq!(cpu.registers.program_counter, (0));
cpu.registers.status.remove(Status::PS_OVERFLOW);
cpu.branch_if_overflow_clear(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
cpu.branch_if_overflow_clear(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]
fn branch_if_overflow_set_test() {
let mut cpu = CPU::new();
cpu.branch_if_overflow_set(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0));
cpu.branch_if_overflow_set(0xABCD);
assert_eq!(cpu.registers.program_counter, (0));
cpu.registers.status.insert(Status::PS_OVERFLOW);
cpu.branch_if_overflow_set(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
cpu.branch_if_overflow_set(0xABCD);
assert_eq!(cpu.registers.program_counter, (0xABCD));
}
#[cfg(test)]

View File

@ -25,8 +25,6 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
use crate::address::Address;
use crate::address::AddressDiff;
use crate::cpu::CPU;
// Abbreviations
@ -113,8 +111,8 @@ pub enum Instruction {
pub enum OpInput {
UseImplied,
UseImmediate(u8),
UseRelative(i8),
UseAddress(Address),
UseRelative(u16),
UseAddress(u16),
}
#[derive(Copy, Clone)]
@ -136,16 +134,19 @@ pub enum AddressingMode {
// 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);
let x = u16::from(arr[0]) + (u16::from(arr[1]) << 8usize);
Address(x)
u16::from(arr[0]) + (u16::from(arr[1]) << 8usize)
}
impl AddressingMode {
pub fn extra_bytes(self) -> AddressDiff {
let x = match self {
pub fn extra_bytes(self) -> u16 {
match self {
AddressingMode::Accumulator => 0,
AddressingMode::Implied => 0,
AddressingMode::Immediate => 1,
@ -159,15 +160,11 @@ impl AddressingMode {
AddressingMode::Indirect => 2,
AddressingMode::IndexedIndirectX => 1,
AddressingMode::IndirectIndexedY => 1,
};
AddressDiff(x)
}
}
pub fn process(self, cpu: &CPU, arr: &[u8]) -> OpInput {
debug_assert!({
let AddressDiff(x) = self.extra_bytes();
arr.len() == x as usize
});
debug_assert!(arr.len() == self.extra_bytes() as usize);
let x = cpu.registers.index_x as u8;
let y = cpu.registers.index_y as u8;
@ -187,24 +184,29 @@ impl AddressingMode {
// Use [u8, ..1] from instruction
// Interpret as 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 => {
// Use [u8, ..1] from instruction
// Add to X register (as u8 -- the final address is in 0-page)
// (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 => {
// Use [u8, ..1] from instruction
// Add to Y register (as u8 -- the final address is in 0-page)
// (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 => {
// Use [u8, ..1] from instruction
// (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 => {
// Use [u8, ..2] from instruction as address
@ -214,18 +216,18 @@ impl AddressingMode {
AddressingMode::AbsoluteX => {
// Use [u8, ..2] from instruction as address, add X
// (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 => {
// Use [u8, ..2] from instruction as address, add Y
// (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 => {
// Use [u8, ..2] from instruction as an address. Interpret the
// two bytes starting at that address as an 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))
}
AddressingMode::IndexedIndirectX => {
@ -233,8 +235,8 @@ impl AddressingMode {
// Add to X register with 0-page wraparound, like ZeroPageX.
// This is where the absolute (16-bit) target address is stored.
// (Output: a 16-bit address)
let start = arr[0] + x;
let slice = memory.get_slice(Address(u16::from(start)), AddressDiff(2));
let start = arr[0].wrapping_add(x);
let slice = memory.get_slice(u16::from(start), 2);
OpInput::UseAddress(arr_to_addr(slice))
}
AddressingMode::IndirectIndexedY => {
@ -243,8 +245,8 @@ impl AddressingMode {
// Add Y register to this address to get the final address
// (Output: a 16-bit address)
let start = arr[0];
let slice = memory.get_slice(Address(u16::from(start)), AddressDiff(2));
OpInput::UseAddress(arr_to_addr(slice) + AddressDiff(i32::from(y)))
let slice = memory.get_slice(u16::from(start), 2);
OpInput::UseAddress(arr_to_addr(slice).wrapping_add(xextend(y)))
}
}
}
@ -766,3 +768,26 @@ pub static OPCODES: [Option<(Instruction, AddressingMode)>; 256] = [
/*0xFF*/
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]
extern crate bitflags;
pub mod address;
pub mod cpu;
pub mod instruction;
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
// POSSIBILITY OF SUCH DAMAGE.
use crate::address::{Address, AddressDiff};
// JAM: We can probably come up with a better way to represent address ranges.
// Address range type?
//
@ -39,12 +37,12 @@ use crate::address::{Address, AddressDiff};
const ADDR_LO_BARE: u16 = 0x0000;
const ADDR_HI_BARE: u16 = 0xFFFF;
pub const MEMORY_ADDRESS_LO: Address = Address(ADDR_LO_BARE);
pub const MEMORY_ADDRESS_HI: Address = Address(ADDR_HI_BARE);
pub const STACK_ADDRESS_LO: Address = Address(0x0100);
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);
pub const MEMORY_ADDRESS_LO: u16 = ADDR_LO_BARE;
pub const MEMORY_ADDRESS_HI: u16 = ADDR_HI_BARE;
pub const STACK_ADDRESS_LO: u16 = 0x0100;
pub const STACK_ADDRESS_HI: u16 = 0x01FF;
pub const IRQ_INTERRUPT_VECTOR_LO: u16 = 0xFFFE;
pub const IRQ_INTERRUPT_VECTOR_HI: u16 = 0xFFFF;
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 {
self.bytes[address.to_usize()]
pub fn get_byte(&self, address: u16) -> u8 {
self.bytes[address as usize]
}
pub fn get_byte_mut_ref(&mut self, address: Address) -> &mut u8 {
&mut self.bytes[address.to_usize()]
pub fn get_byte_mut_ref(&mut self, address: u16) -> &mut u8 {
&mut self.bytes[address as usize]
}
pub fn get_slice(&self, start: Address, diff: AddressDiff) -> &[u8] {
&self.bytes[start.to_usize()..(start + diff).to_usize()]
pub fn get_slice(&self, start: u16, diff: u16) -> &[u8] {
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
// 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);
self.bytes[address.to_usize()] = value;
self.bytes[address as usize] = value;
old_value
}
pub fn set_bytes(&mut self, start: Address, values: &[u8]) {
let start = start.to_usize();
pub fn set_bytes(&mut self, start: u16, values: &[u8]) {
let start = start as usize;
// This panics if the range is invalid
let end = start + values.len();
@ -96,8 +97,8 @@ impl Memory {
self.bytes[start..end].copy_from_slice(values);
}
pub fn is_stack_address(address: Address) -> bool {
(STACK_ADDRESS_LO..=STACK_ADDRESS_HI).contains(&address)
pub fn is_stack_address(address: u16) -> bool {
address > 0xff && address < 0x200
}
}
@ -108,17 +109,14 @@ mod tests {
#[test]
fn test_memory_set_bytes() {
let mut memory = Memory::new();
memory.set_bytes(Address(0x0100), &[1, 2, 3, 4, 5]);
assert_eq!(
memory.get_slice(Address(0x00FF), AddressDiff(7)),
&[0, 1, 2, 3, 4, 5, 0]
);
memory.set_bytes(0x0100, &[1, 2, 3, 4, 5]);
assert_eq!(memory.get_slice(0x00FF, 7), &[0, 1, 2, 3, 4, 5, 0]);
}
#[test]
#[should_panic]
fn test_memory_overflow_panic() {
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
// POSSIBILITY OF SUCH DAMAGE.
use crate::address::{Address, AddressDiff};
use crate::memory::{STACK_ADDRESS_HI, STACK_ADDRESS_LO};
// Useful for constructing Status instances
#[derive(Copy, Clone)]
pub struct StatusArgs {
@ -147,8 +144,9 @@ impl Status {
pub struct StackPointer(pub u8);
impl StackPointer {
pub fn to_address(self) -> Address {
STACK_ADDRESS_LO + AddressDiff(i32::from(self.0))
pub fn to_u16(self) -> u16 {
let StackPointer(val) = self;
u16::from_le_bytes([val, 0x01])
}
pub fn decrement(&mut self) {
@ -166,7 +164,7 @@ pub struct Registers {
pub index_x: i8,
pub index_y: i8,
pub stack_pointer: StackPointer,
pub program_counter: Address,
pub program_counter: u16,
pub status: Status,
}
@ -183,8 +181,8 @@ impl Registers {
accumulator: 0,
index_x: 0,
index_y: 0,
stack_pointer: StackPointer(STACK_ADDRESS_HI.get_offset()),
program_counter: Address(0),
stack_pointer: StackPointer(0),
program_counter: 0,
status: Status::default(),
}
}