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
11 changes: 9 additions & 2 deletions crates/synth-backend/src/arm_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,13 @@ impl Backend for ArmBackend {
}

fn supported_targets(&self) -> Vec<TargetSpec> {
vec![TargetSpec::cortex_m4(), TargetSpec::cortex_m7()]
vec![
TargetSpec::cortex_m3(),
TargetSpec::cortex_m4(),
TargetSpec::cortex_m4f(),
TargetSpec::cortex_m7(),
TargetSpec::cortex_m7dp(),
]
}

fn compile_module(
Expand Down Expand Up @@ -149,6 +155,7 @@ fn compile_wasm_to_arm(
let db = RuleDatabase::with_standard_rules();
let mut selector =
InstructionSelector::with_bounds_check(db.rules().to_vec(), bounds_config);
selector.set_target(config.target.fpu, &config.target.triple);
if config.num_imports > 0 {
selector.set_num_imports(config.num_imports);
}
Expand Down Expand Up @@ -181,7 +188,7 @@ fn compile_wasm_to_arm(
let use_thumb2 = matches!(config.target.isa, IsaVariant::Thumb2 | IsaVariant::Thumb);

let encoder = if use_thumb2 {
ArmEncoder::new_thumb2()
ArmEncoder::new_thumb2_with_fpu(config.target.fpu)
} else {
ArmEncoder::new_arm32()
};
Expand Down
22 changes: 20 additions & 2 deletions crates/synth-backend/src/arm_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,41 @@
//! Generates ARM32/Thumb-2 machine code from ARM instruction structures

use synth_core::Result;
use synth_core::target::FPUPrecision;
use synth_synthesis::{ArmOp, MemAddr, Operand2, Reg};

/// ARM instruction encoding
pub struct ArmEncoder {
/// Use Thumb mode (vs ARM mode)
thumb_mode: bool,
/// FPU capability (prep for VFP encoding in Task 4)
#[allow(dead_code)]
fpu: Option<FPUPrecision>,
}

impl ArmEncoder {
/// Create a new ARM encoder in ARM32 mode
pub fn new_arm32() -> Self {
Self { thumb_mode: false }
Self {
thumb_mode: false,
fpu: None,
}
}

/// Create a new ARM encoder in Thumb-2 mode
pub fn new_thumb2() -> Self {
Self { thumb_mode: true }
Self {
thumb_mode: true,
fpu: None,
}
}

/// Create a new Thumb-2 encoder with FPU capability
pub fn new_thumb2_with_fpu(fpu: Option<FPUPrecision>) -> Self {
Self {
thumb_mode: true,
fpu,
}
}

/// Encode a single ARM instruction to bytes
Expand Down
40 changes: 36 additions & 4 deletions crates/synth-backend/src/cortex_m.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ pub struct StartupCode {
pub bss_start: u32,
/// BSS section end
pub bss_end: u32,
/// Enable FPU (set CPACR for CP10+CP11 full access)
pub enable_fpu: bool,
}

impl StartupCode {
Expand All @@ -83,22 +85,52 @@ impl StartupCode {
data_load: 0,
bss_start: 0,
bss_end: 0,
enable_fpu: false,
}
}

/// Generate Thumb-2 startup code (reset handler)
///
/// This generates minimal startup code that:
/// 1. Sets up the stack pointer (already done by hardware from vector table)
/// 2. Initializes R11 as linear memory base (0x20000000)
/// 3. Calls the entry point
/// 4. Loops forever if entry returns
/// 1. Optionally enables FPU (CPACR setup for CP10+CP11)
/// 2. Sets up the stack pointer (already done by hardware from vector table)
/// 3. Initializes R11 as linear memory base (0x20000000)
/// 4. Calls the entry point
/// 5. Loops forever if entry returns
pub fn generate_thumb(&self) -> Vec<u8> {
let mut code = Vec::new();

// Reset handler entry point
// The stack pointer is already set by hardware from vector table[0]

// Enable FPU: set CP10+CP11 to full access in SCB->CPACR (0xE000ED88)
if self.enable_fpu {
// MOVW R0, #0xED88 (low 16 bits of CPACR address)
// Thumb-2 MOVW encoding: 1111 0 i 10 0 1 0 0 imm4 | 0 imm3 Rd imm8
// 0xED88: imm4=0xE, i=1, imm3=0b101, imm8=0x88
code.extend_from_slice(&[0x4E, 0xF6, 0x88, 0x50]); // MOVW R0, #0xED88

// MOVT R0, #0xE000 (high 16 bits of CPACR address)
// 0xE000: imm4=0xE, i=0, imm3=0, imm8=0
code.extend_from_slice(&[0xCE, 0xF2, 0x00, 0x00]); // MOVT R0, #0xE000

// LDR R1, [R0]
code.extend_from_slice(&[0xD0, 0xF8, 0x00, 0x10]); // LDR R1, [R0, #0]

// ORR R1, R1, #0x00F00000 (enable CP10+CP11 full access)
// Thumb-2 ORR with modified immediate: 0x00F00000
code.extend_from_slice(&[0x41, 0xF0, 0xF0, 0x61]); // ORR R1, R1, #0x00F00000

// STR R1, [R0]
code.extend_from_slice(&[0xC0, 0xF8, 0x00, 0x10]); // STR R1, [R0, #0]

// DSB (data synchronization barrier)
code.extend_from_slice(&[0xBF, 0xF3, 0x4F, 0x8F]); // DSB SY

// ISB (instruction synchronization barrier)
code.extend_from_slice(&[0xBF, 0xF3, 0x6F, 0x8F]); // ISB SY
}

// Initialize R11 with linear memory base address (0x20000000)
// This is used for WASM linear memory access: LDR Rd, [R11, Raddr]
// Thumb-2 MOVW R11, #0x0000 (low 16 bits)
Expand Down
19 changes: 17 additions & 2 deletions crates/synth-backend/src/elf_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,13 @@ pub struct Relocation {
pub reloc_type: ArmRelocationType,
}

/// ARM EABI version 5 (soft-float)
pub const EF_ARM_EABI_VER5: u32 = 0x05000000;
/// ARM hard-float ABI flag
pub const EF_ARM_ABI_FLOAT_HARD: u32 = 0x00000400;
/// ARM soft-float ABI flag
pub const EF_ARM_ABI_FLOAT_SOFT: u32 = 0x00000200;

/// ELF file builder
pub struct ElfBuilder {
/// File class (32 or 64 bit)
Expand All @@ -357,6 +364,8 @@ pub struct ElfBuilder {
machine: ElfMachine,
/// Entry point address
entry: u32,
/// ELF e_flags (EABI version + float ABI)
e_flags: u32,
/// Sections
sections: Vec<Section>,
/// Symbols
Expand All @@ -376,6 +385,7 @@ impl ElfBuilder {
elf_type: ElfType::Exec,
machine: ElfMachine::Arm,
entry: 0,
e_flags: EF_ARM_EABI_VER5,
sections: Vec::new(),
symbols: Vec::new(),
program_headers: Vec::new(),
Expand All @@ -389,6 +399,11 @@ impl ElfBuilder {
self
}

/// Set ELF e_flags (e.g. to add hard-float ABI)
pub fn set_flags(&mut self, flags: u32) {
self.e_flags = flags;
}

/// Set file type
pub fn with_type(mut self, elf_type: ElfType) -> Self {
self.elf_type = elf_type;
Expand Down Expand Up @@ -643,8 +658,8 @@ impl ElfBuilder {
output[cursor..cursor + 4].copy_from_slice(&sh_offset.to_le_bytes());
cursor += 4;

// Flags (little-endian u32) - ARM EABI version 5
output[cursor..cursor + 4].copy_from_slice(&0x05000000u32.to_le_bytes());
// Flags (little-endian u32) - ARM EABI version 5 + float ABI
output[cursor..cursor + 4].copy_from_slice(&self.e_flags.to_le_bytes());
cursor += 4;

// ELF header size (little-endian u16)
Expand Down
6 changes: 3 additions & 3 deletions crates/synth-backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ pub mod mpu_allocator;
pub mod w2c2_wrapper;

pub use elf_builder::{
ArmRelocationType, ElfBuilder, ElfClass, ElfData, ElfMachine, ElfType, ProgramFlags,
ProgramHeader, ProgramType, Relocation, Section, SectionFlags, SectionType as ElfSectionType,
Symbol, SymbolBinding, SymbolType,
ArmRelocationType, EF_ARM_ABI_FLOAT_HARD, EF_ARM_ABI_FLOAT_SOFT, EF_ARM_EABI_VER5, ElfBuilder,
ElfClass, ElfData, ElfMachine, ElfType, ProgramFlags, ProgramHeader, ProgramType, Relocation,
Section, SectionFlags, SectionType as ElfSectionType, Symbol, SymbolBinding, SymbolType,
};
pub use linker_script::{LinkerScriptGenerator, MemoryRegion};
pub use memory_layout::{MemoryLayout, MemoryLayoutAnalyzer, MemorySection, SectionType};
Expand Down
7 changes: 5 additions & 2 deletions crates/synth-backend/tests/f64_operations_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ fn assert_float_rejected(wasm_ops: Vec<WasmOp>, op_name: &str) {
);
let err = result.unwrap_err().to_string();
assert!(
err.contains("floating-point") || err.contains("i64"),
"{op_name} error should mention floating-point or i64, got: {err}"
err.contains("no FPU")
|| err.contains("VFP")
|| err.contains("floating-point")
|| err.contains("i64"),
"{op_name} error should mention FPU/VFP/floating-point or i64, got: {err}"
);
}

Expand Down
Loading
Loading