Skip to content

Commit 7890999

Browse files
authored
Msp430 fixes (#62)
* Improve MSP430 support. - Use the correct number of registers. - Add support for CPUX variant (20-bit registers) * Fix tests and cleanup comments * Use fixed RegId type for msp430
1 parent 5c702d0 commit 7890999

File tree

3 files changed

+87
-47
lines changed

3 files changed

+87
-47
lines changed

gdbstub_arch/src/msp430/mod.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
11
//! Implementations for the TI-MSP430 family of MCUs.
22
33
use gdbstub::arch::Arch;
4-
use gdbstub::arch::RegId;
54

65
pub mod reg;
76

87
/// Implements `Arch` for standard 16-bit TI-MSP430 MCUs.
9-
///
10-
/// Check out the [module level docs](gdbstub::arch#whats-with-regidimpl) for
11-
/// more info about the `RegIdImpl` type parameter.
12-
pub enum Msp430<RegIdImpl: RegId = reg::id::Msp430RegId> {
13-
#[doc(hidden)]
14-
_Marker(core::marker::PhantomData<RegIdImpl>),
15-
}
8+
pub struct Msp430 {}
169

17-
impl<RegIdImpl: RegId> Arch for Msp430<RegIdImpl> {
10+
impl Arch for Msp430 {
1811
type Usize = u16;
19-
type Registers = reg::Msp430Regs;
20-
type RegId = RegIdImpl;
12+
type Registers = reg::Msp430Regs<u16>;
13+
type RegId = reg::id::Msp430RegId<u16>;
2114
type BreakpointKind = usize;
2215

2316
fn target_description_xml() -> Option<&'static str> {
2417
Some(r#"<target version="1.0"><architecture>msp430</architecture></target>"#)
2518
}
2619
}
20+
21+
/// Implements `Arch` for 20-bit TI-MSP430 MCUs (CPUX).
22+
pub struct Msp430X {}
23+
24+
impl Arch for Msp430X {
25+
type Usize = u32;
26+
type Registers = reg::Msp430Regs<u32>;
27+
type RegId = reg::id::Msp430RegId<u32>;
28+
type BreakpointKind = usize;
29+
30+
fn target_description_xml() -> Option<&'static str> {
31+
Some(r#"<target version="1.0"><architecture>msp430x</architecture></target>"#)
32+
}
33+
}

gdbstub_arch/src/msp430/reg/id.rs

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use gdbstub::arch::RegId;
66
/// The best file to reference is [msp430-tdep.c](https://github.com/bminor/binutils-gdb/blob/master/gdb/msp430-tdep.c).
77
#[derive(Debug, Clone, Copy)]
88
#[non_exhaustive]
9-
pub enum Msp430RegId {
9+
pub enum Msp430RegId<U> {
1010
/// Program Counter (R0)
1111
Pc,
1212
/// Stack Pointer (R1)
@@ -17,19 +17,33 @@ pub enum Msp430RegId {
1717
Cg,
1818
/// General Purpose Registers (R4-R15)
1919
Gpr(u8),
20+
#[doc(hidden)]
21+
_Size(U),
2022
}
2123

22-
impl RegId for Msp430RegId {
24+
fn from_raw_id<U>(id: usize) -> Option<(Msp430RegId<U>, usize)> {
25+
let reg = match id {
26+
0 => Msp430RegId::Pc,
27+
1 => Msp430RegId::Sp,
28+
2 => Msp430RegId::Sr,
29+
3 => Msp430RegId::Cg,
30+
4..=15 => Msp430RegId::Gpr((id as u8) - 4),
31+
_ => return None,
32+
};
33+
34+
let ptrsize = core::mem::size_of::<U>();
35+
Some((reg, ptrsize))
36+
}
37+
38+
impl RegId for Msp430RegId<u16> {
2339
fn from_raw_id(id: usize) -> Option<(Self, usize)> {
24-
let reg = match id {
25-
0 => Self::Pc,
26-
1 => Self::Sp,
27-
2 => Self::Sr,
28-
3 => Self::Cg,
29-
4..=15 => Self::Gpr((id as u8) - 4),
30-
_ => return None,
31-
};
32-
Some((reg, 2))
40+
from_raw_id::<u16>(id)
41+
}
42+
}
43+
44+
impl RegId for Msp430RegId<u32> {
45+
fn from_raw_id(id: usize) -> Option<(Self, usize)> {
46+
from_raw_id::<u32>(id)
3347
}
3448
}
3549

@@ -51,7 +65,7 @@ mod tests {
5165

5266
// The `Msp430Regs` implementation does not increment the size for
5367
// the CG register since it will always be the constant zero.
54-
serialized_data_len += 4;
68+
serialized_data_len += RId::from_raw_id(3).unwrap().1;
5569

5670
// Accumulate register sizes returned by `from_raw_id`.
5771
let mut i = 0;
@@ -66,6 +80,11 @@ mod tests {
6680

6781
#[test]
6882
fn test_msp430() {
69-
test::<crate::msp430::reg::Msp430Regs, crate::msp430::reg::id::Msp430RegId>()
83+
test::<crate::msp430::reg::Msp430Regs<u16>, crate::msp430::reg::id::Msp430RegId<u16>>()
84+
}
85+
86+
#[test]
87+
fn test_msp430x() {
88+
test::<crate::msp430::reg::Msp430Regs<u32>, crate::msp430::reg::id::Msp430RegId<u32>>()
7089
}
7190
}

gdbstub_arch/src/msp430/reg/msp430.rs

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,74 @@
1+
use num_traits::PrimInt;
2+
13
use gdbstub::arch::Registers;
4+
use gdbstub::internal::LeBytes;
25

3-
/// 16-bit TI-MSP430 registers.
6+
/// TI-MSP430 registers.
7+
///
8+
/// The register width is set based on the `<U>` type. For 16-bit MSP430 CPUs
9+
/// this should be `u16` and for 20-bit MSP430 CPUs (CPUX) this should be `u32`.
410
#[derive(Debug, Default, Clone, Eq, PartialEq)]
5-
pub struct Msp430Regs {
11+
pub struct Msp430Regs<U> {
612
/// Program Counter (R0)
7-
pub pc: u16,
13+
pub pc: U,
814
/// Stack Pointer (R1)
9-
pub sp: u16,
15+
pub sp: U,
1016
/// Status Register (R2)
11-
pub sr: u16,
17+
pub sr: U,
1218
/// General Purpose Registers (R4-R15)
13-
pub r: [u16; 11],
19+
pub r: [U; 12],
1420
}
1521

16-
impl Registers for Msp430Regs {
17-
type ProgramCounter = u16;
22+
impl<U> Registers for Msp430Regs<U>
23+
where
24+
U: PrimInt + LeBytes + Default + core::fmt::Debug,
25+
{
26+
type ProgramCounter = U;
1827

1928
fn pc(&self) -> Self::ProgramCounter {
2029
self.pc
2130
}
2231

2332
fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) {
24-
macro_rules! write_bytes {
25-
($bytes:expr) => {
26-
for b in $bytes {
27-
write_byte(Some(*b))
33+
macro_rules! write_le_bytes {
34+
($value:expr) => {
35+
let mut buf = [0; 4];
36+
// infallible (register size a maximum of 32-bits)
37+
let len = $value.to_le_bytes(&mut buf).unwrap();
38+
let buf = &buf[..len];
39+
for b in buf {
40+
write_byte(Some(*b));
2841
}
2942
};
3043
}
3144

32-
write_bytes!(&self.pc.to_le_bytes());
33-
write_bytes!(&self.sp.to_le_bytes());
34-
write_bytes!(&self.sr.to_le_bytes());
35-
(0..4).for_each(|_| write_byte(None)); // Constant Generator (CG/R3)
45+
write_le_bytes!(&self.pc);
46+
write_le_bytes!(&self.sp);
47+
write_le_bytes!(&self.sr);
48+
(0..core::mem::size_of::<U>()).for_each(|_| write_byte(None)); // Constant Generator (CG/R3)
3649
for reg in self.r.iter() {
37-
write_bytes!(&reg.to_le_bytes());
50+
write_le_bytes!(&reg);
3851
}
3952
}
4053

4154
fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> {
42-
// ensure bytes.chunks_exact(2) won't panic
43-
if bytes.len() % 2 != 0 {
55+
let ptrsize = core::mem::size_of::<U>();
56+
57+
// Ensure bytes contains enough data for all 16 registers
58+
if bytes.len() < ptrsize * 16 {
4459
return Err(());
4560
}
4661

47-
use core::convert::TryInto;
4862
let mut regs = bytes
49-
.chunks_exact(2)
50-
.map(|c| u16::from_le_bytes(c.try_into().unwrap()));
63+
.chunks_exact(ptrsize)
64+
.map(|c| U::from_le_bytes(c).unwrap());
5165

5266
self.pc = regs.next().ok_or(())?;
5367
self.sp = regs.next().ok_or(())?;
5468
self.sr = regs.next().ok_or(())?;
5569

5670
// Constant Generator (CG/R3) should always be 0
57-
if regs.next().ok_or(())? != 0 {
71+
if regs.next().ok_or(())? != U::zero() {
5872
return Err(());
5973
}
6074

0 commit comments

Comments
 (0)