pub const R0: u16 = 8000; pub const R1: u16 = 8001; pub const R2: u16 = 8002; pub const R3: u16 = 8003; pub const R4: u16 = 8004;
pub const R5: u16 = 8005;
pub const R6: u16 = 8006;
pub const R7: u16 = 8007;
pub const R8: u16 = 8008;
pub const R9: u16 = 8009;
pub const R10: u16 = 8010;
pub const R11: u16 = 8011;
pub const R12: u16 = 8012;
pub const R13: u16 = 8013;
pub const R14: u16 = 8014;
pub const R15: u16 = 8015;
pub const PC: u16 = R0;
pub const SP: u16 = R1;
pub const SR: u16 = R2;
pub const CG1: u16 = R2;
pub const CG2: u16 = R3;
pub const MSP430_GPR_COUNT: usize = 16;
pub const MSP430_MAX_REG_ID: u16 = 8015;
pub const MSP430_GPR_BASE: u16 = 8000;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Msp430RegClass {
GPR16,
}
impl std::fmt::Display for Msp430RegClass {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Msp430RegClass::GPR16 => write!(f, "GPR16"),
}
}
}
pub struct Msp430RegisterInfo;
impl Msp430RegisterInfo {
pub fn get_asm_name(reg_id: u16) -> String {
match reg_id {
R0 => "PC".into(),
R1 => "SP".into(),
R2 => "SR".into(),
R3 => "CG2".into(),
R4 => "R4".into(),
R5 => "R5".into(),
R6 => "R6".into(),
R7 => "R7".into(),
R8 => "R8".into(),
R9 => "R9".into(),
R10 => "R10".into(),
R11 => "R11".into(),
R12 => "R12".into(),
R13 => "R13".into(),
R14 => "R14".into(),
R15 => "R15".into(),
_ => format!("R{}", reg_id - MSP430_GPR_BASE),
}
}
pub fn get_abi_name(reg_id: u16) -> String {
Self::get_asm_name(reg_id)
}
pub fn get_reg_class(_reg_id: u16) -> Msp430RegClass {
Msp430RegClass::GPR16
}
pub fn get_reg_width(_reg_id: u16, _is_64bit: bool) -> u32 {
16
}
pub fn get_dwarf_num(reg_id: u16) -> i32 {
match reg_id {
_ if reg_id >= R0 && reg_id <= R15 => (reg_id - R0) as i32,
_ => -1,
}
}
pub fn is_callee_saved(reg_id: u16) -> bool {
matches!(reg_id, R4 | R5 | R6 | R7 | R8 | R9 | R10 | R11 | R1)
}
pub fn is_caller_saved(reg_id: u16) -> bool {
matches!(reg_id, R12 | R13 | R14 | R15)
}
pub fn is_reserved(reg_id: u16) -> bool {
reg_id == R0 || reg_id == R2 || reg_id == R3
}
pub fn get_allocatable_gprs() -> Vec<u16> {
let mut regs = Vec::new();
for i in 0..16 {
let r = MSP430_GPR_BASE + i as u16;
if !Self::is_reserved(r) {
regs.push(r);
}
}
regs
}
pub fn get_argument_regs() -> Vec<u16> {
vec![R12, R13, R14, R15]
}
pub fn get_return_regs() -> Vec<u16> {
vec![R12, R13]
}
pub fn get_frame_pointer_reg() -> u16 {
R4
}
pub fn get_stack_pointer_reg() -> u16 {
SP
}
pub fn is_gpr(reg_id: u16) -> bool {
reg_id >= MSP430_GPR_BASE && reg_id < MSP430_GPR_BASE + 16
}
pub fn get_reg_index(reg_id: u16) -> u8 {
if reg_id >= MSP430_GPR_BASE && reg_id < MSP430_GPR_BASE + 16 {
(reg_id - MSP430_GPR_BASE) as u8
} else {
0
}
}
pub fn can_be_base_reg(reg_id: u16) -> bool {
Self::is_gpr(reg_id) && reg_id != R3
}
pub fn get_caller_saved_gprs() -> Vec<u16> {
vec![R12, R13, R14, R15]
}
pub fn get_callee_saved_gprs() -> Vec<u16> {
vec![R4, R5, R6, R7, R8, R9, R10, R11]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_register_count_constants() {
assert_eq!(MSP430_GPR_COUNT, 16);
assert_eq!(MSP430_MAX_REG_ID, 8015);
}
#[test]
fn test_register_ids_unique() {
let mut seen = std::collections::HashSet::new();
for i in 0..16 {
assert!(seen.insert(R0 + i));
}
}
#[test]
fn test_abi_names() {
assert_eq!(Msp430RegisterInfo::get_asm_name(R0), "PC");
assert_eq!(Msp430RegisterInfo::get_asm_name(R1), "SP");
assert_eq!(Msp430RegisterInfo::get_asm_name(R2), "SR");
assert_eq!(Msp430RegisterInfo::get_asm_name(R4), "R4");
assert_eq!(Msp430RegisterInfo::get_asm_name(R15), "R15");
}
#[test]
fn test_get_reg_width() {
assert_eq!(Msp430RegisterInfo::get_reg_width(R0, false), 16);
assert_eq!(Msp430RegisterInfo::get_reg_width(R15, true), 16);
}
#[test]
fn test_is_callee_saved() {
assert!(Msp430RegisterInfo::is_callee_saved(R4));
assert!(Msp430RegisterInfo::is_callee_saved(R11));
assert!(Msp430RegisterInfo::is_callee_saved(R1));
assert!(!Msp430RegisterInfo::is_callee_saved(R12));
assert!(!Msp430RegisterInfo::is_callee_saved(R15));
}
#[test]
fn test_is_reserved() {
assert!(Msp430RegisterInfo::is_reserved(R0));
assert!(Msp430RegisterInfo::is_reserved(R2));
assert!(Msp430RegisterInfo::is_reserved(R3));
assert!(!Msp430RegisterInfo::is_reserved(R4));
assert!(!Msp430RegisterInfo::is_reserved(R15));
}
#[test]
fn test_get_argument_regs() {
assert_eq!(
Msp430RegisterInfo::get_argument_regs(),
vec![R12, R13, R14, R15]
);
}
#[test]
fn test_get_return_regs() {
assert_eq!(Msp430RegisterInfo::get_return_regs(), vec![R12, R13]);
}
#[test]
fn test_get_reg_index() {
assert_eq!(Msp430RegisterInfo::get_reg_index(R0), 0);
assert_eq!(Msp430RegisterInfo::get_reg_index(R15), 15);
}
#[test]
fn test_is_gpr() {
assert!(Msp430RegisterInfo::is_gpr(R0));
assert!(Msp430RegisterInfo::is_gpr(R15));
assert!(!Msp430RegisterInfo::is_gpr(9000));
}
}