actually compiles and does stuff now
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
pub mod riscv64;
|
||||
use super::*;
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
use crate::{compiler::program::{Addr, Instr, SymTable}, ir::AddrID};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum LinkerInstruction {
|
||||
Add { dest: Reg, src1: Reg, src2: Reg },
|
||||
Addi { dest: Reg, src: Reg, imm: i32 },
|
||||
Andi { dest: Reg, src: Reg, imm: i32 },
|
||||
Slli { dest: Reg, src: Reg, imm: i32 },
|
||||
Srli { dest: Reg, src: Reg, imm: i32 },
|
||||
Sd { src: Reg, offset: i32, base: Reg },
|
||||
Ld { dest: Reg, offset: i32, base: Reg },
|
||||
Mv { dest: Reg, src: Reg },
|
||||
La { dest: Reg, src: AddrID },
|
||||
Jal { dest: Reg, offset: i32 },
|
||||
Call(AddrID),
|
||||
J(AddrID),
|
||||
Ret,
|
||||
Ecall,
|
||||
Li { dest: Reg, imm: i64 },
|
||||
}
|
||||
|
||||
impl Instr for LinkerInstruction {
|
||||
fn push(
|
||||
&self,
|
||||
data: &mut Vec<u8>,
|
||||
sym_map: &SymTable,
|
||||
pos: Addr,
|
||||
missing: bool,
|
||||
) -> Option<AddrID> {
|
||||
let last = match self {
|
||||
Self::Add { dest, src1, src2 } => add(*dest, *src1, *src2),
|
||||
Self::Addi { dest, src, imm } => addi(*dest, *src, BitsI32::new(*imm)),
|
||||
Self::Andi { dest, src, imm } => andi(*dest, *src, BitsI32::new(*imm)),
|
||||
Self::Slli { dest, src, imm } => slli(*dest, *src, BitsI32::new(*imm)),
|
||||
Self::Srli { dest, src, imm } => srli(*dest, *src, BitsI32::new(*imm)),
|
||||
Self::Sd { src, offset, base } => sd(*src, BitsI32::new(*offset), *base),
|
||||
Self::Ld { dest, offset, base } => ld(*dest, BitsI32::new(*offset), *base),
|
||||
Self::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)),
|
||||
Self::La { dest, src } => {
|
||||
if let Some(addr) = sym_map.get(*src) {
|
||||
let offset = addr.val() as i32 - pos.val() as i32;
|
||||
data.extend(auipc(*dest, BitsI32::new(0)).to_le_bytes());
|
||||
addi(*dest, *dest, BitsI32::new(offset))
|
||||
} else {
|
||||
data.extend_from_slice(&[0; 2 * 4]);
|
||||
return Some(*src);
|
||||
}
|
||||
}
|
||||
Self::Jal { dest, offset } => jal(*dest, BitsI32::new(*offset)),
|
||||
Self::J(sym) => {
|
||||
if let Some(addr) = sym_map.get(*sym) {
|
||||
let offset = addr.val() as i32 - pos.val() as i32;
|
||||
j(BitsI32::new(offset))
|
||||
} else {
|
||||
data.extend_from_slice(&[0; 4]);
|
||||
return Some(*sym);
|
||||
}
|
||||
}
|
||||
Self::Call(sym) => {
|
||||
if let Some(addr) = sym_map.get(*sym) {
|
||||
let offset = addr.val() as i32 - pos.val() as i32;
|
||||
jal(ra, BitsI32::new(offset))
|
||||
} else {
|
||||
data.extend_from_slice(&[0; 4]);
|
||||
return Some(*sym);
|
||||
}
|
||||
}
|
||||
Self::Ret => ret(),
|
||||
Self::Ecall => ecall(),
|
||||
Self::Li { dest, imm } => addi(*dest, zero, BitsI32::new(*imm as i32)),
|
||||
};
|
||||
data.extend(last.to_le_bytes());
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
use crate::util::Bits32;
|
||||
|
||||
use super::Reg;
|
||||
|
||||
pub struct RawInstruction(u32);
|
||||
|
||||
use RawInstruction as I;
|
||||
|
||||
impl RawInstruction {
|
||||
pub fn to_le_bytes(&self) -> impl IntoIterator<Item = u8> {
|
||||
self.0.to_le_bytes().into_iter()
|
||||
}
|
||||
pub fn to_be_bytes(&self) -> impl IntoIterator<Item = u8> {
|
||||
self.0.to_be_bytes().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub type Funct3 = Bits32<2, 0>;
|
||||
|
||||
pub const fn r_type(
|
||||
funct7: Bits32<6, 0>,
|
||||
rs2: Reg,
|
||||
rs1: Reg,
|
||||
funct3: Bits32<2, 0>,
|
||||
rd: Reg,
|
||||
opcode: u32,
|
||||
) -> I {
|
||||
I((funct7.val() << 25)
|
||||
+ (rs2.val() << 20)
|
||||
+ (rs1.val() << 15)
|
||||
+ (funct3.val() << 12)
|
||||
+ (rd.val() << 7)
|
||||
+ opcode)
|
||||
}
|
||||
pub const fn i_type(imm: Bits32<11, 0>, rs1: Reg, funct: Funct3, rd: Reg, opcode: u32) -> I {
|
||||
I((imm.val() << 20) + (rs1.val() << 15) + (funct.val() << 12) + (rd.val() << 7) + opcode)
|
||||
}
|
||||
pub const fn s_type(
|
||||
rs2: Reg,
|
||||
rs1: Reg,
|
||||
funct3: Funct3,
|
||||
imm: Bits32<11, 0>,
|
||||
opcode: u32,
|
||||
) -> I {
|
||||
I((imm.bits(11, 5) << 25)
|
||||
+ (rs2.val() << 20)
|
||||
+ (rs1.val() << 15)
|
||||
+ (funct3.val() << 12)
|
||||
+ (imm.bits(4, 0) << 7)
|
||||
+ opcode)
|
||||
}
|
||||
pub const fn b_type(
|
||||
rs2: Reg,
|
||||
rs1: Reg,
|
||||
funct3: Funct3,
|
||||
imm: Bits32<12, 1>,
|
||||
opcode: u32,
|
||||
) -> I {
|
||||
I((imm.bit(12) << 31)
|
||||
+ (imm.bits(10, 5) << 25)
|
||||
+ (rs2.val() << 20)
|
||||
+ (rs1.val() << 15)
|
||||
+ (funct3.val() << 8)
|
||||
+ (imm.bits(4, 1) << 8)
|
||||
+ (imm.bit(11) << 7)
|
||||
+ opcode)
|
||||
}
|
||||
pub const fn u_type(imm: Bits32<31, 12>, rd: Reg, opcode: u32) -> I {
|
||||
I((imm.bits(31, 12) << 12) + (rd.val() << 7) + opcode)
|
||||
}
|
||||
pub const fn j_type(imm: Bits32<20, 1>, rd: Reg, opcode: u32) -> I {
|
||||
I((imm.bit(20) << 31)
|
||||
+ (imm.bits(10, 1) << 21)
|
||||
+ (imm.bit(11) << 20)
|
||||
+ (imm.bits(19, 12) << 12)
|
||||
+ (rd.val() << 7)
|
||||
+ opcode)
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
compiler::{arch::riscv64::Reg, create_program, Addr},
|
||||
ir::{
|
||||
arch::riscv64::{RV64Instruction as AI, RegRef},
|
||||
IRLInstruction as IRI, Program,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{LinkerInstruction as LI, *};
|
||||
|
||||
pub fn compile(program: Program) -> (Vec<u8>, Option<Addr>) {
|
||||
let mut fns = Vec::new();
|
||||
let mut data = Vec::new();
|
||||
for d in program.data {
|
||||
data.push((d.data, d.addr));
|
||||
}
|
||||
let mut start = None;
|
||||
for f in program.fns {
|
||||
let mut v = Vec::new();
|
||||
let mut stack = HashMap::new();
|
||||
let mut stack_len = 0;
|
||||
if !f.stack.is_empty() || !f.args.is_empty() {
|
||||
for (id, s) in &f.stack {
|
||||
stack.insert(id, stack_len);
|
||||
stack_len += *s as i32;
|
||||
}
|
||||
for (id, s) in f.args.iter().rev() {
|
||||
stack.insert(id, stack_len);
|
||||
stack_len += *s as i32;
|
||||
}
|
||||
v.push(LI::Addi {
|
||||
dest: sp,
|
||||
src: sp,
|
||||
imm: -stack_len,
|
||||
});
|
||||
}
|
||||
for i in &f.instructions {
|
||||
match i {
|
||||
IRI::Mv { dest, src } => todo!(),
|
||||
IRI::Ref { dest, src } => todo!(),
|
||||
IRI::LoadAddr { dest, src } => {
|
||||
v.extend([
|
||||
LI::La {
|
||||
dest: t0,
|
||||
src: *src,
|
||||
},
|
||||
LI::Sd {
|
||||
src: t0,
|
||||
offset: stack[dest],
|
||||
base: sp,
|
||||
},
|
||||
]);
|
||||
}
|
||||
IRI::Call { dest, f, args } => {
|
||||
let mut offset = 0;
|
||||
for (arg, s) in args {
|
||||
offset -= *s as i32;
|
||||
v.extend([
|
||||
LI::Ld {
|
||||
dest: t0,
|
||||
offset: stack[arg],
|
||||
base: sp,
|
||||
},
|
||||
LI::Sd {
|
||||
src: t0,
|
||||
offset,
|
||||
base: sp,
|
||||
},
|
||||
]);
|
||||
}
|
||||
v.push(LI::Call(*f));
|
||||
}
|
||||
IRI::AsmBlock { args, instructions } => {
|
||||
for (reg, var) in args {
|
||||
v.push(LI::Ld {
|
||||
dest: *reg,
|
||||
offset: stack[var],
|
||||
base: sp,
|
||||
});
|
||||
}
|
||||
fn r(rr: RegRef) -> Reg {
|
||||
match rr {
|
||||
RegRef::Var(var_ident) => todo!(),
|
||||
RegRef::Reg(reg) => reg,
|
||||
}
|
||||
}
|
||||
for i in instructions {
|
||||
match *i {
|
||||
AI::Ecall => v.push(LI::Ecall),
|
||||
AI::Li { dest, imm } => v.push(LI::Li { dest: r(dest), imm }),
|
||||
AI::Mv { dest, src } => v.push(LI::Mv {
|
||||
dest: r(dest),
|
||||
src: r(src),
|
||||
}),
|
||||
AI::La { dest, src } => todo!(),
|
||||
AI::Ld { dest, base, offset } => v.push(LI::Ld {
|
||||
dest: r(dest),
|
||||
offset: offset as i32,
|
||||
base: r(base),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
IRI::Ret { src } => todo!(),
|
||||
}
|
||||
}
|
||||
if f.name == "start" {
|
||||
start = Some(f.addr);
|
||||
} else {
|
||||
v.push(LI::Ret);
|
||||
}
|
||||
fns.push((v, f.addr));
|
||||
}
|
||||
create_program(fns, data, start)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
use super::Funct3;
|
||||
|
||||
pub mod op {
|
||||
use super::*;
|
||||
pub const ADD : Funct3 = Funct3::new(0b000);
|
||||
pub const SLL : Funct3 = Funct3::new(0b001);
|
||||
pub const SLT : Funct3 = Funct3::new(0b010);
|
||||
pub const SLTU: Funct3 = Funct3::new(0b011);
|
||||
pub const XOR : Funct3 = Funct3::new(0b100);
|
||||
pub const SR : Funct3 = Funct3::new(0b101);
|
||||
pub const OR : Funct3 = Funct3::new(0b110);
|
||||
pub const AND : Funct3 = Funct3::new(0b111);
|
||||
}
|
||||
|
||||
pub mod width {
|
||||
use super::*;
|
||||
pub const B : Funct3 = Funct3::new(0b000);
|
||||
pub const H : Funct3 = Funct3::new(0b001);
|
||||
pub const W : Funct3 = Funct3::new(0b010);
|
||||
pub const D : Funct3 = Funct3::new(0b011);
|
||||
pub const BU: Funct3 = Funct3::new(0b100);
|
||||
pub const HU: Funct3 = Funct3::new(0b101);
|
||||
pub const WU: Funct3 = Funct3::new(0b110);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
mod asm;
|
||||
mod base;
|
||||
mod funct;
|
||||
mod opcode;
|
||||
mod reg;
|
||||
mod single;
|
||||
mod compile;
|
||||
|
||||
use crate::util::BitsI32;
|
||||
pub use asm::*;
|
||||
use base::*;
|
||||
use funct::{op::*, width};
|
||||
use opcode::*;
|
||||
pub use reg::*;
|
||||
pub use compile::*;
|
||||
|
||||
use single::*;
|
||||
|
||||
pub fn gen() -> Vec<u8> {
|
||||
// use asm::LinkerInstruction as I;
|
||||
// let mut table = SymMap::new();
|
||||
// let (msg, len) = table.push_ro_data_size(b"Hello world!\n".to_vec());
|
||||
// let (msg2, len2) = table.push_ro_data_size(b"IT WORKS!!!!\n".to_vec());
|
||||
// let print_stuff = table.reserve();
|
||||
// let start = table.push_fn(vec![
|
||||
// I::Call(*print_stuff),
|
||||
// I::Li { dest: a0, imm: 0 },
|
||||
// I::Li { dest: a7, imm: 93 },
|
||||
// I::Ecall,
|
||||
// I::Jal {
|
||||
// dest: zero,
|
||||
// offset: 0,
|
||||
// },
|
||||
// ]);
|
||||
// table.write_fn(
|
||||
// print_stuff,
|
||||
// vec![
|
||||
// I::Li { dest: a0, imm: 1 },
|
||||
// I::La { dest: a1, src: msg },
|
||||
// I::Li {
|
||||
// dest: a2,
|
||||
// imm: len as i64,
|
||||
// },
|
||||
// I::Li { dest: a7, imm: 64 },
|
||||
// I::Ecall,
|
||||
// I::Li { dest: a0, imm: 1 },
|
||||
// I::La {
|
||||
// dest: a1,
|
||||
// src: msg2,
|
||||
// },
|
||||
// I::Li {
|
||||
// dest: a2,
|
||||
// imm: len2 as i64,
|
||||
// },
|
||||
// I::Li { dest: a7, imm: 64 },
|
||||
// I::Ecall,
|
||||
// I::Ret,
|
||||
// ],
|
||||
// );
|
||||
// let (program, start) = create_program(table, Some(start));
|
||||
// elf::create(program, start.expect("no start!"))
|
||||
todo!("remove this");
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
pub const OPCODE_MASK: u32 = 0b1111111;
|
||||
|
||||
pub const SYSTEM: u32 = 0b1110011;
|
||||
pub const LOAD : u32 = 0b0000011;
|
||||
pub const STORE : u32 = 0b0100011;
|
||||
pub const AUIPC : u32 = 0b0010111;
|
||||
pub const IMM_OP: u32 = 0b0010011;
|
||||
pub const OP : u32 = 0b0110011;
|
||||
pub const JAL : u32 = 0b1101111;
|
||||
pub const JALR : u32 = 0b1100111;
|
||||
@@ -0,0 +1,179 @@
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reg(u8);
|
||||
|
||||
/// hard wired 0
|
||||
pub const zero: Reg = Reg(0);
|
||||
/// return address
|
||||
pub const ra: Reg = Reg(1);
|
||||
/// stack pointer
|
||||
pub const sp: Reg = Reg(2);
|
||||
/// global pointer
|
||||
pub const gp: Reg = Reg(3);
|
||||
/// thread pointer
|
||||
pub const tp: Reg = Reg(4);
|
||||
/// temp / alternate link
|
||||
pub const t0: Reg = Reg(5);
|
||||
pub const t1: Reg = Reg(6);
|
||||
pub const t2: Reg = Reg(7);
|
||||
|
||||
pub const fp: Reg = Reg(8);
|
||||
pub const s0: Reg = Reg(8);
|
||||
pub const s1: Reg = Reg(9);
|
||||
|
||||
pub const a0: Reg = Reg(10);
|
||||
pub const a1: Reg = Reg(11);
|
||||
pub const a2: Reg = Reg(12);
|
||||
pub const a3: Reg = Reg(13);
|
||||
pub const a4: Reg = Reg(14);
|
||||
pub const a5: Reg = Reg(15);
|
||||
pub const a6: Reg = Reg(16);
|
||||
pub const a7: Reg = Reg(17);
|
||||
|
||||
pub const s2: Reg = Reg(18);
|
||||
pub const s3: Reg = Reg(19);
|
||||
pub const s4: Reg = Reg(20);
|
||||
pub const s5: Reg = Reg(21);
|
||||
pub const s6: Reg = Reg(22);
|
||||
pub const s7: Reg = Reg(23);
|
||||
pub const s8: Reg = Reg(24);
|
||||
pub const s9: Reg = Reg(25);
|
||||
pub const s10: Reg = Reg(26);
|
||||
pub const s11: Reg = Reg(27);
|
||||
|
||||
pub const t3: Reg = Reg(28);
|
||||
pub const t4: Reg = Reg(29);
|
||||
pub const t5: Reg = Reg(30);
|
||||
pub const t6: Reg = Reg(31);
|
||||
|
||||
// pub const ft0: Reg = Reg(0);
|
||||
// pub const ft1: Reg = Reg(1);
|
||||
// pub const ft2: Reg = Reg(2);
|
||||
// pub const ft3: Reg = Reg(3);
|
||||
// pub const ft4: Reg = Reg(4);
|
||||
// pub const ft5: Reg = Reg(5);
|
||||
// pub const ft6: Reg = Reg(6);
|
||||
// pub const ft7: Reg = Reg(7);
|
||||
//
|
||||
// pub const fs0: Reg = Reg(8);
|
||||
// pub const fs1: Reg = Reg(9);
|
||||
//
|
||||
// pub const fa0: Reg = Reg(10);
|
||||
// pub const fa1: Reg = Reg(11);
|
||||
// pub const fa2: Reg = Reg(12);
|
||||
// pub const fa3: Reg = Reg(13);
|
||||
// pub const fa4: Reg = Reg(14);
|
||||
// pub const fa5: Reg = Reg(15);
|
||||
// pub const fa6: Reg = Reg(16);
|
||||
// pub const fa7: Reg = Reg(17);
|
||||
//
|
||||
// pub const fs2: Reg = Reg(18);
|
||||
// pub const fs3: Reg = Reg(19);
|
||||
// pub const fs4: Reg = Reg(20);
|
||||
// pub const fs5: Reg = Reg(21);
|
||||
// pub const fs6: Reg = Reg(22);
|
||||
// pub const fs7: Reg = Reg(23);
|
||||
// pub const fs8: Reg = Reg(24);
|
||||
// pub const fs9: Reg = Reg(25);
|
||||
// pub const fs10: Reg = Reg(26);
|
||||
// pub const fs11: Reg = Reg(27);
|
||||
//
|
||||
// pub const ft8: Reg = Reg(28);
|
||||
// pub const ft9: Reg = Reg(29);
|
||||
// pub const ft10: Reg = Reg(30);
|
||||
// pub const ft11: Reg = Reg(31);
|
||||
|
||||
impl Reg {
|
||||
#[inline]
|
||||
pub const fn val(&self) -> u32 {
|
||||
self.0 as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl Reg {
|
||||
pub fn from_str(str: &str) -> Option<Self> {
|
||||
Some(match str {
|
||||
"zero" => zero,
|
||||
"ra" => ra,
|
||||
"sp" => sp,
|
||||
"gp" => gp,
|
||||
"tp" => tp,
|
||||
"t0" => t0,
|
||||
"t1" => t1,
|
||||
"t2" => t2,
|
||||
"fp" => fp,
|
||||
"s0" => s0,
|
||||
"s1" => s1,
|
||||
"a0" => a0,
|
||||
"a1" => a1,
|
||||
"a2" => a2,
|
||||
"a3" => a3,
|
||||
"a4" => a4,
|
||||
"a5" => a5,
|
||||
"a6" => a6,
|
||||
"a7" => a7,
|
||||
"s2" => s2,
|
||||
"s3" => s3,
|
||||
"s4" => s4,
|
||||
"s5" => s5,
|
||||
"s6" => s6,
|
||||
"s7" => s7,
|
||||
"s8" => s8,
|
||||
"s9" => s9,
|
||||
"s10" => s10,
|
||||
"s11" => s11,
|
||||
"t3" => t3,
|
||||
"t4" => t4,
|
||||
"t5" => t5,
|
||||
"t6" => t6,
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Reg {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self.0 {
|
||||
0 => "zero",
|
||||
1 => "ra",
|
||||
2 => "sp",
|
||||
3 => "gp",
|
||||
4 => "tp",
|
||||
5 => "t0",
|
||||
6 => "t1",
|
||||
7 => "t2",
|
||||
8 => "fp",
|
||||
9 => "s1",
|
||||
10 => "a0",
|
||||
11 => "a1",
|
||||
12 => "a2",
|
||||
13 => "a3",
|
||||
14 => "a4",
|
||||
15 => "a5",
|
||||
16 => "a6",
|
||||
17 => "a7",
|
||||
18 => "s2",
|
||||
19 => "s3",
|
||||
20 => "s4",
|
||||
21 => "s5",
|
||||
22 => "s6",
|
||||
23 => "s7",
|
||||
24 => "s8",
|
||||
25 => "s9",
|
||||
26 => "s10",
|
||||
27 => "s11",
|
||||
28 => "t3",
|
||||
29 => "t4",
|
||||
30 => "t5",
|
||||
31 => "t6",
|
||||
_ => "unknown",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
use crate::util::{Bits32, BitsI32};
|
||||
|
||||
use super::*;
|
||||
|
||||
use RawInstruction as I;
|
||||
|
||||
pub const fn ecall() -> I {
|
||||
i_type(Bits32::new(0), zero, Bits32::new(0), zero, SYSTEM)
|
||||
}
|
||||
pub const fn ebreak() -> I {
|
||||
i_type(Bits32::new(1), zero, Bits32::new(0), zero, SYSTEM)
|
||||
}
|
||||
pub const fn auipc(dest: Reg, imm: BitsI32<31, 12>) -> I {
|
||||
u_type(imm.to_u(), dest, AUIPC)
|
||||
}
|
||||
pub const fn ld(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||
i_type(offset.to_u(), base, width::D, dest, LOAD)
|
||||
}
|
||||
pub const fn lw(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||
i_type(offset.to_u(), base, width::W, dest, LOAD)
|
||||
}
|
||||
pub const fn lb(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||
i_type(offset.to_u(), base, width::B, dest, LOAD)
|
||||
}
|
||||
pub const fn sb(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||
s_type(src, base, width::B, offset.to_u(), STORE)
|
||||
}
|
||||
pub const fn sw(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||
s_type(src, base, width::W, offset.to_u(), STORE)
|
||||
}
|
||||
pub const fn sd(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||
s_type(src, base, width::D, offset.to_u(), STORE)
|
||||
}
|
||||
pub const fn add(dest: Reg, src1: Reg, src2: Reg) -> I {
|
||||
r_type(Bits32::new(0), src2, src1, ADD, dest, OP)
|
||||
}
|
||||
pub const fn addi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> I {
|
||||
i_type(imm.to_u(), src, ADD, dest, IMM_OP)
|
||||
}
|
||||
pub const fn andi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> I {
|
||||
i_type(imm.to_u(), src, AND, dest, IMM_OP)
|
||||
}
|
||||
pub const fn slli(dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I {
|
||||
i_type(Bits32::new(imm.to_u().val()), src, SLL, dest, IMM_OP)
|
||||
}
|
||||
pub const fn srli(dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I {
|
||||
i_type(Bits32::new(imm.to_u().val()), src, SR, dest, IMM_OP)
|
||||
}
|
||||
pub const fn jal(dest: Reg, offset: BitsI32<20, 1>) -> I {
|
||||
j_type(offset.to_u(), dest, JAL)
|
||||
}
|
||||
pub const fn jalr(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||
i_type(offset.to_u(), base, Bits32::new(0), dest, JALR)
|
||||
}
|
||||
|
||||
// pseudoinstructions that map to a single instruction
|
||||
|
||||
pub const fn j(offset: BitsI32<20, 1>) -> I {
|
||||
jal(zero, offset)
|
||||
}
|
||||
pub const fn ret() -> I {
|
||||
jalr(zero, BitsI32::new(0), ra)
|
||||
}
|
||||
Reference in New Issue
Block a user