refactored asm
This commit is contained in:
@@ -5,7 +5,7 @@ fn start() {
|
||||
println("what");
|
||||
print(tester());
|
||||
arger("a", "b", "c");
|
||||
exit(add(35, 4));
|
||||
exit(sub(add(35, 5), 1));
|
||||
}
|
||||
|
||||
fn thinger() {
|
||||
@@ -42,6 +42,17 @@ fn add(a: 64, b: 64) -> 64 {
|
||||
c
|
||||
}
|
||||
|
||||
fn sub(a: 64, b: 64) -> 64 {
|
||||
let c: 64 = 0;
|
||||
asm (t0 = a, t1 = b, a0 = c) {
|
||||
ld t0, 0, t0
|
||||
ld t1, 0, t1
|
||||
sub t0, t0, t1
|
||||
sd t0, 0, a0
|
||||
};
|
||||
c
|
||||
}
|
||||
|
||||
fn arger(a: slice<8>, b: slice<8>, c: slice<8>) {
|
||||
print(a);
|
||||
print(b);
|
||||
|
||||
@@ -1,30 +1,74 @@
|
||||
use crate::{compiler::program::{Addr, Instr, SymTable}, ir::Symbol};
|
||||
use crate::{
|
||||
compiler::program::{Addr, Instr, SymTable},
|
||||
ir::Symbol,
|
||||
};
|
||||
|
||||
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 },
|
||||
Sw { src: Reg, offset: i32, base: Reg },
|
||||
Sh { src: Reg, offset: i32, base: Reg },
|
||||
Sb { src: Reg, offset: i32, base: Reg },
|
||||
Ld { dest: Reg, offset: i32, base: Reg },
|
||||
Lw { dest: Reg, offset: i32, base: Reg },
|
||||
Lh { dest: Reg, offset: i32, base: Reg },
|
||||
Lb { dest: Reg, offset: i32, base: Reg },
|
||||
Mv { dest: Reg, src: Reg },
|
||||
La { dest: Reg, src: Symbol },
|
||||
Jal { dest: Reg, offset: i32 },
|
||||
Op {
|
||||
op: Op,
|
||||
dest: Reg,
|
||||
src1: Reg,
|
||||
src2: Reg,
|
||||
},
|
||||
OpF7 {
|
||||
op: Op,
|
||||
funct: Funct7,
|
||||
dest: Reg,
|
||||
src1: Reg,
|
||||
src2: Reg,
|
||||
},
|
||||
OpImm {
|
||||
op: Op,
|
||||
dest: Reg,
|
||||
src: Reg,
|
||||
imm: i32,
|
||||
},
|
||||
OpImmF7 {
|
||||
op: Op,
|
||||
funct: Funct7,
|
||||
dest: Reg,
|
||||
src: Reg,
|
||||
imm: i32,
|
||||
},
|
||||
Store {
|
||||
width: Width,
|
||||
src: Reg,
|
||||
offset: i32,
|
||||
base: Reg,
|
||||
},
|
||||
Load {
|
||||
width: Width,
|
||||
dest: Reg,
|
||||
offset: i32,
|
||||
base: Reg,
|
||||
},
|
||||
Mv {
|
||||
dest: Reg,
|
||||
src: Reg,
|
||||
},
|
||||
La {
|
||||
dest: Reg,
|
||||
src: Symbol,
|
||||
},
|
||||
Jal {
|
||||
dest: Reg,
|
||||
offset: i32,
|
||||
},
|
||||
Call(Symbol),
|
||||
J(Symbol),
|
||||
Ret,
|
||||
Ecall,
|
||||
Li { dest: Reg, imm: i64 },
|
||||
Li {
|
||||
dest: Reg,
|
||||
imm: i64,
|
||||
},
|
||||
}
|
||||
|
||||
pub const fn addi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> RawInstruction {
|
||||
opi(Op::Add, dest, src, imm)
|
||||
}
|
||||
|
||||
impl Instr for LinkerInstruction {
|
||||
@@ -36,19 +80,39 @@ impl Instr for LinkerInstruction {
|
||||
missing: bool,
|
||||
) -> Option<Symbol> {
|
||||
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::Sw { src, offset, base } => sw(*src, BitsI32::new(*offset), *base),
|
||||
Self::Sh { src, offset, base } => sh(*src, BitsI32::new(*offset), *base),
|
||||
Self::Sb { src, offset, base } => sb(*src, BitsI32::new(*offset), *base),
|
||||
Self::Ld { dest, offset, base } => ld(*dest, BitsI32::new(*offset), *base),
|
||||
Self::Lw { dest, offset, base } => lw(*dest, BitsI32::new(*offset), *base),
|
||||
Self::Lh { dest, offset, base } => lh(*dest, BitsI32::new(*offset), *base),
|
||||
Self::Lb { dest, offset, base } => lb(*dest, BitsI32::new(*offset), *base),
|
||||
Self::Op {
|
||||
op,
|
||||
dest,
|
||||
src1,
|
||||
src2,
|
||||
} => opr(*op, *dest, *src1, *src2),
|
||||
Self::OpF7 {
|
||||
op,
|
||||
funct,
|
||||
dest,
|
||||
src1,
|
||||
src2,
|
||||
} => oprf7(*op, *funct, *dest, *src1, *src2),
|
||||
Self::OpImm { op, dest, src, imm } => opi(*op, *dest, *src, BitsI32::new(*imm)),
|
||||
Self::OpImmF7 {
|
||||
op,
|
||||
funct,
|
||||
dest,
|
||||
src,
|
||||
imm,
|
||||
} => opif7(*op, *funct, *dest, *src, BitsI32::new(*imm)),
|
||||
Self::Store {
|
||||
width,
|
||||
src,
|
||||
offset,
|
||||
base,
|
||||
} => store(*width, *src, BitsI32::new(*offset), *base),
|
||||
Self::Load {
|
||||
width,
|
||||
dest,
|
||||
offset,
|
||||
base,
|
||||
} => load(*width, *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) {
|
||||
@@ -87,3 +151,30 @@ impl Instr for LinkerInstruction {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl LinkerInstruction {
|
||||
pub fn addi(dest: Reg, src: Reg, imm: i32) -> Self {
|
||||
Self::OpImm {
|
||||
op: Op::Add,
|
||||
dest,
|
||||
src,
|
||||
imm,
|
||||
}
|
||||
}
|
||||
pub fn sd(src: Reg, offset: i32, base: Reg) -> Self {
|
||||
Self::Store {
|
||||
width: Width::D,
|
||||
src,
|
||||
offset,
|
||||
base,
|
||||
}
|
||||
}
|
||||
pub fn ld(dest: Reg, offset: i32, base: Reg) -> Self {
|
||||
Self::Load {
|
||||
width: Width::D,
|
||||
dest,
|
||||
offset,
|
||||
base,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::util::Bits32;
|
||||
|
||||
use super::Reg;
|
||||
use super::{Funct3, Reg};
|
||||
|
||||
pub struct RawInstruction(u32);
|
||||
|
||||
@@ -15,8 +15,6 @@ impl RawInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
pub type Funct3 = Bits32<2, 0>;
|
||||
|
||||
pub const fn r_type(
|
||||
funct7: Bits32<6, 0>,
|
||||
rs2: Reg,
|
||||
|
||||
@@ -24,69 +24,26 @@ fn mov_mem(
|
||||
mut len: Len,
|
||||
) {
|
||||
let mut off = 0;
|
||||
while len >= 8 {
|
||||
for width in Width::MAIN.iter().rev() {
|
||||
let wl = width.len();
|
||||
while len >= wl {
|
||||
v.extend([
|
||||
LI::Ld {
|
||||
LI::Load {
|
||||
width: *width,
|
||||
dest: temp,
|
||||
offset: src_offset + off,
|
||||
base: src,
|
||||
},
|
||||
LI::Sd {
|
||||
LI::Store {
|
||||
width: *width,
|
||||
src: temp,
|
||||
offset: dest_offset + off,
|
||||
base: dest,
|
||||
},
|
||||
]);
|
||||
len -= 8;
|
||||
off += 8;
|
||||
len -= wl;
|
||||
off += wl as i32;
|
||||
}
|
||||
while len >= 4 {
|
||||
v.extend([
|
||||
LI::Lw {
|
||||
dest: temp,
|
||||
offset: src_offset + off,
|
||||
base: src,
|
||||
},
|
||||
LI::Sw {
|
||||
src: temp,
|
||||
offset: dest_offset + off,
|
||||
base: dest,
|
||||
},
|
||||
]);
|
||||
len -= 4;
|
||||
off += 4;
|
||||
}
|
||||
while len >= 2 {
|
||||
v.extend([
|
||||
LI::Lh {
|
||||
dest: temp,
|
||||
offset: src_offset + off,
|
||||
base: src,
|
||||
},
|
||||
LI::Sh {
|
||||
src: temp,
|
||||
offset: dest_offset + off,
|
||||
base: dest,
|
||||
},
|
||||
]);
|
||||
len -= 2;
|
||||
off += 2;
|
||||
}
|
||||
while len >= 1 {
|
||||
v.extend([
|
||||
LI::Lb {
|
||||
dest: temp,
|
||||
offset: src_offset + off,
|
||||
base: src,
|
||||
},
|
||||
LI::Sb {
|
||||
src: temp,
|
||||
offset: dest_offset + off,
|
||||
base: dest,
|
||||
},
|
||||
]);
|
||||
len -= 1;
|
||||
off += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,19 +76,11 @@ pub fn compile(program: IRLProgram) -> (Vec<u8>, Option<Addr>) {
|
||||
stack_rva = Some(stack_len);
|
||||
stack_len += align(&f.ret_size);
|
||||
}
|
||||
v.push(LI::Addi {
|
||||
dest: sp,
|
||||
src: sp,
|
||||
imm: -stack_len,
|
||||
});
|
||||
v.push(LI::addi(sp, sp, -stack_len));
|
||||
let has_stack = stack_len > 0;
|
||||
if has_stack {
|
||||
if let Some(stack_ra) = stack_ra {
|
||||
v.push(LI::Sd {
|
||||
src: ra,
|
||||
offset: stack_ra,
|
||||
base: sp,
|
||||
});
|
||||
v.push(LI::sd(ra, stack_ra, sp));
|
||||
}
|
||||
}
|
||||
for i in &f.instructions {
|
||||
@@ -144,11 +93,7 @@ pub fn compile(program: IRLProgram) -> (Vec<u8>, Option<Addr>) {
|
||||
dest: t0,
|
||||
src: *src,
|
||||
},
|
||||
LI::Sd {
|
||||
src: t0,
|
||||
offset: stack[dest] + *offset as i32,
|
||||
base: sp,
|
||||
},
|
||||
LI::sd(t0, stack[dest] + *offset as i32, sp),
|
||||
]);
|
||||
}
|
||||
IRI::LoadData {
|
||||
@@ -167,16 +112,8 @@ pub fn compile(program: IRLProgram) -> (Vec<u8>, Option<Addr>) {
|
||||
let mut offset = 0;
|
||||
if let Some((dest, s)) = dest {
|
||||
offset -= align(s);
|
||||
v.push(LI::Addi {
|
||||
dest: t0,
|
||||
src: sp,
|
||||
imm: stack[&dest],
|
||||
});
|
||||
v.push(LI::Sd {
|
||||
src: t0,
|
||||
offset,
|
||||
base: sp,
|
||||
})
|
||||
v.push(LI::addi(t0, sp, stack[&dest]));
|
||||
v.push(LI::sd(t0, offset, sp))
|
||||
}
|
||||
for (arg, s) in args {
|
||||
let bs = align(s);
|
||||
@@ -187,11 +124,7 @@ pub fn compile(program: IRLProgram) -> (Vec<u8>, Option<Addr>) {
|
||||
}
|
||||
IRI::AsmBlock { args, instructions } => {
|
||||
for (reg, var) in args {
|
||||
v.push(LI::Addi {
|
||||
dest: *reg,
|
||||
imm: stack[var],
|
||||
src: sp,
|
||||
});
|
||||
v.push(LI::addi(*reg, sp, stack[var]));
|
||||
}
|
||||
fn r(rr: RegRef) -> Reg {
|
||||
match rr {
|
||||
@@ -208,21 +141,71 @@ pub fn compile(program: IRLProgram) -> (Vec<u8>, Option<Addr>) {
|
||||
src: r(src),
|
||||
}),
|
||||
AI::La { dest, src } => todo!(),
|
||||
AI::Ld { dest, base, offset } => v.push(LI::Ld {
|
||||
AI::Load {
|
||||
width,
|
||||
dest,
|
||||
base,
|
||||
offset,
|
||||
} => v.push(LI::Load {
|
||||
width,
|
||||
dest: r(dest),
|
||||
offset: offset as i32,
|
||||
base: r(base),
|
||||
}),
|
||||
AI::Sd { src, base, offset } => v.push(LI::Sd {
|
||||
AI::Store {
|
||||
width,
|
||||
src,
|
||||
base,
|
||||
offset,
|
||||
} => v.push(LI::Store {
|
||||
width,
|
||||
src: r(src),
|
||||
offset: offset as i32,
|
||||
base: r(base),
|
||||
}),
|
||||
AI::Add { dest, src1, src2 } => v.push(LI::Add {
|
||||
AI::Op {
|
||||
op,
|
||||
dest,
|
||||
src1,
|
||||
src2,
|
||||
} => v.push(LI::Op {
|
||||
op,
|
||||
dest: r(dest),
|
||||
src1: r(src1),
|
||||
src2: r(src2),
|
||||
}),
|
||||
AI::OpF7 {
|
||||
op,
|
||||
funct,
|
||||
dest,
|
||||
src1,
|
||||
src2,
|
||||
} => v.push(LI::OpF7 {
|
||||
op,
|
||||
funct,
|
||||
dest: r(dest),
|
||||
src1: r(src1),
|
||||
src2: r(src2),
|
||||
}),
|
||||
AI::OpImm { op, dest, src, imm } => v.push(LI::OpImm {
|
||||
op,
|
||||
dest: r(dest),
|
||||
src: r(src),
|
||||
imm: imm as i32,
|
||||
}),
|
||||
AI::OpImmF7 {
|
||||
op,
|
||||
funct,
|
||||
dest,
|
||||
src,
|
||||
imm,
|
||||
} => v.push(LI::OpImmF7 {
|
||||
op,
|
||||
funct,
|
||||
dest: r(dest),
|
||||
src: r(src),
|
||||
imm: imm as i32,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,28 +213,16 @@ pub fn compile(program: IRLProgram) -> (Vec<u8>, Option<Addr>) {
|
||||
let Some(rva) = stack_rva else {
|
||||
panic!("no return value address on stack!")
|
||||
};
|
||||
v.push(LI::Ld {
|
||||
dest: t0,
|
||||
offset: rva,
|
||||
base: sp,
|
||||
});
|
||||
v.push(LI::ld(t0, rva, sp));
|
||||
mov_mem(&mut v, sp, stack[src], t0, 0, t1, align(&f.ret_size) as u32);
|
||||
}
|
||||
}
|
||||
}
|
||||
if has_stack {
|
||||
if let Some(stack_ra) = stack_ra {
|
||||
v.push(LI::Ld {
|
||||
dest: ra,
|
||||
offset: stack_ra,
|
||||
base: sp,
|
||||
});
|
||||
v.push(LI::ld(ra, stack_ra, sp));
|
||||
}
|
||||
v.push(LI::Addi {
|
||||
dest: sp,
|
||||
src: sp,
|
||||
imm: stack_len,
|
||||
});
|
||||
v.push(LI::addi(sp, sp, stack_len));
|
||||
}
|
||||
v.push(LI::Ret);
|
||||
fns.push((v, *sym));
|
||||
|
||||
@@ -1,24 +1,96 @@
|
||||
use super::Funct3;
|
||||
use crate::{ir::Len, util::Bits32};
|
||||
|
||||
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 type Funct3 = Bits32<2, 0>;
|
||||
pub type Funct7 = Bits32<6, 0>;
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Op {
|
||||
Add = 0b000,
|
||||
Sl = 0b001,
|
||||
Slt = 0b010,
|
||||
Sltu = 0b011,
|
||||
Xor = 0b100,
|
||||
Sr = 0b101,
|
||||
Or = 0b110,
|
||||
And = 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);
|
||||
impl Op {
|
||||
pub const fn code(&self) -> Funct3 {
|
||||
Funct3::new(*self as u32)
|
||||
}
|
||||
pub const fn str(&self) -> &str {
|
||||
match self {
|
||||
Op::Add => "add",
|
||||
Op::Sl => "sl",
|
||||
Op::Slt => "slt",
|
||||
Op::Sltu => "sltu",
|
||||
Op::Xor => "xor",
|
||||
Op::Sr => "sr",
|
||||
Op::Or => "or",
|
||||
Op::And => "and",
|
||||
}
|
||||
}
|
||||
pub fn fstr(&self, funct: Funct7) -> String {
|
||||
match (self, funct) {
|
||||
(Op::Add, funct7::ADD) => "add",
|
||||
(Op::Add, funct7::SUB) => "sub",
|
||||
(Op::Sl, funct7::LOGICAL) => "sll",
|
||||
(Op::Sr, funct7::LOGICAL) => "srl",
|
||||
(Op::Sr, funct7::ARITHMETIC) => "sra",
|
||||
other => return self.str().to_string() + "?"
|
||||
}.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub mod funct7 {
|
||||
use super::Funct7;
|
||||
|
||||
pub const LOGICAL: Funct7 = Funct7::new(0b0000000);
|
||||
pub const ARITHMETIC: Funct7 = Funct7::new(0b0100000);
|
||||
pub const ADD: Funct7 = Funct7::new(0b0000000);
|
||||
pub const SUB: Funct7 = Funct7::new(0b0100000);
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Width {
|
||||
B = 0b000,
|
||||
H = 0b001,
|
||||
W = 0b010,
|
||||
D = 0b011,
|
||||
BU = 0b100,
|
||||
HU = 0b101,
|
||||
WU = 0b110,
|
||||
}
|
||||
|
||||
impl Width {
|
||||
pub const MAIN: [Self; 4] = [Self::B, Self::H, Self::W, Self::D];
|
||||
|
||||
pub const fn code(&self) -> Funct3 {
|
||||
Funct3::new(*self as u32)
|
||||
}
|
||||
pub const fn len(&self) -> Len {
|
||||
match self {
|
||||
Width::B => 1,
|
||||
Width::H => 2,
|
||||
Width::W => 4,
|
||||
Width::D => 8,
|
||||
Width::BU => 1,
|
||||
Width::HU => 2,
|
||||
Width::WU => 4,
|
||||
}
|
||||
}
|
||||
pub const fn str(&self) -> &str {
|
||||
match self {
|
||||
Width::B => "b",
|
||||
Width::H => "h",
|
||||
Width::W => "w",
|
||||
Width::D => "d",
|
||||
Width::BU => "bu",
|
||||
Width::HU => "hu",
|
||||
Width::WU => "wu",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ mod single;
|
||||
|
||||
use crate::util::BitsI32;
|
||||
use base::*;
|
||||
use funct::{op::*, width};
|
||||
use opcode::*;
|
||||
use single::*;
|
||||
|
||||
pub use asm::*;
|
||||
pub use compile::*;
|
||||
pub use reg::*;
|
||||
pub use funct::*;
|
||||
|
||||
@@ -14,46 +14,31 @@ 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 lh(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||
i_type(offset.to_u(), base, width::H, 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 load(width: Width, dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||
i_type(offset.to_u(), base, width.code(), dest, LOAD)
|
||||
}
|
||||
|
||||
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 sb(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||
s_type(src, base, width::B, offset.to_u(), STORE)
|
||||
}
|
||||
pub const fn sh(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||
s_type(src, base, width::H, 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 store(width: Width, src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||
s_type(src, base, width.code(), 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 opr(op: Op, dest: Reg, src1: Reg, src2: Reg) -> I {
|
||||
r_type(Bits32::new(0), src2, src1, op.code(), 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 oprf7(op: Op, funct: Funct7, dest: Reg, src1: Reg, src2: Reg) -> I {
|
||||
r_type(funct, src2, src1, op.code(), dest, 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 opi(op: Op, dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> I {
|
||||
i_type(imm.to_u(), src, op.code(), 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 opif7(op: Op, funct: Funct7, dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I {
|
||||
i_type(
|
||||
Bits32::new(imm.to_u().val() + (funct.val() << 5)),
|
||||
src,
|
||||
op.code(),
|
||||
dest,
|
||||
IMM_OP,
|
||||
)
|
||||
}
|
||||
pub const fn jal(dest: Reg, offset: BitsI32<20, 1>) -> I {
|
||||
j_type(offset.to_u(), dest, JAL)
|
||||
|
||||
@@ -15,21 +15,44 @@ pub enum RV64Instruction {
|
||||
dest: RegRef,
|
||||
src: VarInst,
|
||||
},
|
||||
Ld {
|
||||
Load {
|
||||
width: Width,
|
||||
dest: RegRef,
|
||||
offset: i64,
|
||||
base: RegRef,
|
||||
},
|
||||
Sd {
|
||||
Store {
|
||||
width: Width,
|
||||
src: RegRef,
|
||||
offset: i64,
|
||||
base: RegRef,
|
||||
},
|
||||
Add {
|
||||
Op {
|
||||
op: Op,
|
||||
dest: RegRef,
|
||||
src1: RegRef,
|
||||
src2: RegRef,
|
||||
},
|
||||
OpF7 {
|
||||
op: Op,
|
||||
funct: Funct7,
|
||||
dest: RegRef,
|
||||
src1: RegRef,
|
||||
src2: RegRef,
|
||||
},
|
||||
OpImm {
|
||||
op: Op,
|
||||
dest: RegRef,
|
||||
src: RegRef,
|
||||
imm: i64,
|
||||
},
|
||||
OpImmF7 {
|
||||
op: Op,
|
||||
funct: Funct7,
|
||||
dest: RegRef,
|
||||
src: RegRef,
|
||||
imm: i64,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@@ -54,9 +77,41 @@ impl std::fmt::Debug for RV64Instruction {
|
||||
Self::Li { dest, imm } => write!(f, "li {dest:?}, {imm:?}"),
|
||||
Self::Mv { dest, src } => write!(f, "mv {dest:?}, {src:?}"),
|
||||
Self::La { dest, src } => write!(f, "la {dest:?}, {src:?}"),
|
||||
Self::Ld { dest, offset, base } => write!(f, "ld {dest:?}, {offset}({base:?})"),
|
||||
Self::Sd { src, offset, base } => write!(f, "sd {src:?}, {offset}({base:?})"),
|
||||
Self::Add { dest, src1, src2 } => write!(f, "add {dest:?}, {src1:?}, {src2:?}"),
|
||||
Self::Load {
|
||||
width,
|
||||
dest,
|
||||
offset,
|
||||
base,
|
||||
} => write!(f, "l{} {dest:?}, {offset}({base:?})", width.str()),
|
||||
Self::Store {
|
||||
width,
|
||||
src,
|
||||
offset,
|
||||
base,
|
||||
} => write!(f, "s{} {src:?}, {offset}({base:?})", width.str()),
|
||||
Self::Op {
|
||||
op,
|
||||
dest,
|
||||
src1,
|
||||
src2,
|
||||
} => write!(f, "{} {dest:?}, {src1:?}, {src2:?}", op.str()),
|
||||
Self::OpF7 {
|
||||
op,
|
||||
funct,
|
||||
dest,
|
||||
src1,
|
||||
src2,
|
||||
} => write!(f, "{} {dest:?}, {src1:?}, {src2:?}", op.fstr(*funct)),
|
||||
Self::OpImm { op, dest, src, imm } => {
|
||||
write!(f, "{}i {dest:?}, {src:?}, {imm}", op.str())
|
||||
}
|
||||
Self::OpImmF7 {
|
||||
op,
|
||||
funct,
|
||||
dest,
|
||||
src,
|
||||
imm,
|
||||
} => write!(f, "{}i {dest:?}, {src:?}, {imm}", op.fstr(*funct)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,95 @@ use crate::{
|
||||
impl RV64Instruction {
|
||||
pub fn parse(inst: &PInstruction, ctx: &mut FnLowerCtx) -> Option<Self> {
|
||||
let args = &inst.args[..];
|
||||
Some(match &**inst.op.inner.as_ref()? {
|
||||
let opstr = &**inst.op.inner.as_ref()?;
|
||||
let op = |ctx: &mut FnLowerCtx<'_, '_>, op: Op| -> Option<Self> {
|
||||
let [dest, src1, src2] = args else {
|
||||
ctx.err(format!("{opstr} requires 3 arguments"));
|
||||
return None;
|
||||
};
|
||||
let dest = RegRef::from_arg(dest, ctx)?;
|
||||
let src1 = RegRef::from_arg(src1, ctx)?;
|
||||
let src2 = RegRef::from_arg(src2, ctx)?;
|
||||
Some(Self::Op {
|
||||
op,
|
||||
dest,
|
||||
src1,
|
||||
src2,
|
||||
})
|
||||
};
|
||||
let opi = |ctx: &mut FnLowerCtx<'_, '_>, op: Op| -> Option<Self> {
|
||||
let [dest, src, imm] = args else {
|
||||
ctx.err(format!("{opstr} requires 3 arguments"));
|
||||
return None;
|
||||
};
|
||||
let dest = RegRef::from_arg(dest, ctx)?;
|
||||
let src = RegRef::from_arg(src, ctx)?;
|
||||
let imm = i64_from_arg(imm, ctx)?;
|
||||
Some(Self::OpImm { op, dest, src, imm })
|
||||
};
|
||||
let opf7 = |ctx: &mut FnLowerCtx<'_, '_>, op: Op, funct: Funct7| -> Option<Self> {
|
||||
let [dest, src1, src2] = args else {
|
||||
ctx.err(format!("{opstr} requires 3 arguments"));
|
||||
return None;
|
||||
};
|
||||
let dest = RegRef::from_arg(dest, ctx)?;
|
||||
let src1 = RegRef::from_arg(src1, ctx)?;
|
||||
let src2 = RegRef::from_arg(src2, ctx)?;
|
||||
Some(Self::OpF7 {
|
||||
op,
|
||||
funct,
|
||||
dest,
|
||||
src1,
|
||||
src2,
|
||||
})
|
||||
};
|
||||
let opif7 = |ctx: &mut FnLowerCtx<'_, '_>, op: Op, funct: Funct7| -> Option<Self> {
|
||||
let [dest, src, imm] = args else {
|
||||
ctx.err(format!("{opstr} requires 3 arguments"));
|
||||
return None;
|
||||
};
|
||||
let dest = RegRef::from_arg(dest, ctx)?;
|
||||
let src = RegRef::from_arg(src, ctx)?;
|
||||
let imm = i64_from_arg(imm, ctx)?;
|
||||
Some(Self::OpImmF7 {
|
||||
op,
|
||||
funct,
|
||||
dest,
|
||||
src,
|
||||
imm,
|
||||
})
|
||||
};
|
||||
let store = |ctx: &mut FnLowerCtx<'_, '_>, width: Width| -> Option<Self> {
|
||||
let [src, offset, base] = args else {
|
||||
ctx.err(format!("{opstr} requires 3 arguments"));
|
||||
return None;
|
||||
};
|
||||
let src = RegRef::from_arg(src, ctx)?;
|
||||
let offset = i64_from_arg(offset, ctx)?;
|
||||
let base = RegRef::from_arg(base, ctx)?;
|
||||
Some(Self::Store {
|
||||
width,
|
||||
src,
|
||||
offset,
|
||||
base,
|
||||
})
|
||||
};
|
||||
let load = |ctx: &mut FnLowerCtx<'_, '_>, width: Width| -> Option<Self> {
|
||||
let [dest, offset, base] = args else {
|
||||
ctx.err("ld requires 3 arguments".to_string());
|
||||
return None;
|
||||
};
|
||||
let dest = RegRef::from_arg(dest, ctx)?;
|
||||
let offset = i64_from_arg(offset, ctx)?;
|
||||
let base = RegRef::from_arg(base, ctx)?;
|
||||
Some(Self::Load {
|
||||
width,
|
||||
dest,
|
||||
offset,
|
||||
base,
|
||||
})
|
||||
};
|
||||
Some(match opstr {
|
||||
"ecall" => Self::Ecall,
|
||||
"li" => {
|
||||
let [dest, imm] = args else {
|
||||
@@ -30,26 +118,6 @@ impl RV64Instruction {
|
||||
let src = arg_to_var(src, ctx)?;
|
||||
Self::La { dest, src }
|
||||
}
|
||||
"ld" => {
|
||||
let [dest, offset, base] = args else {
|
||||
ctx.err("ld requires 3 arguments".to_string());
|
||||
return None;
|
||||
};
|
||||
let dest = RegRef::from_arg(dest, ctx)?;
|
||||
let offset = i64_from_arg(offset, ctx)?;
|
||||
let base = RegRef::from_arg(base, ctx)?;
|
||||
Self::Ld { dest, offset, base }
|
||||
}
|
||||
"sd" => {
|
||||
let [src, offset, base] = args else {
|
||||
ctx.err("sd requires 3 arguments".to_string());
|
||||
return None;
|
||||
};
|
||||
let src = RegRef::from_arg(src, ctx)?;
|
||||
let offset = i64_from_arg(offset, ctx)?;
|
||||
let base = RegRef::from_arg(base, ctx)?;
|
||||
Self::Sd { src, offset, base }
|
||||
}
|
||||
"mv" => {
|
||||
let [dest, src] = args else {
|
||||
ctx.err("la requires 2 arguments".to_string());
|
||||
@@ -59,16 +127,42 @@ impl RV64Instruction {
|
||||
let src = RegRef::from_arg(src, ctx)?;
|
||||
Self::Mv { dest, src }
|
||||
}
|
||||
"add" => {
|
||||
let [dest, src1, src2] = args else {
|
||||
ctx.err("add requires 3 arguments".to_string());
|
||||
return None;
|
||||
};
|
||||
let dest = RegRef::from_arg(dest, ctx)?;
|
||||
let src1 = RegRef::from_arg(src1, ctx)?;
|
||||
let src2 = RegRef::from_arg(src2, ctx)?;
|
||||
Self::Add { dest, src1, src2 }
|
||||
}
|
||||
|
||||
"lb" => load(ctx, Width::B)?,
|
||||
"lh" => load(ctx, Width::H)?,
|
||||
"lw" => load(ctx, Width::W)?,
|
||||
"ld" => load(ctx, Width::D)?,
|
||||
"lbu" => load(ctx, Width::BU)?,
|
||||
"lhu" => load(ctx, Width::HU)?,
|
||||
"lwu" => load(ctx, Width::WU)?,
|
||||
|
||||
"sb" => store(ctx, Width::B)?,
|
||||
"sh" => store(ctx, Width::H)?,
|
||||
"sw" => store(ctx, Width::W)?,
|
||||
"sd" => store(ctx, Width::D)?,
|
||||
|
||||
"addi" => opi(ctx, Op::Add)?,
|
||||
"slti" => opi(ctx, Op::Slt)?,
|
||||
"sltiu" => opi(ctx, Op::Sltu)?,
|
||||
"xori" => opi(ctx, Op::Xor)?,
|
||||
"ori" => opi(ctx, Op::Or)?,
|
||||
"andi" => opi(ctx, Op::And)?,
|
||||
|
||||
"slli" => opif7(ctx, Op::Sl, funct7::LOGICAL)?,
|
||||
"srli" => opif7(ctx, Op::Sr, funct7::LOGICAL)?,
|
||||
"srla" => opif7(ctx, Op::Sr, funct7::ARITHMETIC)?,
|
||||
|
||||
"add" => opf7(ctx, Op::Add, funct7::ADD)?,
|
||||
"sub" => opf7(ctx, Op::Add, funct7::SUB)?,
|
||||
"sll" => op(ctx, Op::Sl)?,
|
||||
"slt" => op(ctx, Op::Slt)?,
|
||||
"sltu" => op(ctx, Op::Sltu)?,
|
||||
"xor" => op(ctx, Op::Xor)?,
|
||||
"srl" => opf7(ctx, Op::Sr, funct7::LOGICAL)?,
|
||||
"sra" => opf7(ctx, Op::Sr, funct7::ARITHMETIC)?,
|
||||
"or" => op(ctx, Op::Or)?,
|
||||
"and" => op(ctx, Op::And)?,
|
||||
|
||||
w => {
|
||||
ctx.err_at(inst.op.span, format!("Unknown instruction '{}'", w));
|
||||
return None;
|
||||
@@ -92,9 +186,7 @@ impl RegRef {
|
||||
pub fn from_arg(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<Self> {
|
||||
Some(match node.inner.as_ref()? {
|
||||
PAsmArg::Value(node) => {
|
||||
let Some(reg) = Reg::from_ident(node, ctx) else {
|
||||
return None;
|
||||
};
|
||||
let reg = Reg::from_ident(node, ctx)?;
|
||||
Self::Reg(reg)
|
||||
}
|
||||
PAsmArg::Ref(node) => Self::Var(ctx.get_var(node)?),
|
||||
@@ -115,7 +207,7 @@ impl Reg {
|
||||
|
||||
fn i64_from_arg(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<i64> {
|
||||
let PAsmArg::Value(node) = node.inner.as_ref()? else {
|
||||
ctx.err_at(node.span, format!("Expected an i64, found reference"));
|
||||
ctx.err_at(node.span, "Expected an i64, found reference".to_string());
|
||||
return None;
|
||||
};
|
||||
let word = node.inner.as_ref()?;
|
||||
|
||||
@@ -10,9 +10,9 @@ pub const fn mask(h: u8, l: u8) -> u32 {
|
||||
base_mask(h - l) << l
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Bits32<const H: u8, const L: u8>(u32);
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct BitsI32<const H: u8, const L: u8>(u32);
|
||||
|
||||
impl<const H: u8, const L: u8> Bits32<H, L> {
|
||||
|
||||
Reference in New Issue
Block a user