Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Msp430 fixes #62

Merged
merged 3 commits into from
Jul 27, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions gdbstub_arch/src/msp430/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,38 @@ pub mod reg;
///
/// Check out the [module level docs](gdbstub::arch#whats-with-regidimpl) for
/// more info about the `RegIdImpl` type parameter.
pub enum Msp430<RegIdImpl: RegId = reg::id::Msp430RegId> {
pub enum Msp430<RegIdImpl: RegId = reg::id::Msp430RegId<u16>> {
daniel5151 marked this conversation as resolved.
Show resolved Hide resolved
#[doc(hidden)]
_Marker(core::marker::PhantomData<RegIdImpl>),
}

impl<RegIdImpl: RegId> Arch for Msp430<RegIdImpl> {
type Usize = u16;
type Registers = reg::Msp430Regs;
type Registers = reg::Msp430Regs<u16>;
type RegId = RegIdImpl;
type BreakpointKind = usize;

fn target_description_xml() -> Option<&'static str> {
Some(r#"<target version="1.0"><architecture>msp430</architecture></target>"#)
}
}

/// Implements `Arch` for 20-bit TI-MSP430 MCUs (CPUX).
///
/// Check out the [module level docs](gdbstub::arch#whats-with-regidimpl) for
/// more info about the `RegIdImpl` type parameter.
pub enum Msp430X<RegIdImpl: RegId = reg::id::Msp430RegId<u32>> {
daniel5151 marked this conversation as resolved.
Show resolved Hide resolved
#[doc(hidden)]
_Marker(core::marker::PhantomData<RegIdImpl>),
}

impl<RegIdImpl: RegId> Arch for Msp430X<RegIdImpl> {
type Usize = u32;
type Registers = reg::Msp430Regs<u32>;
type RegId = RegIdImpl;
type BreakpointKind = usize;

fn target_description_xml() -> Option<&'static str> {
Some(r#"<target version="1.0"><architecture>msp430x</architecture></target>"#)
}
}
45 changes: 32 additions & 13 deletions gdbstub_arch/src/msp430/reg/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use gdbstub::arch::RegId;
/// The best file to reference is [msp430-tdep.c](https://github.com/bminor/binutils-gdb/blob/master/gdb/msp430-tdep.c).
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub enum Msp430RegId {
pub enum Msp430RegId<U> {
/// Program Counter (R0)
Pc,
/// Stack Pointer (R1)
Expand All @@ -17,19 +17,33 @@ pub enum Msp430RegId {
Cg,
/// General Purpose Registers (R4-R15)
Gpr(u8),
#[doc(hidden)]
_Size(U),
}

impl RegId for Msp430RegId {
fn from_raw_id<U>(id: usize) -> Option<(Msp430RegId<U>, usize)> {
let reg = match id {
0 => Msp430RegId::Pc,
1 => Msp430RegId::Sp,
2 => Msp430RegId::Sr,
3 => Msp430RegId::Cg,
4..=15 => Msp430RegId::Gpr((id as u8) - 4),
_ => return None,
};

let ptrsize = core::mem::size_of::<U>();
Some((reg, ptrsize))
}

impl RegId for Msp430RegId<u16> {
fn from_raw_id(id: usize) -> Option<(Self, usize)> {
let reg = match id {
0 => Self::Pc,
1 => Self::Sp,
2 => Self::Sr,
3 => Self::Cg,
4..=15 => Self::Gpr((id as u8) - 4),
_ => return None,
};
Some((reg, 2))
from_raw_id::<u16>(id)
}
}

impl RegId for Msp430RegId<u32> {
fn from_raw_id(id: usize) -> Option<(Self, usize)> {
from_raw_id::<u32>(id)
}
}

Expand All @@ -51,7 +65,7 @@ mod tests {

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

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

#[test]
fn test_msp430() {
test::<crate::msp430::reg::Msp430Regs, crate::msp430::reg::id::Msp430RegId>()
test::<crate::msp430::reg::Msp430Regs<u16>, crate::msp430::reg::id::Msp430RegId<u16>>()
}

#[test]
fn test_msp430x() {
test::<crate::msp430::reg::Msp430Regs<u32>, crate::msp430::reg::id::Msp430RegId<u32>>()
}
}
60 changes: 37 additions & 23 deletions gdbstub_arch/src/msp430/reg/msp430.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,74 @@
use num_traits::PrimInt;

use gdbstub::arch::Registers;
use gdbstub::internal::LeBytes;

/// 16-bit TI-MSP430 registers.
/// TI-MSP430 registers.
///
/// The register width is set based on the `<U>` type. For 16-bit MSP430 CPUs
/// this should be `u16` and for 20-bit MSP430 CPUs (CPUX) this should be `u32`.
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct Msp430Regs {
pub struct Msp430Regs<U> {
/// Program Counter (R0)
pub pc: u16,
pub pc: U,
/// Stack Pointer (R1)
pub sp: u16,
pub sp: U,
/// Status Register (R2)
pub sr: u16,
pub sr: U,
/// General Purpose Registers (R4-R15)
pub r: [u16; 11],
pub r: [U; 12],
}

impl Registers for Msp430Regs {
type ProgramCounter = u16;
impl<U> Registers for Msp430Regs<U>
where
U: PrimInt + LeBytes + Default + core::fmt::Debug,
{
type ProgramCounter = U;

fn pc(&self) -> Self::ProgramCounter {
self.pc
}

fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) {
macro_rules! write_bytes {
($bytes:expr) => {
for b in $bytes {
write_byte(Some(*b))
macro_rules! write_le_bytes {
($value:expr) => {
let mut buf = [0; 4];
// infallible (register size a maximum of 32-bits)
let len = $value.to_le_bytes(&mut buf).unwrap();
let buf = &buf[..len];
for b in buf {
write_byte(Some(*b));
}
};
}

write_bytes!(&self.pc.to_le_bytes());
write_bytes!(&self.sp.to_le_bytes());
write_bytes!(&self.sr.to_le_bytes());
(0..4).for_each(|_| write_byte(None)); // Constant Generator (CG/R3)
write_le_bytes!(&self.pc);
write_le_bytes!(&self.sp);
write_le_bytes!(&self.sr);
(0..core::mem::size_of::<U>()).for_each(|_| write_byte(None)); // Constant Generator (CG/R3)
for reg in self.r.iter() {
write_bytes!(&reg.to_le_bytes());
write_le_bytes!(&reg);
}
}

fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> {
// ensure bytes.chunks_exact(2) won't panic
if bytes.len() % 2 != 0 {
let ptrsize = core::mem::size_of::<U>();

// Ensure bytes contains enough data for all 16 registers
if bytes.len() < ptrsize * 16 {
return Err(());
}

use core::convert::TryInto;
let mut regs = bytes
.chunks_exact(2)
.map(|c| u16::from_le_bytes(c.try_into().unwrap()));
.chunks_exact(ptrsize)
.map(|c| U::from_le_bytes(c).unwrap());

self.pc = regs.next().ok_or(())?;
self.sp = regs.next().ok_or(())?;
self.sr = regs.next().ok_or(())?;

// Constant Generator (CG/R3) should always be 0
if regs.next().ok_or(())? != 0 {
if regs.next().ok_or(())? != U::zero() {
return Err(());
}

Expand Down