Skip to content

Commit

Permalink
Refactor Gpr struct in gpr.rs and add record field for difftest
Browse files Browse the repository at this point in the history
  • Loading branch information
Clo91eaf committed May 1, 2024
1 parent 0692333 commit 2d39f91
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 18 deletions.
10 changes: 7 additions & 3 deletions src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ pub struct Cpu {
reservation_set: Vec<u64>,
/// Idle state. True when WFI is called, and becomes false when an interrupt happens.
pub idle: bool,

pub diff: Vec<>,
}

impl Cpu {
Expand Down Expand Up @@ -225,7 +223,8 @@ impl Cpu {
}

/// Translate a virtual address to a physical address for the paged virtual-memory system.
fn translate(&mut self, addr: u64, access_type: AccessType) -> Result<u64, Exception> {
/// pub for dut to access
pub fn translate(&mut self, addr: u64, access_type: AccessType) -> Result<u64, Exception> {
if !self.enable_paging || self.mode == Mode::Machine {
return Ok(addr);
}
Expand Down Expand Up @@ -461,18 +460,23 @@ impl Cpu {
return Ok(0);
}

// Reset the record of the register for difftest.
self.gpr.reset_record();

// Fetch. It can be optimized by only one fetch.
let inst16 = self.fetch(HALFWORD)?;
let inst = self.fetch(WORD)?;
match inst16 & 0b11 {
0 | 1 | 2 => {
self.execute_compressed(inst16)?;

// Add 2 bytes to the program counter.
self.pc = self.pc.wrapping_add(2);
Ok(inst16)
}
_ => {
self.execute_general(inst)?;

// Add 4 bytes to the program counter.
self.pc = self.pc.wrapping_add(4);
Ok(inst)
Expand Down
17 changes: 14 additions & 3 deletions src/cpu/gpr.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::fmt;

use crate::cpu::{REGISTERS_COUNT, DRAM_BASE, DRAM_SIZE, POINTER_TO_DTB};
use crate::cpu::{DRAM_BASE, DRAM_SIZE, POINTER_TO_DTB, REGISTERS_COUNT};

/// The integer registers.
#[derive(Debug)]
pub struct Gpr {
gpr: [u64; REGISTERS_COUNT],

pub record: Option<(u8, u64)>,
}

impl Gpr {
Expand All @@ -27,19 +29,28 @@ impl Gpr {
// So, we need to set registers register to the state as they are when a bootloader finished.
gpr[10] = 0;
gpr[11] = POINTER_TO_DTB;
Self { gpr }
Self { gpr, record: None }
}

/// Read the value from a register.
pub fn read(&self, index: u64) -> u64 {
self.gpr[index as usize]
}

pub fn reset_record(&mut self) {
self.record = None;
}

fn record(&mut self, wnum: u8, wdata: u64) {
self.record = Some((wnum, wdata));
}

/// Write the value to a register.
pub fn write(&mut self, index: u64, value: u64) {
// Register x0 is hardwired with all bits equal to 0.
if index != 0 {
self.gpr[index as usize] = value;
self.record(index as u8, value);
}
}
}
Expand Down Expand Up @@ -75,4 +86,4 @@ impl fmt::Display for Gpr {
}
write!(f, "{}", output)
}
}
}
34 changes: 32 additions & 2 deletions src/dut.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
mod top;
use top::Top;
use crate::emulator::DebugInfo;

pub struct SramRequest {
pub en: bool,
pub addr: u32,
}

impl SramRequest {
pub fn new(en: bool, addr: u32) -> Self {
SramRequest { en, addr }
}
}

// sram interface
pub struct Dut {
Expand Down Expand Up @@ -42,8 +54,9 @@ impl Dut {
}

/// drive the instruction SRAM interface
pub fn step(&mut self, inst: u32) -> anyhow::Result<bool> {
pub fn step(&mut self, inst: u32, data: u64) -> anyhow::Result<(SramRequest, SramRequest, DebugInfo)> {
self.top.set_inst_sram_rdata(inst);
self.top.set_data_sram_rdata(data);

self.top.clock_toggle();
self.top.eval();
Expand All @@ -60,7 +73,24 @@ impl Dut {
println!("debug_reg_wnum: {}", self.top.debug_reg_wnum());
println!("debug_wdata: 0x{:x}", self.top.debug_wdata());

Ok(self.top.inst_sram_en() != 0)
Ok({
(
SramRequest::new(
self.top.inst_sram_en() != 0,
self.top.inst_sram_addr(),
),
SramRequest::new(
self.top.data_sram_en() != 0,
self.top.data_sram_addr(),
),
DebugInfo::new(
self.top.debug_commit() != 0,
self.top.debug_pc(),
self.top.debug_reg_wnum(),
self.top.debug_wdata(),
)
)
})
}
}

Expand Down
94 changes: 84 additions & 10 deletions src/emulator.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,42 @@
//! The emulator module represents an entire computer.
use core::fmt;

use crate::cpu::Cpu;
use crate::dut::Dut;
use crate::exception::Trap;

#[derive(Default)]
pub struct DebugInfo {
pub commit: bool,
pub pc: u64,
pub wnum: u8,
pub wdata: u64,
}

impl fmt::Display for DebugInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "commit: {}, pc: 0x{:#x}, wnum: {}, wdata: 0x{:#x}", self.commit, self.pc, self.wnum, self.wdata)
}
}

impl PartialEq for DebugInfo {
fn eq(&self, other: &Self) -> bool {
self.commit == other.commit
&& self.pc == other.pc
&& self.wnum == other.wnum
&& self.wdata == other.wdata
}
}

impl Eq for DebugInfo {}

impl DebugInfo {
pub fn new(commit: bool, pc: u64, wnum: u8, wdata: u64) -> Self {
DebugInfo { commit, pc, wnum, wdata }
}
}

/// The emulator to hold a CPU.
pub struct Emulator {
/// The CPU which is the core implementation of this emulator.
Expand Down Expand Up @@ -64,23 +97,64 @@ impl Emulator {
/// Start executing the emulator.
pub fn start(&mut self) {
let mut inst: u32 = 0;
let mut data: u64 = 0;
loop {
// ================ cpu ====================
let pc = self.cpu.pc;
let trap = self.execute();
println!("pc: {:#x}, inst: {}", pc, self.cpu.inst);
let mut cpu_diff = DebugInfo::default();
loop {
let pc = self.cpu.pc;
let trap = self.execute();
println!("pc: {:#x}, inst: {}", pc, self.cpu.inst);

match trap {
Trap::Fatal => {
println!("pc: {:#x}, trap {:#?}", self.cpu.pc, trap);
return;
}
_ => {}
}

match self.cpu.gpr.record {
Some((wnum, wdata)) => {
cpu_diff = DebugInfo::new(true, pc, wnum, wdata);
break;
}
None => {}
}
}

// ================ dut ====================
// continue to step the DUT until the instruction is ready
while !self.dut.step(inst).unwrap() {}
inst = self.cpu.inst.bits;
let mut dut_diff = DebugInfo::default();
loop {
let (inst_sram, data_sram, debug_info) = self.dut.step(inst, data).unwrap();

if data_sram.en {
let p_addr = self.cpu.translate(data_sram.addr as u64, crate::cpu::AccessType::Instruction).unwrap();

match trap {
Trap::Fatal => {
println!("pc: {:#x}, trap {:#?}", self.cpu.pc, trap);
return;
// The result of the read method can be `Exception::LoadAccessFault`. In fetch(), an error
// should be `Exception::InstructionAccessFault`.
data = self.cpu.bus.read(p_addr, crate::cpu::DOUBLEWORD).unwrap();
}
_ => {}

if inst_sram.en {
let p_pc = self.cpu.translate(inst_sram.addr as u64, crate::cpu::AccessType::Instruction).unwrap();

// The result of the read method can be `Exception::LoadAccessFault`. In fetch(), an error
// should be `Exception::InstructionAccessFault`.
inst = self.cpu.bus.read(p_pc, crate::cpu::WORD).unwrap() as u32;
}

if debug_info.commit {
dut_diff = debug_info;
break;
}
}

// ==================== diff ====================
if cpu_diff != dut_diff {
println!("pc: {:#x}\ncpu: {}\ndut: {}\n", self.cpu.pc, cpu_diff, dut_diff);
return;
}
}
}
Expand Down

0 comments on commit 2d39f91

Please sign in to comment.