use crate::processor::elements::cheri::{IntegerModeCheriAggregateMemory,IntegerModeCheriRV64RegisterFile};
use crate::models::Processor;
use crate::processor::exceptions::IllegalInstructionException::MiscDecodeException;
use anyhow::{Context,Result};
use crate::processor::exceptions::{IllegalInstructionException,MemoryException};
use crate::processor::decode;
use crate::processor::decode::{decode, InstructionBits};
use crate::processor::elements::cheri::{Cc128Cap,CheriRV64RegisterFile,CheriAggregateMemory};
use crate::processor::isa_mods::{IsaMod, Rv64im, Rv64imConn, Rv64imCapabilityMode, XCheri64, XCheri64Conn, Zicsr64, Zicsr64Conn, Rv64Cheriv, CheriVectorRegisterFile, CSRProvider};
pub struct Rv64imvXCheriProcessor {
pub running: bool,
pub memory: CheriAggregateMemory,
start_pc: u64,
pcc: Cc128Cap,
ddc: Cc128Cap,
max_cap: Cc128Cap,
sreg: CheriRV64RegisterFile,
csrs: Rv64imvXCheriProcessorCSRs,
initial_mode: CheriExecMode,
}
pub struct Rv64imvXCheriProcessorModules {
rv64im: Rv64im,
rv64im_cap: Rv64imCapabilityMode,
xcheri: XCheri64,
rvv: Rv64Cheriv,
zicsr: Option<Zicsr64>
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub enum CheriExecMode {
Integer,
Capability,
}
struct Rv64imvXCheriProcessorCSRs {}
impl CSRProvider<u64> for Rv64imvXCheriProcessorCSRs {
fn has_csr(&self, _csr: u32) -> bool {
false
}
fn csr_atomic_read_write(&mut self, _csr: u32, _need_read: bool, _write_val: u64) -> Result<Option<u64>> { todo!() }
fn csr_atomic_read_set(&mut self, _csr: u32, _set_bits: Option<u64>) -> Result<u64> { todo!() }
fn csr_atomic_read_clear(&mut self, _csr: u32, _clear_bits: Option<u64>) -> Result<u64> { todo!() }
}
impl Rv64imvXCheriProcessor {
pub fn new(start_pc: u64, mem: CheriAggregateMemory, mode: CheriExecMode) -> (Rv64imvXCheriProcessor, Rv64imvXCheriProcessorModules) {
let full_range_cap = mem.get_full_range_cap();
let mut pcc = full_range_cap.clone();
pcc.set_address_unchecked(start_pc);
if mode == CheriExecMode::Capability {
pcc.set_flags(1);
}
let mut p = Rv64imvXCheriProcessor {
running: false,
memory: mem,
start_pc,
pcc: pcc,
ddc: full_range_cap,
max_cap: full_range_cap,
sreg: CheriRV64RegisterFile::default(),
csrs: Rv64imvXCheriProcessorCSRs{},
initial_mode: mode,
};
let mut mods = Rv64imvXCheriProcessorModules {
rv64im: Rv64im{},
rv64im_cap: Rv64imCapabilityMode{},
xcheri: XCheri64{},
rvv: Rv64Cheriv::new(Box::new(CheriVectorRegisterFile::default())),
zicsr: Some(Zicsr64::default())
};
p.reset(&mut mods);
(p, mods)
}
fn zicsr_conn<'a,'b>(&'a mut self, rvv: &'a mut Rv64Cheriv) -> Zicsr64Conn<'b> where 'a: 'b {
let csr_providers = vec![
&mut self.csrs as &mut dyn CSRProvider<u64>,
rvv as &mut dyn CSRProvider<u64>,
];
Zicsr64Conn {
sreg: &mut self.sreg,
csr_providers
}
}
fn xcheri64_conn<'a,'b>(&'a mut self, mode: CheriExecMode) -> XCheri64Conn<'b> where 'a: 'b {
XCheri64Conn {
pcc: self.pcc,
sreg: &mut self.sreg,
memory: &mut self.memory,
mode,
ddc: self.ddc,
}
}
fn process_inst(&mut self, mods: &mut Rv64imvXCheriProcessorModules, inst_bits: u32, opcode: decode::Opcode, inst: InstructionBits) -> Result<Cc128Cap> {
let mode = match self.pcc.flags() {
0 => CheriExecMode::Integer,
1 => CheriExecMode::Capability,
_ => bail!("invalid flag in PC")
};
let mut next_pcc = self.pcc;
next_pcc.set_address_unchecked(next_pcc.address() + 4);
if mods.xcheri.will_handle(opcode, inst) {
let requested_pcc = mods.xcheri.execute(opcode, inst, inst_bits, self.xcheri64_conn(mode))?;
if let Some(requested_pcc) = requested_pcc {
next_pcc = requested_pcc;
}
return Ok(next_pcc);
}
if mode == CheriExecMode::Capability && mods.rv64im_cap.will_handle(opcode, inst) {
let requested_pc = mods.rv64im_cap.execute(opcode, inst, inst_bits, self.xcheri64_conn(mode))?;
if let Some(requested_pc) = requested_pc {
next_pcc.set_address_unchecked(requested_pc);
}
return Ok(next_pcc);
} else if mods.rv64im.will_handle(opcode, inst) {
let requested_pc = {
let mut mem_wrap = IntegerModeCheriAggregateMemory::wrap(&mut self.memory, self.ddc);
mods.rv64im.execute(opcode, inst, inst_bits, Rv64imConn {
pc: self.pcc.address(),
sreg: &mut self.sreg,
memory: &mut mem_wrap,
})?
};
if let Some(requested_pc) = requested_pc {
next_pcc.set_address_unchecked(requested_pc);
}
return Ok(next_pcc);
}
if mods.rvv.will_handle(opcode, inst) {
let requested_pc = match mode {
CheriExecMode::Capability => mods.rvv.execute(opcode, inst, inst_bits, (
&mut self.sreg,
&mut self.memory,
))?,
CheriExecMode::Integer => {
let mut reg_wrap = IntegerModeCheriRV64RegisterFile::wrap(&mut self.sreg, self.ddc);
let mut mem_wrap = IntegerModeCheriAggregateMemory::wrap(&mut self.memory, self.ddc);
mods.rvv.execute(opcode, inst, inst_bits, (
&mut reg_wrap,
&mut mem_wrap,
))?
}
};
if let Some(_) = requested_pc {
bail!("vector shouldn't try to jump");
}
return Ok(next_pcc);
}
if let Some(zicsr) = mods.zicsr.as_mut() {
if zicsr.will_handle(opcode, inst) {
let requested_pc = zicsr.execute(opcode, inst, inst_bits, self.zicsr_conn(&mut mods.rvv))?;
if let Some(_) = requested_pc {
bail!("csr shouldn't try to jump");
}
return Ok(next_pcc);
}
}
bail!(MiscDecodeException("Unexpected opcode/InstructionBits pair".to_string()))
}
}
impl Processor<Rv64imvXCheriProcessorModules> for Rv64imvXCheriProcessor {
fn reset(&mut self, _mods: &mut Rv64imvXCheriProcessorModules) {
self.running = false;
self.pcc = self.max_cap;
self.pcc.set_address_unchecked(self.start_pc);
if self.initial_mode == CheriExecMode::Capability {
self.pcc.set_flags(1);
}
self.sreg.reset();
}
fn exec_step(&mut self, mods: &mut Rv64imvXCheriProcessorModules) -> Result<()> {
self.running = true;
let next_pcc_res: Result<Cc128Cap> = {
let inst_bits = self.memory.fetch_inst_u32(self.pcc).context("Couldn't load next instruction")?;
let (opcode, inst) = decode(inst_bits)
.with_context(|| format!("Failed to decode instruction {:08x}", inst_bits))?;
let next_pcc = self.process_inst(mods, inst_bits, opcode, inst)
.with_context(|| format!("Failed to execute decoded instruction {:?} {:x?}", opcode, inst))?;
if next_pcc.address() % 4 != 0 {
Err(MemoryException::JumpMisaligned{addr: next_pcc.address() as usize, expected: 4})?
} else {
Ok(next_pcc)
}
};
let next_pcc = match next_pcc_res {
Ok(val) => val,
Err(err) => {
if let Some(_iie) = err.downcast_ref::<IllegalInstructionException>() {
println!("Found Illegal Instruction error");
return Err(err)
} else if let Some(_mem) = err.downcast_ref::<MemoryException>() {
println!("Found Memory error");
return Err(err)
} else {
println!("Untrappable error");
return Err(err)
}
}
};
self.pcc = next_pcc;
Ok(())
}
fn dump(&self, mods: &Rv64imvXCheriProcessorModules) {
println!("running: {:?}\npc: {:x?}\nddc: {:x?}", self.running, self.pcc, self.ddc);
self.sreg.dump();
mods.rvv.dump();
}
fn running(&self) -> bool {
self.running
}
fn get_io_values(&self) -> Vec<Option<u64>> {
self.memory.get_io_values()
}
}