Created
November 11, 2018 00:22
-
-
Save yuriks/51380e2b75773425329e3f11b8838a25 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mod decode; | |
use self::decode::DecodeInstruction; | |
use self::decode::DecodedArmInstruction; | |
use scheduler::GeneratorTask; | |
use scheduler::Task; | |
use system::AccessWidth; | |
use system::Bus; | |
use system::MemoryRequest; | |
use system::OperationType; | |
// Named constants for common registers | |
const LR: usize = 14; | |
const PC: usize = 15; | |
struct ArmCpu { | |
regs: [u32; 16], | |
cpsr: u32, | |
} | |
impl ArmCpu { | |
fn new() -> ArmCpu { | |
ArmCpu { | |
regs: [0; 16], | |
cpsr: 0, | |
} | |
} | |
} | |
fn run_cpu<'a>(cpu: &'a mut ArmCpu, bus: &'a Bus) -> impl Task<'a, Return = ()> { | |
GeneratorTask::new(move || { | |
let mut sequential_fetch = false; | |
let mut refill_steps = 2; | |
let mut instr_decoding = 0xFFFFFFFF; | |
let mut instr_executing = 0xFFFFFFFF; | |
loop { | |
println!("F[${:X}], D[{:08X}], E[{:08X}]", cpu.regs[PC], instr_decoding, instr_executing); | |
bus.make_request(MemoryRequest { | |
address: cpu.regs[PC], | |
width: AccessWidth::Bit32, | |
op: OperationType::Read { | |
is_instruction: true, | |
}, | |
seq: sequential_fetch, | |
}); | |
println!("Fetching from PC={:X}", cpu.regs[PC]); | |
sequential_fetch = true; | |
if refill_steps > 0 { | |
println!("Skipping execute"); | |
refill_steps -= 1; | |
cpu.regs[PC] = cpu.regs[PC].wrapping_add(4); | |
} else { | |
println!("Executing {:08X}", instr_executing); | |
let decoded_instr = DecodedArmInstruction::decode_arm_instruction(instr_executing); | |
match decoded_instr { | |
DecodedArmInstruction::BranchImm { cond, link, offset } => { | |
sequential_fetch = false; | |
refill_steps = 2; | |
if link { | |
cpu.regs[LR] = cpu.regs[PC].wrapping_sub(4); | |
} | |
// TODO: Handle faulting on bad address | |
cpu.regs[PC] = cpu.regs[PC].wrapping_add((offset * 4) as u32); | |
println!("Branching to PC={:0X}", cpu.regs[PC]); | |
} | |
instr => unimplemented!("Unimplemented instruction execute: {:?}", instr), | |
} | |
if refill_steps == 0 { | |
cpu.regs[PC] = cpu.regs[PC].wrapping_add(4); | |
} | |
} | |
wait_cycles!(1); | |
while bus.should_cpu_wait() { | |
println!("waitstate"); | |
wait_cycles!(1); | |
} | |
instr_executing = instr_decoding; | |
instr_decoding = bus.data.get(); | |
} | |
}) | |
} | |
#[cfg(test)] | |
mod test { | |
use super::*; | |
use std::pin::Pin; | |
#[test] | |
fn test_branch() { | |
let bus = Default::default(); | |
let mut cpu = ArmCpu::new(); | |
let mut cpu_task = Box::pinned(run_cpu(&mut cpu, &bus)); | |
cpu_task.as_mut().step(); | |
assert_eq!( | |
bus.request.get(), | |
Some(MemoryRequest { | |
address: 0, | |
width: AccessWidth::Bit32, | |
op: OperationType::Read { | |
is_instruction: true | |
}, | |
seq: false, | |
}) | |
); | |
bus.data.set(0xEA000006); | |
cpu_task.as_mut().step(); | |
assert_eq!( | |
bus.request.get(), | |
Some(MemoryRequest { | |
address: 4, | |
width: AccessWidth::Bit32, | |
op: OperationType::Read { | |
is_instruction: true | |
}, | |
seq: true, | |
}) | |
); | |
bus.data.set(0xFFFFFFFF); | |
cpu_task.as_mut().step(); | |
assert_eq!( | |
bus.request.get(), | |
Some(MemoryRequest { | |
address: 8, | |
width: AccessWidth::Bit32, | |
op: OperationType::Read { | |
is_instruction: true | |
}, | |
seq: true, | |
}) | |
); | |
bus.data.set(0xFFFFFFFF); | |
cpu_task.as_mut().step(); | |
assert_eq!( | |
bus.request.get(), | |
Some(MemoryRequest { | |
address: 0x20, | |
width: AccessWidth::Bit32, | |
op: OperationType::Read { | |
is_instruction: true | |
}, | |
seq: false, | |
}) | |
); | |
bus.busy.set(true); | |
cpu_task.as_mut().step(); | |
bus.busy.set(false); | |
bus.data.set(0xE3A00302); | |
cpu_task.as_mut().step(); | |
assert_eq!( | |
bus.request.get(), | |
Some(MemoryRequest { | |
address: 0x24, | |
width: AccessWidth::Bit32, | |
op: OperationType::Read { | |
is_instruction: true | |
}, | |
seq: true, | |
}) | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
test cpu::test::test_branch ... | |
F[$0], D[FFFFFFFF], E[FFFFFFFF] | |
Fetching from PC=0 | |
Skipping execute | |
F[$4], D[EA000006], E[FFFFFFFF] | |
Fetching from PC=4 | |
Skipping execute | |
F[$8], D[FFFFFFFF], E[EA000006] | |
Fetching from PC=8 | |
Executing EA000006 | |
Branching to PC=20 | |
F[$20], D[FFFFFFFF], E[FFFFFFFF] | |
Fetching from PC=20 | |
Skipping execute | |
waitstate | |
F[$24], D[E3A00302], E[FFFFFFFF] | |
Fetching from PC=24 | |
Skipping execute | |
ok |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment