Skip to content

Commit

Permalink
implement Arch for RISC-V 32/64
Browse files Browse the repository at this point in the history
Introduces support for **integer** RISC-V ISA.
  • Loading branch information
thomashk0 committed Aug 30, 2020
1 parent 26dd30f commit 893c5cb
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 version 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 @@
//! RISC-V Register Definitions.
//!
//! 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)
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.
#[derive(Default)]
pub struct RiscvCoreRegs<U> {
/// General purpose registers (x0-x31)
pub r: [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.r.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.r.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 893c5cb

Please sign in to comment.