use std::fs;
use std::fs::File;
use std::io::Write;
use svd_parser::{
parse,
svd::{Cpu, Device},
};
fn main() {
let current_dir = std::env::current_dir().expect("Failed to get current directory");
println!("Scanning directory: {:?}", current_dir);
let svd_files: Vec<_> = fs::read_dir(¤t_dir)
.expect("Failed to read directory")
.filter_map(|entry| {
let entry = entry.expect("Failed to get directory entry");
let path = entry.path();
if let Some(extension) = path.extension() {
if extension == "svd" {
return Some(path);
}
}
None
})
.collect();
if svd_files.is_empty() {
eprintln!("No SVD files found. Please place SVD files in the project directory.");
std::process::exit(1);
}
for path in svd_files {
let svd_content = fs::read_to_string(&path).expect("Failed to read SVD file");
let device: Device = parse(&svd_content).expect("Failed to parse SVD file");
let system_exceptions: Vec<String> = match device.cpu {
Some(Cpu { name, .. }) => match name.as_str() {
"CM0" | "CM0+" => vec![
"Some(Reset_Handler)".to_string(),
"Some(NMI_Handler)".to_string(),
"Some(HardFault_Handler)".to_string(),
"None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "Some(SVCall_Handler)".to_string(),
"None".to_string(), "None".to_string(), "Some(PendSV_Handler)".to_string(),
"Some(SysTick_Handler)".to_string(),
],
"CM3" | "CM4" | "CM7" => vec![
"Some(Reset_Handler)".to_string(),
"Some(NMI_Handler)".to_string(),
"Some(HardFault_Handler)".to_string(),
"Some(MemManage_Handler)".to_string(),
"Some(BusFault_Handler)".to_string(),
"Some(UsageFault_Handler)".to_string(),
"None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "Some(SVCall_Handler)".to_string(),
"None".to_string(), "None".to_string(), "Some(PendSV_Handler)".to_string(),
"Some(SysTick_Handler)".to_string(),
],
_ => vec![
"Some(Reset_Handler)".to_string(),
"Some(NMI_Handler)".to_string(),
"Some(HardFault_Handler)".to_string(),
"None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "Some(SVCall_Handler)".to_string(),
"None".to_string(), "None".to_string(), "Some(PendSV_Handler)".to_string(),
"Some(SysTick_Handler)".to_string(),
],
},
None => vec![
"Some(Reset_Handler)".to_string(),
"Some(NMI_Handler)".to_string(),
"Some(HardFault_Handler)".to_string(),
"None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "None".to_string(), "Some(SVCall_Handler)".to_string(),
"None".to_string(), "None".to_string(), "Some(PendSV_Handler)".to_string(),
"Some(SysTick_Handler)".to_string(),
],
};
let mut interrupts = Vec::new();
for peripheral in &device.peripherals {
for interrupt in &peripheral.interrupt {
interrupts.push(interrupt.clone());
}
}
let max_interrupt_number = interrupts
.iter()
.map(|interrupt| interrupt.value as usize)
.max()
.unwrap_or(0);
let mut vector_table: Vec<String> = vec!["None".to_string(); max_interrupt_number + 1];
for interrupt in &interrupts {
vector_table[interrupt.value as usize] = format!("Some({}_Handler)", interrupt.name);
}
let mut full_vector_table = system_exceptions;
full_vector_table.extend(vector_table.into_iter());
let mut vector_table_string = "static VECTOR_TABLE: [Option<unsafe fn()>; ".to_string();
vector_table_string.push_str(&full_vector_table.len().to_string());
vector_table_string.push_str("] = [\n");
for entry in full_vector_table {
vector_table_string.push_str(&format!(" {},\n", entry));
}
vector_table_string.push_str("];\n");
let file_stem = path
.file_stem()
.unwrap_or_default()
.to_str()
.unwrap_or("unknown");
let vector_output_path = format!("vector_{}.txt", file_stem);
let mut vector_file =
File::create(&vector_output_path).expect("Failed to create vector output file");
vector_file
.write_all(vector_table_string.as_bytes())
.expect("Failed to write to vector output file");
println!("Generated {}", vector_output_path);
let mut device_entries = String::new();
for interrupt in &interrupts {
device_entries.push_str(&format!("PROVIDE({} = default_handler);\n", interrupt.name));
}
let device_output_path = format!("device_{}.x", file_stem);
let mut device_file =
File::create(&device_output_path).expect("Failed to create device output file");
device_file
.write_all(device_entries.as_bytes())
.expect("Failed to write to device output file");
println!("Generated {}", device_output_path);
}
}