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);
}
let known_exceptions = [
"MemManage_Handler",
"BusFault_Handler",
"UsageFault_Handler",
"SVCall_Handler",
"DebugMon_Handler",
"PendSV_Handler",
"SysTick_Handler",
];
let defined_handlers = ["Reset_Handler", "NMI_Handler", "HardFault_Handler"];
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 handler_names: Vec<String> = full_vector_table
.iter()
.filter_map(|entry| {
if entry.starts_with("Some(") && entry.ends_with(")") {
let inside = &entry[5..entry.len()-1];
if inside.ends_with("_Handler") {
Some(inside.to_string())
} else {
None
}
} else {
None
}
})
.collect();
let mut unique_handlers = handler_names.clone();
unique_handlers.sort();
unique_handlers.dedup();
let (handlers_to_define, handlers_to_declare): (Vec<_>, Vec<_>) = unique_handlers
.into_iter()
.partition(|h| defined_handlers.contains(&h.as_str()));
let mut exceptions_to_declare = Vec::new();
let mut irqs_to_declare = Vec::new();
for h in handlers_to_declare {
if known_exceptions.contains(&h.as_str()) {
exceptions_to_declare.push(h);
} else {
irqs_to_declare.push(h);
}
}
let mut top_definitions = String::new();
for handler in handlers_to_define {
top_definitions.push_str(&format!(
"extern \"C\" fn {}() {{ loop {{}} }}\n",
handler
));
}
top_definitions.push('\n');
let mut extern_block = String::from("extern \"C\" {\n");
for handler in &exceptions_to_declare {
extern_block.push_str(&format!(" fn {}();\n", handler));
}
for handler in &irqs_to_declare {
extern_block.push_str(&format!(" fn {}();\n", handler));
}
extern_block.push_str("}\n\n");
let mut vector_table_string = String::new();
vector_table_string.push_str(&top_definitions);
vector_table_string.push_str(&extern_block);
vector_table_string.push_str("static VECTOR_TABLE: [Option<unsafe extern \"C\" fn()>; ");
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);
}
}