use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AvrRegister {
R0,
R1,
R2,
R3,
R4,
R5,
R6,
R7,
R8,
R9,
R10,
R11,
R12,
R13,
R14,
R15,
R16,
R17,
R18,
R19,
R20,
R21,
R22,
R23,
R24,
R25,
R26,
R27,
R28,
R29,
R30,
R31,
XL, XH, YL, YH, ZL, ZH, SPL, SPH, SREG, PC, }
impl AvrRegister {
pub fn index(&self) -> u8 {
match self {
AvrRegister::R0 => 0,
AvrRegister::R1 => 1,
AvrRegister::R2 => 2,
AvrRegister::R3 => 3,
AvrRegister::R4 => 4,
AvrRegister::R5 => 5,
AvrRegister::R6 => 6,
AvrRegister::R7 => 7,
AvrRegister::R8 => 8,
AvrRegister::R9 => 9,
AvrRegister::R10 => 10,
AvrRegister::R11 => 11,
AvrRegister::R12 => 12,
AvrRegister::R13 => 13,
AvrRegister::R14 => 14,
AvrRegister::R15 => 15,
AvrRegister::R16 => 16,
AvrRegister::R17 => 17,
AvrRegister::R18 => 18,
AvrRegister::R19 => 19,
AvrRegister::R20 => 20,
AvrRegister::R21 => 21,
AvrRegister::R22 => 22,
AvrRegister::R23 => 23,
AvrRegister::R24 => 24,
AvrRegister::R25 => 25,
AvrRegister::R26 => 26,
AvrRegister::XL => 26,
AvrRegister::XH => 27,
AvrRegister::R27 => 27,
AvrRegister::R28 => 28,
AvrRegister::R29 => 29,
AvrRegister::R30 => 30,
AvrRegister::R31 => 31,
AvrRegister::YL => 28,
AvrRegister::YH => 29,
AvrRegister::ZL => 30,
AvrRegister::ZH => 31,
_ => 0xFF,
}
}
pub fn name(&self) -> &'static str {
match self {
AvrRegister::R0 => "r0",
AvrRegister::R1 => "r1",
AvrRegister::R2 => "r2",
AvrRegister::R3 => "r3",
AvrRegister::R4 => "r4",
AvrRegister::R5 => "r5",
AvrRegister::R6 => "r6",
AvrRegister::R7 => "r7",
AvrRegister::R8 => "r8",
AvrRegister::R9 => "r9",
AvrRegister::R10 => "r10",
AvrRegister::R11 => "r11",
AvrRegister::R12 => "r12",
AvrRegister::R13 => "r13",
AvrRegister::R14 => "r14",
AvrRegister::R15 => "r15",
AvrRegister::R16 => "r16",
AvrRegister::R17 => "r17",
AvrRegister::R18 => "r18",
AvrRegister::R19 => "r19",
AvrRegister::R20 => "r20",
AvrRegister::R21 => "r21",
AvrRegister::R22 => "r22",
AvrRegister::R23 => "r23",
AvrRegister::R24 => "r24",
AvrRegister::R25 => "r25",
AvrRegister::R26 => "r26",
AvrRegister::R27 => "r27",
AvrRegister::R28 => "r28",
AvrRegister::R29 => "r29",
AvrRegister::R30 => "r30",
AvrRegister::R31 => "r31",
AvrRegister::XL => "r26",
AvrRegister::XH => "r27",
AvrRegister::YL => "r28",
AvrRegister::YH => "r29",
AvrRegister::ZL => "r30",
AvrRegister::ZH => "r31",
AvrRegister::SPL => "SPL",
AvrRegister::SPH => "SPH",
AvrRegister::SREG => "SREG",
AvrRegister::PC => "PC",
}
}
pub fn is_gpr(&self) -> bool {
matches!(
self,
AvrRegister::R0
| AvrRegister::R1
| AvrRegister::R2
| AvrRegister::R3
| AvrRegister::R4
| AvrRegister::R5
| AvrRegister::R6
| AvrRegister::R7
| AvrRegister::R8
| AvrRegister::R9
| AvrRegister::R10
| AvrRegister::R11
| AvrRegister::R12
| AvrRegister::R13
| AvrRegister::R14
| AvrRegister::R15
| AvrRegister::R16
| AvrRegister::R17
| AvrRegister::R18
| AvrRegister::R19
| AvrRegister::R20
| AvrRegister::R21
| AvrRegister::R22
| AvrRegister::R23
| AvrRegister::R24
| AvrRegister::R25
| AvrRegister::R26
| AvrRegister::R27
| AvrRegister::R28
| AvrRegister::R29
| AvrRegister::R30
| AvrRegister::R31
)
}
}
pub struct AvrCallingConvention {
pub arg_regs: Vec<AvrRegister>,
pub ret_regs: Vec<AvrRegister>,
pub callee_saved: Vec<AvrRegister>,
pub caller_saved: Vec<AvrRegister>,
pub sp: AvrRegister,
pub fp: AvrRegister,
}
impl AvrCallingConvention {
pub fn new() -> Self {
AvrCallingConvention {
arg_regs: vec![
AvrRegister::R24,
AvrRegister::R25,
AvrRegister::R22,
AvrRegister::R23,
AvrRegister::R20,
AvrRegister::R21,
AvrRegister::R18,
AvrRegister::R19,
],
ret_regs: vec![AvrRegister::R24, AvrRegister::R25],
callee_saved: vec![
AvrRegister::R2,
AvrRegister::R3,
AvrRegister::R4,
AvrRegister::R5,
AvrRegister::R6,
AvrRegister::R7,
AvrRegister::R8,
AvrRegister::R9,
AvrRegister::R10,
AvrRegister::R11,
AvrRegister::R12,
AvrRegister::R13,
AvrRegister::R14,
AvrRegister::R15,
AvrRegister::R16,
AvrRegister::R17,
AvrRegister::R28,
AvrRegister::R29,
],
caller_saved: vec![
AvrRegister::R0,
AvrRegister::R18,
AvrRegister::R19,
AvrRegister::R20,
AvrRegister::R21,
AvrRegister::R22,
AvrRegister::R23,
AvrRegister::R24,
AvrRegister::R25,
AvrRegister::R26,
AvrRegister::R27,
AvrRegister::R30,
AvrRegister::R31,
],
sp: AvrRegister::SPL,
fp: AvrRegister::R29, }
}
}
pub struct AvrTargetMachine {
pub cpu: String,
pub flash_size: u32,
pub sram_size: u32,
pub eeprom_size: u32,
pub frequency_hz: u64,
pub calling_conv: AvrCallingConvention,
}
impl AvrTargetMachine {
pub fn new(cpu: &str) -> Self {
let (flash, sram, eeprom) = match cpu {
"atmega328p" => (32768, 2048, 1024),
"atmega2560" => (262144, 8192, 4096),
"attiny85" => (8192, 512, 512),
"atmega32u4" => (32768, 2560, 1024),
_ => (32768, 2048, 1024), };
AvrTargetMachine {
cpu: cpu.to_string(),
flash_size: flash,
sram_size: sram,
eeprom_size: eeprom,
frequency_hz: 16_000_000,
calling_conv: AvrCallingConvention::new(),
}
}
pub fn default_target() -> Self {
Self::new("atmega328p")
}
pub fn get_target_triple(&self) -> String {
"avr-none-elf".to_string()
}
pub fn get_data_layout(&self) -> String {
"e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string()
}
pub fn get_pointer_size(&self) -> u32 {
16
}
pub fn get_register_width(&self) -> u32 {
8
}
pub fn get_cpu(&self) -> &str {
&self.cpu
}
pub fn get_flash_size(&self) -> u32 {
self.flash_size
}
pub fn get_sram_size(&self) -> u32 {
self.sram_size
}
pub fn has_hardware_mul(&self) -> bool {
true
}
pub fn has_enhanced_core(&self) -> bool {
self.cpu != "attiny85"
}
pub fn get_stack_alignment(&self) -> u32 {
1
}
pub fn get_min_stack_size(&self) -> u32 {
match self.sram_size {
0..=512 => 64,
513..=2048 => 128,
_ => 256,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_avr_register_index() {
assert_eq!(AvrRegister::R0.index(), 0);
assert_eq!(AvrRegister::R16.index(), 16);
assert_eq!(AvrRegister::R31.index(), 31);
}
#[test]
fn test_avr_register_aliases() {
assert_eq!(AvrRegister::XL.index(), 26);
assert_eq!(AvrRegister::XH.index(), 27);
assert_eq!(AvrRegister::YL.index(), 28);
assert_eq!(AvrRegister::YH.index(), 29);
assert_eq!(AvrRegister::ZL.index(), 30);
assert_eq!(AvrRegister::ZH.index(), 31);
}
#[test]
fn test_avr_register_name() {
assert_eq!(AvrRegister::R0.name(), "r0");
assert_eq!(AvrRegister::R16.name(), "r16");
assert_eq!(AvrRegister::SREG.name(), "SREG");
}
#[test]
fn test_avr_register_is_gpr() {
assert!(AvrRegister::R0.is_gpr());
assert!(AvrRegister::R31.is_gpr());
assert!(!AvrRegister::SREG.is_gpr());
assert!(!AvrRegister::PC.is_gpr());
}
#[test]
fn test_calling_convention_arg_regs() {
let cc = AvrCallingConvention::new();
assert_eq!(cc.arg_regs.len(), 8);
assert_eq!(cc.arg_regs[0], AvrRegister::R24);
}
#[test]
fn test_calling_convention_ret_regs() {
let cc = AvrCallingConvention::new();
assert_eq!(cc.ret_regs, vec![AvrRegister::R24, AvrRegister::R25]);
}
#[test]
fn test_calling_convention_callee_saved() {
let cc = AvrCallingConvention::new();
assert!(cc.callee_saved.contains(&AvrRegister::R2));
assert!(cc.callee_saved.contains(&AvrRegister::R17));
assert!(!cc.callee_saved.contains(&AvrRegister::R0));
}
#[test]
fn test_atmega328p_config() {
let tm = AvrTargetMachine::new("atmega328p");
assert_eq!(tm.flash_size, 32768);
assert_eq!(tm.sram_size, 2048);
assert_eq!(tm.eeprom_size, 1024);
assert_eq!(tm.frequency_hz, 16_000_000);
}
#[test]
fn test_attiny85_config() {
let tm = AvrTargetMachine::new("attiny85");
assert_eq!(tm.sram_size, 512);
assert_eq!(tm.eeprom_size, 512);
}
#[test]
fn test_target_triple() {
let tm = AvrTargetMachine::default_target();
assert_eq!(tm.get_target_triple(), "avr-none-elf");
}
#[test]
fn test_data_layout() {
let tm = AvrTargetMachine::default_target();
assert!(tm.get_data_layout().contains("P1"));
}
#[test]
fn test_has_hardware_mul() {
let tm = AvrTargetMachine::default_target();
assert!(tm.has_hardware_mul());
}
#[test]
fn test_has_enhanced_core() {
let tm = AvrTargetMachine::new("atmega328p");
assert!(tm.has_enhanced_core());
let tiny = AvrTargetMachine::new("attiny85");
assert!(!tiny.has_enhanced_core());
}
#[test]
fn test_pointer_size() {
let tm = AvrTargetMachine::default_target();
assert_eq!(tm.get_pointer_size(), 16);
}
#[test]
fn test_register_width() {
let tm = AvrTargetMachine::default_target();
assert_eq!(tm.get_register_width(), 8);
}
#[test]
fn test_min_stack_size() {
let tiny = AvrTargetMachine::new("attiny85");
assert_eq!(tiny.get_min_stack_size(), 64);
let mega = AvrTargetMachine::new("atmega328p");
assert_eq!(mega.get_min_stack_size(), 128);
let large = AvrTargetMachine::new("atmega2560");
assert_eq!(large.get_min_stack_size(), 256);
}
#[test]
fn test_default_cpu_is_atmega328p() {
let tm = AvrTargetMachine::default_target();
assert_eq!(tm.cpu, "atmega328p");
}
}