Improve the core generator so that it doesn't generate broken modules

Now that the core generator is set to generate modules for all
microcontrollers, we need to blacklist the ones it cannot yet handle.
This commit is contained in:
Dylan McKay 2021-01-28 06:05:26 +13:00
parent ccad9c169b
commit d6ab7fafd2
2 changed files with 185 additions and 27 deletions

View File

@ -9,6 +9,7 @@ pub fn write_registers(mcu: &Mcu, w: &mut dyn Write) -> Result<(), io::Error> {
// HACK: Skip, atmeg328p pack defines two of these.
if register.name == "GTCCR" { continue; }
writeln!(w, "#[allow(non_camel_case_types)]")?;
writeln!(w, "pub struct {};", register.name)?;
writeln!(w)?;
@ -47,6 +48,8 @@ pub fn write_registers(mcu: &Mcu, w: &mut dyn Write) -> Result<(), io::Error> {
pub fn write_pins(mcu: &Mcu, w: &mut dyn Write) -> Result<(), io::Error> {
if let Some(port) = mcu.peripheral("PORT") {
writeln!(w, "pub mod port {{")?;
writeln!(w, " #![allow(unused_imports)]")?;
writeln!(w)?;
writeln!(w, " use super::*;")?;
writeln!(w, " use crate::Pin;")?;
writeln!(w)?;
@ -164,32 +167,41 @@ pub fn write_timers(mcu: &Mcu, w: &mut dyn Write) -> Result<(), io::Error> {
tc.registers().find(|r| r.name.starts_with(name))
.expect(&format!("could not find '{}' register", name))
};
let find_reg_suffix = |name: &'static str, suffix: &'static str| {
let find_reg_suffix_optional = |name: &'static str, suffix: &'static str| {
tc.registers().find(|r| r.name.starts_with(name) && r.name.ends_with(suffix))
};
let find_reg_suffix = |name: &'static str, suffix: &'static str| {
find_reg_suffix_optional(name, suffix)
.expect(&format!("could not find '{}' register", name))
};
let timer_number = find_reg("TIMSK").name.chars().last().unwrap()
.to_digit(10).unwrap();
writeln!(w, "/// 8-bit timer.")?;
writeln!(w, "pub struct {};", TYPE_NAME)?;
writeln!(w)?;
writeln!(w, "impl modules::Timer8 for {} {{", TYPE_NAME)?;
writeln!(w, " type CompareA = {};", find_reg_suffix("OCR", "A").name)?;
writeln!(w, " type CompareB = {};", find_reg_suffix("OCR", "B").name)?;
writeln!(w, " type Counter = {};", find_reg("TCNT").name)?;
writeln!(w, " type ControlA = {};", find_reg_suffix("TCCR", "A").name)?;
writeln!(w, " type ControlB = {};", find_reg_suffix("TCCR", "B").name)?;
writeln!(w, " type InterruptMask = {};", find_reg("TIMSK").name)?;
writeln!(w, " type InterruptFlag = {};", find_reg("TIFR").name)?;
writeln!(w, " const CS0: RegisterBits<Self::ControlB> = Self::ControlB::CS00;")?;
writeln!(w, " const CS1: RegisterBits<Self::ControlB> = Self::ControlB::CS01;")?;
writeln!(w, " const CS2: RegisterBits<Self::ControlB> = Self::ControlB::CS02;")?;
writeln!(w, " const WGM0: RegisterBits<Self::ControlA> = Self::ControlA::WGM00;")?;
writeln!(w, " const WGM1: RegisterBits<Self::ControlA> = Self::ControlA::WGM01;")?;
writeln!(w, " const WGM2: RegisterBits<Self::ControlB> = Self::ControlB::WGM020;")?;
writeln!(w, " const OCIEA: RegisterBits<Self::InterruptMask> = Self::InterruptMask::OCIE{}A;", timer_number)?;
writeln!(w, "}}")?;
// TODO: At the moment, we do not support 8 bit timers that don't have two compare
// registers.
let should_skip_timer = find_reg_suffix_optional("OCR", "B").is_none();
if !should_skip_timer {
writeln!(w, "/// 8-bit timer.")?;
writeln!(w, "pub struct {};", TYPE_NAME)?;
writeln!(w)?;
writeln!(w, "impl modules::Timer8 for {} {{", TYPE_NAME)?;
writeln!(w, " type CompareA = {};", find_reg_suffix("OCR", "A").name)?;
writeln!(w, " type CompareB = {};", find_reg_suffix("OCR", "B").name)?;
writeln!(w, " type Counter = {};", find_reg("TCNT").name)?;
writeln!(w, " type ControlA = {};", find_reg_suffix("TCCR", "A").name)?;
writeln!(w, " type ControlB = {};", find_reg_suffix("TCCR", "B").name)?;
writeln!(w, " type InterruptMask = {};", find_reg("TIMSK").name)?;
writeln!(w, " type InterruptFlag = {};", find_reg("TIFR").name)?;
writeln!(w, " const CS0: RegisterBits<Self::ControlB> = Self::ControlB::CS00;")?;
writeln!(w, " const CS1: RegisterBits<Self::ControlB> = Self::ControlB::CS01;")?;
writeln!(w, " const CS2: RegisterBits<Self::ControlB> = Self::ControlB::CS02;")?;
writeln!(w, " const WGM0: RegisterBits<Self::ControlA> = Self::ControlA::WGM00;")?;
writeln!(w, " const WGM1: RegisterBits<Self::ControlA> = Self::ControlA::WGM01;")?;
writeln!(w, " const WGM2: RegisterBits<Self::ControlB> = Self::ControlB::WGM020;")?;
writeln!(w, " const OCIEA: RegisterBits<Self::InterruptMask> = Self::InterruptMask::OCIE{}A;", timer_number)?;
writeln!(w, "}}")?;
}
}
if let Some(tc) = mcu.module("TC16") { // Timer/Counter, 16-bit.

View File

@ -4,7 +4,7 @@ mod gen;
use avr_mcu::*;
use std::fs::{self, File};
use std::{env, io};
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
@ -12,7 +12,106 @@ use std::path::{Path, PathBuf};
/// archicectures that are not AVR.
const DEFAULT_MCU_FOR_NON_AVR_DOCS: &'static str = "atmega328";
const DEFAULT_FREQUENCY_HZ_FOR_NON_AVR_DOCS: u64 = 16_000_000;
// Disable core generation for various devices as it does not work for them yet.
const DISABLE_FOR_DEVICES: &'static [&'static str] = &[
"ATmega256RFR2",
"AT90PWM81",
"at90can128",
"at90can32",
"at90can64",
"at90pwm216",
"at90pwm316",
"at90usb1286",
"at90usb1287",
"at90usb162",
"at90usb646",
"at90usb647",
"at90usb82",
"atmega1280",
"atmega1281",
"atmega1284",
"atmega1284p",
"atmega164a",
"atmega164p",
"atmega164pa",
"atmega165a",
"atmega165p",
"atmega165pa",
"atmega168pb",
"atmega169a",
"atmega169p",
"atmega169pa",
"atmega16m1",
"atmega2560",
"atmega2561",
"atmega324a",
"atmega324p",
"atmega324pa",
"atmega324pb",
"atmega325",
"atmega3250",
"atmega3250a",
"atmega3250p",
"atmega3250pa",
"atmega325a",
"atmega325p",
"atmega325pa",
"atmega328pb",
"atmega329",
"atmega3290",
"atmega3290a",
"atmega3290p",
"atmega3290pa",
"atmega329a",
"atmega329p",
"atmega329pa",
"atmega32c1",
"atmega32m1",
"atmega48pb",
"atmega640",
"atmega644",
"atmega644a",
"atmega644p",
"atmega644pa",
"atmega645",
"atmega6450",
"atmega6450a",
"atmega6450p",
"atmega645a",
"atmega645p",
"atmega649",
"atmega6490",
"atmega6490a",
"atmega6490p",
"atmega649a",
"atmega649p",
"atmega64c1",
"atmega64m1",
"atmega88pb",
"attiny10",
"attiny102",
"attiny104",
"attiny13",
"attiny13a",
"attiny167",
"attiny24",
"attiny24a",
"attiny4",
"attiny43u",
"attiny44",
"attiny44a",
"attiny5",
"attiny80",
"attiny828",
"attiny84",
"attiny840",
"attiny84a",
"attiny87",
"attiny9",
"at90pwm1",
"at90pwm2b",
"at90pwm3b",
];
fn base_output_path() -> PathBuf {
match std::env::args().skip(1).next() {
@ -46,7 +145,46 @@ fn main() {
};
let current_mcu_name = current_mcu.device.name.clone();
generate_cores(&[current_mcu]).unwrap();
let microcontrollers = avr_mcu::microcontrollers();
let (count_total, mut cores_successful, mut cores_failed) = (microcontrollers.len(), Vec::new(), Vec::new());
for (i, mcu) in microcontrollers.iter().enumerate() {
if DISABLE_FOR_DEVICES.iter().any(|d| mcu.device.name == *d || core_module_name(mcu) == *d) {
println!("skipping generation of core for '{}'", mcu.device.name);
continue;
}
let result = std::panic::catch_unwind(|| {
println!("generating core for '{}' ({} of {})", mcu.device.name, i + 1, count_total);
generate_cores(&[mcu.clone()]).unwrap();
});
match result {
Ok(..) => {
println!("successfully generated core for '{}'", mcu.device.name);
cores_successful.push(mcu);
},
Err(e) => {
delete_core_module(mcu).unwrap(); // Don't leave around broken core files.
let error_message = if let Some(e) = e.downcast_ref::<&dyn std::error::Error>() {
format!("{}", e)
} else {
String::new()
};
eprintln!("failed to generate core for '{}', skipping: {}\n", mcu.device.name, error_message);
cores_failed.push(mcu);
},
}
}
println!("generating 'src/cores/mod.rs' for the {} successfully generated cores", cores_successful.len());
generate_cores_mod_rs(&cores_successful[..]).expect("failed to generates src/cores/mod.rs");
println!("statistics:");
println!(" total successful: {}", cores_successful.len());
println!(" total failed: {}", cores_failed.len());
println!("cargo:rustc-cfg=avr_mcu_{}", normalize_device_name(&current_mcu_name));
}
@ -55,7 +193,8 @@ fn generate_cores(mcus: &[Mcu]) -> Result<(), io::Error> {
for mcu in mcus {
generate_core_module(mcu).expect("failed to generate mcu core");
}
generate_cores_mod_rs(mcus)
Ok(())
}
fn generate_core_module(mcu: &Mcu) -> Result<(), io::Error> {
@ -64,18 +203,25 @@ fn generate_core_module(mcu: &Mcu) -> Result<(), io::Error> {
write_core_module(mcu, &mut file)
}
fn generate_cores_mod_rs(mcus: &[Mcu]) -> Result<(), io::Error> {
fn delete_core_module(mcu: &Mcu) -> Result<(), io::Error> {
let path = cores_path().join(format!("{}.rs", core_module_name(mcu)));
std::fs::remove_file(&path)
}
fn generate_cores_mod_rs(mcus: &[&Mcu]) -> Result<(), io::Error> {
let path = cores_path().join("mod.rs");
let mut w = File::create(&path)?;
writeln!(w, "//! The primary module containing microcontroller-specific core definitions")?;
writeln!(w)?;
for mcu in mcus {
let module_name = core_module_name(mcu);
writeln!(w, "/// The {}.", mcu.device.name)?;
writeln!(w, "pub mod {};", module_name)?;
writeln!(w, "#[cfg(avr_mcu_{})]", module_name)?;
writeln!(w, "pub use self::{} as current;", module_name)?;
writeln!(w, "#[cfg(avr_mcu_{})] pub use self::{} as current;", module_name, module_name)?;
writeln!(w)?;
}
writeln!(w)
}