use std::sync::{Arc, Mutex};
use std::time::Duration;
use crate::architecture::riscv::communication_interface::{
AccessRegisterCommand, MemoryAccessMethod, RiscvBusAccess, RiscvCommunicationInterface,
};
use crate::architecture::riscv::sequences::RiscvDebugSequence;
use crate::core::RegisterId;
use crate::memory::MemoryInterface;
const QSPI0_BASE: u64 = 0x1004_0000;
const QSPI_FCTRL: u64 = 0x60;
const FCTRL_EN: u32 = 1;
#[derive(Debug)]
pub struct SifiveSequence {
saved_fctrl: Mutex<Option<u32>>,
}
impl SifiveSequence {
pub fn create() -> Arc<dyn RiscvDebugSequence> {
Arc::new(Self {
saved_fctrl: Mutex::new(None),
})
}
fn bootstrap_ebreakm(interface: &mut RiscvCommunicationInterface) -> Result<(), crate::Error> {
const S1_REGNO: RegisterId = RegisterId(0x1009);
const DCSR_EBREAKM_PRV_M: u32 = (1 << 15) | 0x3;
const CSRRS_X0_DCSR_X9: u32 = 0x7B04A073;
interface
.abstract_cmd_register_write(S1_REGNO, DCSR_EBREAKM_PRV_M)
.map_err(crate::Error::Riscv)?;
interface
.schedule_setup_program_buffer(&[CSRRS_X0_DCSR_X9])
.map_err(crate::Error::Riscv)?;
let mut cmd = AccessRegisterCommand(0);
cmd.set_cmd_type(0);
cmd.set_aarsize(RiscvBusAccess::A32); cmd.set_postexec(true);
cmd.set_transfer(false);
interface
.execute_abstract_command(cmd.0)
.map_err(crate::Error::Riscv)?;
tracing::debug!("SifiveSequence: dcsr.ebreakm=1 and prv=M set via progbuf bootstrap");
Ok(())
}
}
impl RiscvDebugSequence for SifiveSequence {
fn reset_system_and_halt(
&self,
interface: &mut RiscvCommunicationInterface,
timeout: Duration,
) -> Result<(), crate::Error> {
interface.clear_abstractauto();
interface.reset_hart_and_halt(timeout)?;
if let Err(e) = Self::bootstrap_ebreakm(interface) {
tracing::warn!(
"SifiveSequence::reset_system_and_halt: bootstrap_ebreakm failed: {:?}",
e
);
}
tracing::debug!("SifiveSequence: reset complete, dcsr.ebreakm=1 re-established");
Ok(())
}
fn on_connect(&self, interface: &mut RiscvCommunicationInterface) -> Result<(), crate::Error> {
interface.clear_abstractauto();
let config = interface.memory_access_config();
for width in [
RiscvBusAccess::A8,
RiscvBusAccess::A16,
RiscvBusAccess::A32,
RiscvBusAccess::A64,
RiscvBusAccess::A128,
] {
config.set_default_method(width, MemoryAccessMethod::ProgramBuffer);
}
if let Err(e) = Self::bootstrap_ebreakm(interface) {
tracing::warn!(
"SifiveSequence: bootstrap_ebreakm failed (will try to continue): {:?}",
e
);
}
if let Ok(misa) = interface.read_csr_progbuf_64(0x301) {
let mxl = misa >> 62;
if mxl == 2 {
tracing::info!(
"SifiveSequence: detected RV64 (MISA={:#018x}), setting xlen_64",
misa
);
interface.set_xlen_64(true);
} else {
tracing::debug!("SifiveSequence: MISA={:#018x}, MXL={}", misa, mxl);
}
}
tracing::debug!("SifiveSequence: enabling force_machine_mode_progbuf");
interface.set_force_machine_mode_progbuf(true);
let fctrl_addr = QSPI0_BASE + QSPI_FCTRL;
let current_fctrl = interface.read_word_32(fctrl_addr)?;
tracing::debug!(
"SifiveSequence: QSPI0 fctrl @ {:#010x} = {:#010x}",
fctrl_addr,
current_fctrl
);
if let Ok(mut saved) = self.saved_fctrl.lock() {
*saved = Some(current_fctrl);
}
if current_fctrl & FCTRL_EN == 0 {
tracing::info!(
"SifiveSequence: QSPI0 XIP disabled (fctrl={:#010x}), re-enabling for flash access",
current_fctrl
);
interface.write_word_32(fctrl_addr, current_fctrl | FCTRL_EN)?;
} else {
tracing::debug!("SifiveSequence: QSPI0 XIP already enabled");
}
Ok(())
}
}