Skip to content

Commit

Permalink
Add (partial) support for RISC-V (#21)
Browse files Browse the repository at this point in the history
* implement Arch for RISC-V 32/64

Introduces support for **integer** RISC-V ISA.

* fix minor style issues in the riscv module
  • Loading branch information
thomashk0 committed Aug 31, 2020
1 parent 26dd30f commit 5920a3c
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/arch/mod.rs
Expand Up @@ -12,6 +12,7 @@
pub mod arm;
pub mod mips;
pub mod msp430;
pub mod riscv;
mod traits;
pub mod x86;

Expand Down
33 changes: 33 additions & 0 deletions src/arch/riscv/mod.rs
@@ -0,0 +1,33 @@
//! Support for the [RISC-V](https://riscv.org/) architecture.
//!
//! *Note*: currently only supports integer versions of the ISA.

use crate::arch::Arch;

pub mod reg;

/// Implements `Arch` for 32-bit RISC-V.
#[derive(Eq, PartialEq)]
pub struct Riscv32;

/// Implements `Arch` for 64-bit RISC-V.
#[derive(Eq, PartialEq)]
pub struct Riscv64;

impl Arch for Riscv32 {
type Usize = u32;
type Registers = reg::RiscvCoreRegs<u32>;

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

impl Arch for Riscv64 {
type Usize = u64;
type Registers = reg::RiscvCoreRegs<u64>;

fn target_description_xml() -> Option<&'static str> {
Some(r#"<target version="1.0"><architecture>riscv64</architecture></target>"#)
}
}
5 changes: 5 additions & 0 deletions src/arch/riscv/reg/mod.rs
@@ -0,0 +1,5 @@
//! `GdbRegister` structs for RISC-V architectures.

mod riscv;

pub use riscv::RiscvCoreRegs;
70 changes: 70 additions & 0 deletions src/arch/riscv/reg/riscv.rs
@@ -0,0 +1,70 @@
use crate::arch::Registers;
use crate::internal::LeBytes;
use num_traits::PrimInt;

/// RISC-V Integer registers.
///
/// The register width is set to `u32` or `u64` based on the `<U>` type.
///
/// Useful links:
/// * [GNU binutils-gdb XML descriptions](https://github.com/bminor/binutils-gdb/blob/master/gdb/features/riscv)
/// * [riscv-tdep.h](https://github.com/bminor/binutils-gdb/blob/master/gdb/riscv-tdep.h)
#[derive(Default)]
pub struct RiscvCoreRegs<U> {
/// General purpose registers (x0-x31)
pub x: [U; 32],
/// Program counter
pub pc: U,
}

impl<U> Registers for RiscvCoreRegs<U>
where
U: PrimInt + LeBytes + Default,
{
fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) {
macro_rules! write_le_bytes {
($value:expr) => {
let mut buf = [0; 16];
// infallible (unless digit is a >128 bit number)
let len = $value.to_le_bytes(&mut buf).unwrap();
let buf = &buf[..len];
for b in buf {
write_byte(Some(*b));
}
};
}

// Write GPRs
for reg in self.x.iter() {
write_le_bytes!(reg);
}

// Program Counter is regnum 33
write_le_bytes!(&self.pc);
}

fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> {
let ptrsize = core::mem::size_of::<U>();

// ensure bytes.chunks_exact(ptrsize) won't panic
if bytes.len() % ptrsize != 0 {
return Err(());
}

let mut regs = bytes
.chunks_exact(ptrsize)
.map(|c| U::from_le_bytes(c).unwrap());

// Read GPRs
for reg in self.x.iter_mut() {
*reg = regs.next().ok_or(())?
}
self.pc = regs.next().ok_or(())?;

if regs.next().is_some() {
return Err(());
}

Ok(())
}
}

0 comments on commit 5920a3c

Please sign in to comment.