summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core.rs2
-rw-r--r--src/decode.rs9
-rw-r--r--src/instructions.rs54
-rw-r--r--src/instructions/macros.rs64
-rw-r--r--src/instructions/rvi.rs131
5 files changed, 146 insertions, 114 deletions
diff --git a/src/core.rs b/src/core.rs
index f46fd54..acc52f2 100644
--- a/src/core.rs
+++ b/src/core.rs
@@ -4,8 +4,6 @@
// This file is part of TRVE (https://gitea.taitep.se/taitep/trve)
// See LICENSE file in the project root for full license text.
-use std::fmt::format;
-
use crate::{
consts::{Addr, RegId, RegValue},
decode::Instruction,
diff --git a/src/decode.rs b/src/decode.rs
index 21a1e64..4258a6f 100644
--- a/src/decode.rs
+++ b/src/decode.rs
@@ -85,15 +85,10 @@ impl Instruction {
imm_20 | imm_10_1 | imm_11 | imm_19_12
}
- // The following are AFAIK only used for shift by immediate operations
-
+ /// Technically part of immediate. Only used to determine shift type for immediate shifts afaik
+ /// 32bit ones use funct7 in this way
#[inline]
pub fn funct6(self) -> u8 {
(self.0 >> 26 & 0x3f) as u8
}
-
- #[inline]
- pub fn imm_shamt(self) -> usize {
- (self.0 >> 20 & 0x3f) as usize
- }
}
diff --git a/src/instructions.rs b/src/instructions.rs
index c7af5ec..2942995 100644
--- a/src/instructions.rs
+++ b/src/instructions.rs
@@ -4,6 +4,9 @@
// This file is part of TRVE (https://gitea.taitep.se/taitep/trve)
// See LICENSE file in the project root for full license text.
+#[macro_use]
+mod macros;
+
mod rvi;
use crate::{
@@ -14,35 +17,60 @@ use crate::{
pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), ExceptionType> {
match instr.opcode_noncompressed() {
- 0b01100 => match (instr.funct7(), instr.funct3()) {
+ 0b01100 => match (instr.funct3(), instr.funct7()) {
// OP
- (0b0000000, 0b000) => rvi::add(core, instr),
- (0b0100000, 0b000) => rvi::sub(core, instr),
- (0b0000000, 0b111) => rvi::and(core, instr),
- (0b0000000, 0b110) => rvi::or(core, instr),
+ (0b000, 0b0000000) => rvi::add(core, instr),
+ (0b000, 0b0100000) => rvi::sub(core, instr),
+ (0b010, 0b0000000) => rvi::slt(core, instr),
+ (0b011, 0b0000000) => rvi::sltu(core, instr),
+ (0b001, 0b0000000) => rvi::sll(core, instr),
+ (0b101, 0b0000000) => rvi::srl(core, instr),
+ (0b101, 0b0100000) => rvi::sra(core, instr),
+ (0b111, 0b0000000) => rvi::and(core, instr),
+ (0b100, 0b0000000) => rvi::xor(core, instr),
+ (0b110, 0b0000000) => rvi::or(core, instr),
+ _ => Err(IllegalInstruction),
+ },
+ 0b01110 => match (instr.funct3(), instr.funct7()) {
+ // OP_32
+ (0b000, 0b0000000) => rvi::addw(core, instr),
+ (0b000, 0b0100000) => rvi::subw(core, instr),
+ (0b001, 0b0000000) => rvi::sllw(core, instr),
+ (0b101, 0b0000000) => rvi::srlw(core, instr),
+ (0b101, 0b0100000) => rvi::sraw(core, instr),
_ => Err(IllegalInstruction),
},
0b00100 => match instr.funct3() {
// OP_IMM
0b000 => rvi::addi(core, instr),
- 0b001 => {
- if instr.funct6() == 0 {
- rvi::slli(core, instr)
- } else {
- Err(IllegalInstruction)
- }
- }
+ 0b010 => rvi::slti(core, instr),
+ 0b011 => rvi::sltiu(core, instr),
+ 0b001 => match instr.funct6() {
+ 0 => rvi::slli(core, instr),
+ _ => Err(IllegalInstruction),
+ },
0b101 => match instr.funct6() {
- // immediate right-shift
0b000000 => rvi::srli(core, instr),
+ 0b010000 => rvi::srai(core, instr),
_ => Err(IllegalInstruction),
},
+ 0b100 => rvi::xori(core, instr),
+ 0b110 => rvi::ori(core, instr),
0b111 => rvi::andi(core, instr),
_ => Err(IllegalInstruction),
},
0b00110 => match instr.funct3() {
// OP_IMM_32
0b000 => rvi::addiw(core, instr),
+ 0b001 => match instr.funct7() {
+ 0 => rvi::slliw(core, instr),
+ _ => Err(IllegalInstruction),
+ },
+ 0b101 => match instr.funct7() {
+ 0b0000000 => rvi::srliw(core, instr),
+ 0b0100000 => rvi::sraiw(core, instr),
+ _ => Err(IllegalInstruction),
+ },
_ => Err(IllegalInstruction),
},
0b01000 => match instr.funct3() {
diff --git a/src/instructions/macros.rs b/src/instructions/macros.rs
new file mode 100644
index 0000000..c88114c
--- /dev/null
+++ b/src/instructions/macros.rs
@@ -0,0 +1,64 @@
+// Copyright (c) 2025 taitep
+// SPDX-License-Identifier: MIT
+//
+// This file is part of TRVE (https://gitea.taitep.se/taitep/trve)
+// See LICENSE file in the project root for full license text.
+
+#[macro_export]
+macro_rules! instr_branch {
+ ($name:ident, $cond:expr) => {
+ pub fn $name(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
+ let a = core.reg_read(instr.rs1());
+ let b = core.reg_read(instr.rs2());
+ if $cond(a, b) {
+ core.pc = core.pc.wrapping_add(instr.imm_b());
+ } else {
+ core.advance_pc();
+ }
+ Ok(())
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! instr_branch_signed {
+ ($name:ident, $cond:expr) => {
+ instr_branch!($name, |a, b| $cond((a as i64), (b as i64)));
+ };
+}
+
+#[macro_export]
+macro_rules! instr_op_r {
+ ($name:ident, $op:expr) => {
+ pub fn $name(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
+ let a = core.reg_read(instr.rs1());
+ let b = core.reg_read(instr.rs2());
+ let res = $op(a, b);
+ core.reg_write(instr.rd(), res);
+ core.advance_pc();
+ Ok(())
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! instr_op_i {
+ ($name:ident, $op:expr) => {
+ pub fn $name(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
+ let a = core.reg_read(instr.rs1());
+ let b = instr.imm_i();
+ let res = $op(a, b);
+ core.reg_write(instr.rd(), res);
+ core.advance_pc();
+ Ok(())
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! instr_op {
+ ($name:ident, $name_imm:ident, $op:expr) => {
+ instr_op_r!($name, $op);
+ instr_op_i!($name_imm, $op);
+ };
+}
diff --git a/src/instructions/rvi.rs b/src/instructions/rvi.rs
index a348596..c35098f 100644
--- a/src/instructions/rvi.rs
+++ b/src/instructions/rvi.rs
@@ -4,83 +4,50 @@
// This file is part of TRVE (https://gitea.taitep.se/taitep/trve)
// See LICENSE file in the project root for full license text.
-use crate::{core::Core, decode::Instruction, exceptions::ExceptionType};
+use crate::{consts::RegValue, core::Core, decode::Instruction, exceptions::ExceptionType};
+
+use std::ops::{BitAnd, BitOr, BitXor};
mod mem;
pub use mem::*;
-pub fn add(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
- core.reg_write(
- instr.rd(),
- core.reg_read(instr.rs1())
- .wrapping_add(core.reg_read(instr.rs2())),
- );
- core.advance_pc();
- Ok(())
-}
-
-pub fn sub(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
- core.reg_write(
- instr.rd(),
- core.reg_read(instr.rs1())
- .wrapping_sub(core.reg_read(instr.rs2())),
- );
- core.advance_pc();
- Ok(())
-}
-
-pub fn addi(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
- core.reg_write(
- instr.rd(),
- core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()),
- );
- core.advance_pc();
- Ok(())
-}
-
-pub fn addiw(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
- let res = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()) as i32;
- core.reg_write(instr.rd(), res as i64 as u64);
- core.advance_pc();
- Ok(())
-}
-
-pub fn and(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
- core.reg_write(
- instr.rd(),
- core.reg_read(instr.rs1()) & core.reg_read(instr.rs2()),
- );
- core.advance_pc();
- Ok(())
-}
-
-pub fn andi(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
- core.reg_write(instr.rd(), core.reg_read(instr.rs1()) & instr.imm_i());
- core.advance_pc();
- Ok(())
-}
-
-pub fn or(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
- core.reg_write(
- instr.rd(),
- core.reg_read(instr.rs1()) | core.reg_read(instr.rs2()),
- );
- core.advance_pc();
- Ok(())
-}
-
-pub fn slli(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
- core.reg_write(instr.rd(), core.reg_read(instr.rs1()) << instr.imm_shamt());
- core.advance_pc();
- Ok(())
-}
-
-pub fn srli(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
- core.reg_write(instr.rd(), core.reg_read(instr.rs1()) >> instr.imm_shamt());
- core.advance_pc();
- Ok(())
-}
+instr_op!(add, addi, RegValue::wrapping_add);
+instr_op!(
+ addw,
+ addiw,
+ |a, b| RegValue::wrapping_add(a, b) as i32 as i64 as RegValue
+);
+instr_op_r!(sub, RegValue::wrapping_sub);
+instr_op_r!(subw, |a, b| RegValue::wrapping_sub(a, b) as i32 as i64
+ as RegValue);
+
+instr_op!(and, andi, RegValue::bitand);
+instr_op!(or, ori, RegValue::bitor);
+instr_op!(xor, xori, RegValue::bitxor);
+
+instr_op!(sll, slli, |x, shamt| x << (shamt & 0b111111));
+instr_op!(
+ sllw,
+ slliw,
+ |x, shamt| (x << (shamt & 0b11111)) as i32 as i64 as RegValue
+);
+instr_op!(srl, srli, |x, shamt| x >> (shamt & 0b111111));
+instr_op!(
+ srlw,
+ srliw,
+ |x, shamt| (x >> (shamt & 0b11111)) as i32 as i64 as RegValue
+);
+instr_op!(sra, srai, |x, shamt| (x as i64 >> (shamt & 0b111111))
+ as RegValue);
+instr_op!(
+ sraw,
+ sraiw,
+ |x, shamt| (x as i32 >> (shamt & 0b11111)) as i64 as RegValue
+);
+
+instr_op!(sltu, sltiu, |a, b| (a < b) as RegValue);
+instr_op!(slt, slti, |a, b| ((a as i64) < (b as i64)) as RegValue);
pub fn lui(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write(instr.rd(), instr.imm_u());
@@ -106,26 +73,6 @@ pub fn jalr(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
Ok(())
}
-macro_rules! instr_branch {
- ($name:ident, $cond:expr) => {
- pub fn $name(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
- let a = core.reg_read(instr.rs1());
- let b = core.reg_read(instr.rs2());
- if $cond(a, b) {
- core.pc = core.pc.wrapping_add(instr.imm_b());
- } else {
- core.advance_pc();
- }
- Ok(())
- }
- };
-}
-macro_rules! instr_branch_signed {
- ($name:ident, $cond:expr) => {
- instr_branch!($name, |a, b| $cond((a as i64), (b as i64)));
- };
-}
-
instr_branch!(beq, |a, b| a == b);
instr_branch!(bne, |a, b| a != b);
instr_branch!(bltu, |a, b| a < b);