Make macros for R/I-type operations and use them to implement basically every single one i think
This commit is contained in:
64
src/instructions/macros.rs
Normal file
64
src/instructions/macros.rs
Normal file
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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(())
|
||||
}
|
||||
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);
|
||||
|
||||
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(())
|
||||
}
|
||||
instr_op!(and, andi, RegValue::bitand);
|
||||
instr_op!(or, ori, RegValue::bitor);
|
||||
instr_op!(xor, xori, RegValue::bitxor);
|
||||
|
||||
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(())
|
||||
}
|
||||
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
|
||||
);
|
||||
|
||||
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!(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);
|
||||
|
||||
Reference in New Issue
Block a user