Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions crates/synth-analysis/src/ssa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,11 +335,11 @@ impl DeadCodeElimination {
SSAInstr::Assign { result, .. }
| SSAInstr::BinOp { result, .. }
| SSAInstr::UnaryOp { result, .. }
| SSAInstr::Load { result, .. } => {
if !used_vars.contains(result) {
removed += 1;
return false;
}
| SSAInstr::Load { result, .. }
if !used_vars.contains(result) =>
{
removed += 1;
return false;
}
_ => {}
}
Expand Down
82 changes: 82 additions & 0 deletions crates/synth-backend/src/mpu_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,4 +339,86 @@ mod tests {
assert!(region.validate().is_ok());
}
}

#[test]
fn test_imxrt1062_has_16_regions() {
// i.MX RT1062 (M7-class) has 16 MPU regions vs 8 on M4-class parts
let hw_caps = HardwareCapabilities::imxrt1062();
assert_eq!(hw_caps.mpu_regions, 16);

let allocator = MPUAllocator::new(hw_caps);
assert_eq!(allocator.available_regions(), 16);
}

#[test]
fn test_m7_can_allocate_more_than_8_regions() {
// Validate that the allocator actually uses all 16 regions on M7
let mut allocator = MPUAllocator::new(HardwareCapabilities::imxrt1062());

for i in 0u32..16 {
let request = MPUAllocationRequest {
memory: Memory {
index: i,
initial: 1,
maximum: None,
shared: false,
memory64: false,
},
permissions: MPUPermissions::FullRW,
attributes: MPUAttributes::normal(),
preferred_base: Some(0x20000000 + i * 0x10000),
};
allocator.allocate(request).unwrap_or_else(|e| {
panic!("region {} allocation failed: {:?}", i, e);
});
}

assert_eq!(allocator.available_regions(), 0);
assert_eq!(allocator.allocated_regions().len(), 16);
}

#[test]
fn test_m4_class_caps_at_8_regions() {
// Negative — M4-class parts must reject the 9th region.
let mut allocator = MPUAllocator::new(HardwareCapabilities::nrf52840());

for i in 0u32..8 {
let request = MPUAllocationRequest {
memory: Memory {
index: i,
initial: 1,
maximum: None,
shared: false,
memory64: false,
},
permissions: MPUPermissions::FullRW,
attributes: MPUAttributes::normal(),
preferred_base: Some(0x20000000 + i * 0x10000),
};
allocator.allocate(request).unwrap();
}

// 9th region must fail
let overflow = MPUAllocationRequest {
memory: Memory {
index: 8,
initial: 1,
maximum: None,
shared: false,
memory64: false,
},
permissions: MPUPermissions::FullRW,
attributes: MPUAttributes::normal(),
preferred_base: Some(0x20100000),
};
assert!(allocator.allocate(overflow).is_err());
}

#[test]
fn test_stm32h743_has_16_regions_and_double_fpu() {
let caps = HardwareCapabilities::stm32h743();
assert_eq!(caps.mpu_regions, 16);
assert!(caps.has_fpu);
assert_eq!(caps.fpu_precision, Some(synth_core::FPUPrecision::Double));
}
}
43 changes: 38 additions & 5 deletions crates/synth-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ enum Commands {
)]
target: String,

/// Hardware config (nrf52840, stm32f407, or custom)
/// Hardware config (nrf52840, stm32f407, stm32h743, imxrt1062, or custom)
#[arg(long, value_name = "HARDWARE", default_value = "nrf52840")]
hardware: String,

Expand Down Expand Up @@ -170,6 +170,11 @@ enum Commands {
/// Path to kiln-builtins object file (.o) for linking (used with --link)
#[arg(long, value_name = "BUILTINS")]
builtins: Option<PathBuf>,

/// Force relocatable object (.o, ET_REL) output even when wasm has no imports
/// — for linking into a host build system.
#[arg(long)]
relocatable: bool,
},

/// Disassemble an ARM ELF file (e.g., synth disasm output.elf)
Expand Down Expand Up @@ -248,6 +253,7 @@ fn main() -> Result<()> {
verify,
link,
builtins,
relocatable,
} => {
// Resolve target spec: --target overrides, --cortex-m is backwards compat
let target_spec = resolve_target_spec(target.as_deref(), cortex_m)?;
Expand All @@ -272,6 +278,7 @@ fn main() -> Result<()> {
&backend,
verify,
&target_spec,
relocatable,
)?;

// If --link requested, invoke the cross-linker
Expand Down Expand Up @@ -356,9 +363,11 @@ fn synthesize_command(
let hw_caps = match hardware.as_str() {
"nrf52840" => HardwareCapabilities::nrf52840(),
"stm32f407" => HardwareCapabilities::stm32f407(),
"stm32h743" => HardwareCapabilities::stm32h743(),
"imxrt1062" => HardwareCapabilities::imxrt1062(),
_ => {
anyhow::bail!(
"Unsupported hardware: {}. Use nrf52840 or stm32f407",
"Unsupported hardware: {}. Use nrf52840, stm32f407, stm32h743, imxrt1062",
hardware
);
}
Expand Down Expand Up @@ -398,8 +407,19 @@ fn target_info_command(target: String) -> Result<()> {
let caps = HardwareCapabilities::stm32f407();
print_hardware_info(&caps);
}
"stm32h743" => {
let caps = HardwareCapabilities::stm32h743();
print_hardware_info(&caps);
}
"imxrt1062" => {
let caps = HardwareCapabilities::imxrt1062();
print_hardware_info(&caps);
}
_ => {
anyhow::bail!("Unknown target: {}. Supported: nrf52840, stm32f407", target);
anyhow::bail!(
"Unknown target: {}. Supported: nrf52840, stm32f407, stm32h743, imxrt1062",
target
);
}
}

Expand Down Expand Up @@ -553,6 +573,7 @@ fn compile_command(
backend_name: &str,
verify: bool,
target_spec: &TargetSpec,
relocatable: bool,
) -> Result<()> {
// Validate backend exists
let registry = build_backend_registry();
Expand Down Expand Up @@ -595,6 +616,7 @@ fn compile_command(
backend,
verify,
target_spec,
relocatable,
);
}

Expand Down Expand Up @@ -1222,6 +1244,7 @@ fn compile_all_exports(
backend: &dyn Backend,
verify: bool,
target_spec: &TargetSpec,
relocatable: bool,
) -> Result<()> {
let path = input.context("--all-exports requires an input file")?;

Expand Down Expand Up @@ -1428,8 +1451,18 @@ fn compile_all_exports(
// When there are relocations, produce a relocatable object (.o) instead of
// an executable. This lets the output be linked with the Kiln bridge crate
// (which provides __meld_dispatch_import and __meld_get_memory_base).
let elf_data = if has_relocations {
info!("Module has import calls — producing relocatable object (ET_REL)");
// The --relocatable flag forces ET_REL output even when the wasm has no
// imports, for linking into a host build system (e.g. Zephyr).
let elf_data = if has_relocations || relocatable {
let total_relocs: usize = compiled_funcs.iter().map(|f| f.relocations.len()).sum();
if has_relocations {
info!(
"Producing relocatable object (ET_REL): {} import call relocations",
total_relocs
);
} else {
info!("Producing relocatable object (ET_REL): forced by --relocatable");
}
build_relocatable_elf(&compiled_funcs, &all_imports)?
} else if cortex_m {
build_multi_func_cortex_m_elf(&compiled_funcs, &all_memories, target_spec)?
Expand Down
43 changes: 43 additions & 0 deletions crates/synth-core/src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,49 @@ impl HardwareCapabilities {
ram_size: 192 * 1024, // 192KB (128KB + 64KB CCM)
}
}

/// Create capabilities for STM32H743 (Cortex-M7 with double-precision FPU)
///
/// 16 MPU regions, 2MB Flash, 1MB RAM (DTCM + AXI SRAM + SRAM1-4).
pub fn stm32h743() -> Self {
Self {
arch: TargetArch::ARMCortexM(CortexMVariant::M7DP),
has_mpu: true,
mpu_regions: 16,
has_pmp: false,
pmp_entries: 0,
has_fpu: true,
fpu_precision: Some(FPUPrecision::Double),
has_simd: false,
simd_level: None,
xip_capable: true,
flash_size: 2 * 1024 * 1024, // 2MB
ram_size: 1024 * 1024, // 1MB total
}
}

/// Create capabilities for i.MX RT1062 (Cortex-M7 with single-precision FPU)
///
/// Representative high-end M7 with 16 MPU regions, single-precision FPU,
/// large OCRAM, and external XIP-capable QuadSPI Flash. Matches the
/// configuration of safety-grade lockstepped M7 platforms used in
/// industrial and embedded automotive contexts.
pub fn imxrt1062() -> Self {
Self {
arch: TargetArch::ARMCortexM(CortexMVariant::M7),
has_mpu: true,
mpu_regions: 16,
has_pmp: false,
pmp_entries: 0,
has_fpu: true,
fpu_precision: Some(FPUPrecision::Single),
has_simd: false,
simd_level: None,
xip_capable: true,
flash_size: 8 * 1024 * 1024, // 8MB external QSPI flash (typical)
ram_size: 1024 * 1024, // 1MB OCRAM (FlexRAM 512KB + OCRAM 512KB)
}
}
}

// ============================================================================
Expand Down
Loading
Loading