Skip to content

Commit

Permalink
Merge pull request #305 from athenavm/refactor-vm-instructions
Browse files Browse the repository at this point in the history
Refactor Instruction type, catch more errors during transpilation
  • Loading branch information
poszu authored Jan 9, 2025
2 parents 290842d + 9a757d7 commit 911b18b
Show file tree
Hide file tree
Showing 13 changed files with 1,063 additions and 1,268 deletions.
568 changes: 294 additions & 274 deletions core/src/disassembler/instruction.rs

Large diffs are not rendered by default.

20 changes: 4 additions & 16 deletions core/src/disassembler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,14 @@ mod instruction;
use anyhow::Context;
use core::panic;
pub use elf::*;
pub use instruction::*;
use instruction::transpile;
use std::{collections::BTreeMap, fs::File, io::Read};

use crate::runtime::{Instruction, Program};
use crate::runtime::Program;

use athena_interface::MethodSelector;

impl Program {
/// Create a new program.
pub const fn new(instructions: Vec<Instruction>, pc_start: u32, pc_base: u32) -> Self {
Self {
instructions,
symbol_table: BTreeMap::new(),
selector_table: BTreeMap::new(),
pc_start,
pc_base,
memory_image: BTreeMap::new(),
}
}

/// Disassemble an ELF to a program that be executed by the VM.
pub fn from(input: &[u8]) -> anyhow::Result<Self> {
// Check the magic number
Expand All @@ -33,7 +21,7 @@ impl Program {
let elf = Elf::decode(input).context("decoding ELF")?;

// Transpile the RV32IM instructions.
let instructions = transpile(&elf.instructions);
let instructions = transpile(&elf.instructions)?;

// Construct the selector table from the symbol table.
let mut selector_table = BTreeMap::new();
Expand Down Expand Up @@ -68,7 +56,7 @@ impl Program {
}

// short-circuit for Athena binaries
let instructions = transpile(&instructions);
let instructions = transpile(&instructions)?;

// Return the program.
Ok(Program::new(instructions, 0, 0))
Expand Down
73 changes: 73 additions & 0 deletions core/src/instruction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use crate::runtime::Register;

/// Instructions set for RV32IM/RV32EM
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Instruction {
/// RV32IM/RV32EM base instructions
// U-type
Lui(Register, u32), // Load Upper Immediate
Auipc(Register, u32), // Add Upper Immediate to PC

// J-type
Jal(Register, i32), // Jump and Link

// I-type
Jalr(Register, Register, i32), // Jump and Link Register
Lb(Register, Register, i32), // Load Byte
Lh(Register, Register, i32), // Load Halfword
Lw(Register, Register, i32), // Load Word
Lbu(Register, Register, i32), // Load Byte Unsigned
Lhu(Register, Register, i32), // Load Halfword Unsigned
Addi(Register, Register, i32), // Add Immediate
Slti(Register, Register, i32), // Set Less Than Immediate
Sltiu(Register, Register, i32), // Set Less Than Immediate Unsigned
Xori(Register, Register, i32), // Xor Immediate
Ori(Register, Register, i32), // Or Immediate
Andi(Register, Register, i32), // And Immediate
Slli(Register, Register, u32), // Shift Left Logical Immediate
Srli(Register, Register, u32), // Shift Right Logical Immediate
Srai(Register, Register, u32), // Shift Right Arithmetic Immediate

// S-type
Sb(Register, Register, i32), // Store Byte
Sh(Register, Register, i32), // Store Halfword
Sw(Register, Register, i32), // Store Word

// R-type
Add(Register, Register, Register), // Add
Sub(Register, Register, Register), // Subtract
Sll(Register, Register, Register), // Shift Left Logical
Slt(Register, Register, Register), // Set Less Than
Sltu(Register, Register, Register), // Set Less Than Unsigned
Xor(Register, Register, Register), // Xor
Srl(Register, Register, Register), // Shift Right Logical
Sra(Register, Register, Register), // Shift Right Arithmetic
Or(Register, Register, Register), // Or
And(Register, Register, Register), // And

// B-type
Beq(Register, Register, i32), // Branch Equal
Bne(Register, Register, i32), // Branch Not Equal
Blt(Register, Register, i32), // Branch Less Than
Bge(Register, Register, i32), // Branch Greater Equal
Bltu(Register, Register, i32), // Branch Less Than Unsigned
Bgeu(Register, Register, i32), // Branch Greater Equal Unsigned

// RV32M Standard Extension for Integer Multiplication and Division
Mul(Register, Register, Register), // Multiply
Mulh(Register, Register, Register), // Multiply High Signed Signed
Mulhsu(Register, Register, Register), // Multiply High Signed Unsigned
Mulhu(Register, Register, Register), // Multiply High Unsigned Unsigned
Div(Register, Register, Register), // Divide Signed
Divu(Register, Register, Register), // Divide Unsigned
Rem(Register, Register, Register), // Remainder Signed
Remu(Register, Register, Register), // Remainder Unsigned

// System Instructions
Ecall, // Environment Call
Ebreak, // Environment Break

NotImplemented {
opcode: &'static str,
},
}
1 change: 1 addition & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

pub mod disassembler;
pub mod host;
mod instruction;
pub mod io;
pub mod runtime;
pub mod syscall;
Expand Down
20 changes: 10 additions & 10 deletions core/src/runtime/gdbstub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl SingleThreadBase for Runtime<'_> {
) -> gdbstub::target::TargetResult<(), Self> {
tracing::trace!("writing registers: {regs:?}");
for (reg, value) in regs.x.iter().enumerate() {
self.rw(Register::try_from(reg as u32).unwrap(), *value)
self.rw(Register::try_from(reg).unwrap(), *value)
}

Ok(())
Expand Down Expand Up @@ -182,7 +182,10 @@ impl SingleRegisterAccess<()> for Runtime<'_> {
) -> gdbstub::target::TargetResult<usize, Self> {
match reg_id {
RiscvRegId::Gpr(id) => {
let value = self.state.regs.read(Register::try_from(id as u32).unwrap());
let value = self
.state
.regs
.read(Register::try_from(id as usize).unwrap());
buf.copy_from_slice(&value.to_le_bytes());
Ok(4)
}
Expand All @@ -202,7 +205,7 @@ impl SingleRegisterAccess<()> for Runtime<'_> {
match reg_id {
RiscvRegId::Gpr(id) => {
let value = u32::from_le_bytes(val.try_into().unwrap());
self.rw(Register::try_from(id as u32).unwrap(), value);
self.rw(Register::try_from(id as usize).unwrap(), value);
}
RiscvRegId::Pc => {
let value = u32::from_le_bytes(val.try_into().unwrap());
Expand Down Expand Up @@ -307,6 +310,9 @@ impl<'h> run_blocking::BlockingEventLoop for GdbBlockingEventLoop<'h> {
ExecutionError::ParsingCodeFailed(_) => {
SingleThreadStopReason::Terminated(Signal::SIGABRT)
}
ExecutionError::InstructionFetchFailed { pc: _ } => {
SingleThreadStopReason::Terminated(Signal::SIGABRT)
}
};
Ok(run_blocking::Event::TargetStopped(stop_reason))
}
Expand Down Expand Up @@ -351,13 +357,7 @@ pub fn gdb_event_loop_thread<'h>(
tracing::info!("Target terminated with signal {}!", sig);
match sig {
Signal::SIGILL => return Err(ExecutionError::Unimplemented()),
Signal::EXC_BAD_ACCESS => {
return Err(ExecutionError::InvalidMemoryAccess(
crate::runtime::Opcode::UNIMP,
0,
crate::runtime::MemoryErr::Unaligned,
))
}
Signal::EXC_BAD_ACCESS => panic!("received EXC_BAD_ACCESS signal"),
Signal::SIGSYS => return Err(ExecutionError::UnsupportedSyscall(0)),
_ => panic!("Unexpected signal: {sig}"),
}
Expand Down
122 changes: 0 additions & 122 deletions core/src/runtime/instruction.rs

This file was deleted.

Loading

0 comments on commit 911b18b

Please sign in to comment.