Skip to content

Commit

Permalink
ARM: Add memory field into arm implementation of CPU
Browse files Browse the repository at this point in the history
This allows to fix `SingleDataTransfer::Ldr` istruction.

Signed-off-by: Federico Guerinoni <[email protected]>
  • Loading branch information
guerinoni authored and FedericoBruzzone committed Sep 29, 2022
1 parent 0881eea commit 1ad102c
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 10 deletions.
31 changes: 22 additions & 9 deletions src/arm7tdmi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::convert::TryInto;
use crate::alu_instruction::ArmModeAluInstruction;
use crate::bitwise::Bits;
use crate::instruction::ArmModeInstruction;
use crate::internal_memory::InternalMemory;
use crate::io_device::IoDevice;
use crate::{condition::Condition, cpsr::Cpsr, cpu::Cpu};

/// Contains the 16 registers for the CPU, latest (R15) is special because
Expand Down Expand Up @@ -39,6 +41,8 @@ pub struct Arm7tdmi {

registers: Registers,
cpsr: Cpsr,

memory: InternalMemory,
}

const OPCODE_ARM_SIZE: usize = 4;
Expand Down Expand Up @@ -113,6 +117,7 @@ impl Arm7tdmi {
rom,
registers: Registers::default(),
cpsr: Cpsr::default(),
memory: InternalMemory::new(),
}
}

Expand Down Expand Up @@ -225,15 +230,20 @@ impl Arm7tdmi {
let load_store: SingleDataTransfer =
opcode.try_into().expect("convert to Single Data Transfer");

let value: u32 = self
.memory
.read_at(if up_down {
address.wrapping_sub(offset)
} else {
address.wrapping_add(offset)
})
.try_into()
.unwrap(); // FIXME: is this right? Or we should read a WORD (u32)

match load_store {
SingleDataTransfer::Ldr => self.registers.set_register_at(
rd.try_into().unwrap(),
if up_down {
address.wrapping_sub(offset)
} else {
address.wrapping_add(offset)
},
),
SingleDataTransfer::Ldr => self
.registers
.set_register_at(rd.try_into().unwrap(), value),
_ => todo!(),
}
}
Expand Down Expand Up @@ -428,8 +438,11 @@ mod tests {
// then will be 92 + 8 (.wrapping_sub(offset))
cpu.registers.set_program_counter(92);

// simulate mem already contains something.
cpu.memory.write_at(76, 99);

cpu.execute(op_code, instruction);
assert_eq!(cpu.registers.register_at(13), 76);
assert_eq!(cpu.registers.register_at(13), 99);
assert_eq!(cpu.registers.program_counter(), 96);
}
}
25 changes: 25 additions & 0 deletions src/bitwise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub trait Bits {
fn get_bit(self, bit_idx: u8) -> bool;
fn get_bits(self, bits_range: RangeInclusive<u8>) -> u32;
fn are_bits_on(self, bits_range: RangeInclusive<u8>) -> bool;
fn clear_bits(&mut self, bit_idx: u8, to: u8);
}

impl Bits for u32 {
Expand Down Expand Up @@ -82,13 +83,37 @@ impl Bits for u32 {
}
true
}

/// To clear all bits from the `from` through `to` (inclusive)
fn clear_bits(&mut self, from: u8, to: u8) {
let from_mask = (1 << from) - 1;
let to_mask = (1 << to) - 1;
let mask = !(from_mask - to_mask);
*self &= mask;
}
}

#[cfg(test)]
mod tests {
use super::*;
use rand::Rng;

#[test]
fn test_clear_bits_msb_to_idx() {
let mut b = 0b11111111;
b.clear_bits(5, 2);
println!("{}", b);
assert_eq!(b, 0b11100011);
}

#[test]
fn test_clear_bits_idx_to_0() {
let mut b = 0b11111111;
b.clear_bits(3, 1);
println!("{}", b);
assert_eq!(b, 0b11111001);
}

#[test]
fn test_is_on() {
let b = 0b110011101_u32;
Expand Down
2 changes: 1 addition & 1 deletion src/internal_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub struct InternalMemory {
}

impl InternalMemory {
pub fn new() -> Self {
pub const fn new() -> Self {
Self {
internal_work_ram: [0; 0x7FFF],
}
Expand Down
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ mod cpsr;
mod cpu;
mod egui_app;
mod instruction;
mod internal_memory;
mod io_device;
mod ppu;

fn main() {
Expand Down

0 comments on commit 1ad102c

Please sign in to comment.