From d6ab7fafd27be7db6886e30682583f173d194772 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 28 Jan 2021 06:05:26 +1300 Subject: [PATCH] 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. --- core_generator/src/gen.rs | 52 +++++++----- core_generator/src/main.rs | 160 +++++++++++++++++++++++++++++++++++-- 2 files changed, 185 insertions(+), 27 deletions(-) diff --git a/core_generator/src/gen.rs b/core_generator/src/gen.rs index e2e37a2..18d3904 100644 --- a/core_generator/src/gen.rs +++ b/core_generator/src/gen.rs @@ -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::CS00;")?; - writeln!(w, " const CS1: RegisterBits = Self::ControlB::CS01;")?; - writeln!(w, " const CS2: RegisterBits = Self::ControlB::CS02;")?; - writeln!(w, " const WGM0: RegisterBits = Self::ControlA::WGM00;")?; - writeln!(w, " const WGM1: RegisterBits = Self::ControlA::WGM01;")?; - writeln!(w, " const WGM2: RegisterBits = Self::ControlB::WGM020;")?; - writeln!(w, " const OCIEA: RegisterBits = 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::CS00;")?; + writeln!(w, " const CS1: RegisterBits = Self::ControlB::CS01;")?; + writeln!(w, " const CS2: RegisterBits = Self::ControlB::CS02;")?; + writeln!(w, " const WGM0: RegisterBits = Self::ControlA::WGM00;")?; + writeln!(w, " const WGM1: RegisterBits = Self::ControlA::WGM01;")?; + writeln!(w, " const WGM2: RegisterBits = Self::ControlB::WGM020;")?; + writeln!(w, " const OCIEA: RegisterBits = Self::InterruptMask::OCIE{}A;", timer_number)?; + writeln!(w, "}}")?; + } } if let Some(tc) = mcu.module("TC16") { // Timer/Counter, 16-bit. diff --git a/core_generator/src/main.rs b/core_generator/src/main.rs index 6f043c0..7360949 100644 --- a/core_generator/src/main.rs +++ b/core_generator/src/main.rs @@ -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(¤t_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) }