use std::num::{NonZeroU32, NonZeroU64};
use crate::emulator::{Alias, EmulatorCommand, Property};
pub const MACHINE: &str = "rigless-armv7m";
pub const PROPERTIES: [(&str, &str); 5] = [
(CLOCK_HZ, "size"),
(INTERRUPT_LINES, "uint32"),
(PRIORITY_BITS, "uint8"),
(PPB_WINDOWS, "string"),
(REFCLK_DIVIDER, "uint32"),
];
const WINDOW_SEPARATOR: &str = "+";
const RESET_VECTOR: u64 = 0;
const CLOCK_HZ: &str = "clock-hz";
const INTERRUPT_LINES: &str = "num-irq";
const PRIORITY_BITS: &str = "num-prio-bits";
const REFCLK_DIVIDER: &str = "refclk-divider";
const PPB_WINDOWS: &str = "ppb-windows";
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Model {
M3,
M4,
M7,
M33,
}
impl Model {
pub const ALL: [Self; 4] = [Self::M3, Self::M4, Self::M7, Self::M33];
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Self::M3 => "cortex-m3",
Self::M4 => "cortex-m4",
Self::M7 => "cortex-m7",
Self::M33 => "cortex-m33",
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Core {
pub model: Model,
pub clock_hz: NonZeroU64,
pub interrupt_lines: NonZeroU32,
pub priority_bits: u8,
pub refclk_divider: NonZeroU32,
pub icount_shift: u32,
pub boot: &'static str,
}
impl Core {
#[must_use]
pub fn command(self, ppb: &[crate::cpu::armv7m::Window]) -> EmulatorCommand {
EmulatorCommand {
machine: MACHINE,
cpu: self.model.name(),
properties: vec![
Property::new(CLOCK_HZ, self.clock_hz),
Property::new(INTERRUPT_LINES, self.interrupt_lines),
Property::new(PRIORITY_BITS, self.priority_bits),
Property::new(REFCLK_DIVIDER, self.refclk_divider),
Property::new(
PPB_WINDOWS,
ppb.iter()
.map(ToString::to_string)
.collect::<Vec<String>>()
.join(WINDOW_SEPARATOR),
),
],
icount_shift: self.icount_shift,
aliases: vec![Alias {
region: self.boot,
at: RESET_VECTOR,
}],
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn core() -> Core {
Core {
model: Model::M4,
clock_hz: NonZeroU64::new(168_000_000).unwrap(),
interrupt_lines: NonZeroU32::new(91).unwrap(),
priority_bits: 4,
refclk_divider: NonZeroU32::new(8).unwrap(),
icount_shift: 2,
boot: "flash",
}
}
const WINDOWS: [crate::cpu::armv7m::Window; 2] = [
crate::cpu::armv7m::Window {
base: 0xE000_0000,
size: 0x1000,
},
crate::cpu::armv7m::Window {
base: 0xE000_1000,
size: 0x8,
},
];
fn rendered(core: Core) -> Vec<String> {
core.command(&WINDOWS)
.properties
.iter()
.map(ToString::to_string)
.collect()
}
#[test]
fn the_properties_render_as_the_machine_spells_them() {
assert_eq!(
rendered(core()),
[
"clock-hz=168000000",
"num-irq=91",
"num-prio-bits=4",
"refclk-divider=8",
"ppb-windows=0xe0000000:0x1000+0xe0001000:0x8",
]
);
let command = core().command(&WINDOWS);
assert_eq!(command.machine, MACHINE);
assert_eq!(command.cpu, "cortex-m4");
assert_eq!(
command.properties.len(),
PROPERTIES.len(),
"every property the machine declares is set"
);
}
#[test]
fn the_boot_region_is_the_one_the_core_also_finds_at_its_reset_vector() {
assert_eq!(
core().command(&WINDOWS).aliases,
[Alias {
region: "flash",
at: 0
}]
);
let from_system = Core {
boot: "system",
..core()
};
assert_eq!(
from_system.command(&WINDOWS).aliases,
[Alias {
region: "system",
at: 0
}],
"the SoC's boot configuration says which region, not the family"
);
}
}