mirror of
https://github.com/Noratrieb/rustv32i.git
synced 2026-01-16 14:25:02 +01:00
more compressed instructions
This commit is contained in:
parent
dd2e4001fd
commit
957b6a263a
3 changed files with 265 additions and 55 deletions
14
src/emu.rs
14
src/emu.rs
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::inst::{AmoOp, Inst, InstCode};
|
use crate::inst::{AmoOp, Inst, InstCode, IsCompressed};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
ops::{Index, IndexMut},
|
ops::{Index, IndexMut},
|
||||||
|
|
@ -162,12 +162,16 @@ impl Emulator {
|
||||||
|
|
||||||
fn step(&mut self) -> Result<(), Status> {
|
fn step(&mut self) -> Result<(), Status> {
|
||||||
let code = self.mem.load_u32(self.pc)?;
|
let code = self.mem.load_u32(self.pc)?;
|
||||||
let inst = Inst::decode(code)?;
|
let (inst, was_compressed) = Inst::decode(code)?;
|
||||||
|
|
||||||
if self.debug {
|
if self.debug {
|
||||||
println!("executing 0x{:x} {inst:?}", self.pc);
|
println!("executing 0x{:x} {inst:?}", self.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let next_pc = self.pc.wrapping_add(match was_compressed {
|
||||||
|
IsCompressed::Yes => 2,
|
||||||
|
IsCompressed::No => 4,
|
||||||
|
});
|
||||||
let mut jumped = false;
|
let mut jumped = false;
|
||||||
|
|
||||||
match inst {
|
match inst {
|
||||||
|
|
@ -175,13 +179,13 @@ impl Emulator {
|
||||||
Inst::Auipc { uimm, dest } => self[dest] = self.pc.wrapping_add(uimm),
|
Inst::Auipc { uimm, dest } => self[dest] = self.pc.wrapping_add(uimm),
|
||||||
Inst::Jal { offset, dest } => {
|
Inst::Jal { offset, dest } => {
|
||||||
let target = self.pc.wrapping_add(offset);
|
let target = self.pc.wrapping_add(offset);
|
||||||
self[dest] = self.pc.wrapping_add(4);
|
self[dest] = next_pc;
|
||||||
self.set_pc(target)?;
|
self.set_pc(target)?;
|
||||||
jumped = true;
|
jumped = true;
|
||||||
}
|
}
|
||||||
Inst::Jalr { offset, base, dest } => {
|
Inst::Jalr { offset, base, dest } => {
|
||||||
let target = self[base].wrapping_add(offset) & !1;
|
let target = self[base].wrapping_add(offset) & !1;
|
||||||
self[dest] = self.pc.wrapping_add(4);
|
self[dest] = next_pc;
|
||||||
self.set_pc(target)?;
|
self.set_pc(target)?;
|
||||||
jumped = true;
|
jumped = true;
|
||||||
}
|
}
|
||||||
|
|
@ -406,7 +410,7 @@ impl Emulator {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !jumped {
|
if !jumped {
|
||||||
self.set_pc(self.pc + 4)?;
|
self.set_pc(next_pc)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
299
src/inst.rs
299
src/inst.rs
|
|
@ -5,77 +5,127 @@ use std::ops::RangeInclusive;
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub enum Inst {
|
pub enum Inst {
|
||||||
|
/// Load Upper Immediate
|
||||||
Lui { uimm: u32, dest: Reg },
|
Lui { uimm: u32, dest: Reg },
|
||||||
|
/// Add Upper Immediate to PC
|
||||||
Auipc { uimm: u32, dest: Reg },
|
Auipc { uimm: u32, dest: Reg },
|
||||||
|
|
||||||
|
/// Jump And Link
|
||||||
Jal { offset: u32, dest: Reg },
|
Jal { offset: u32, dest: Reg },
|
||||||
|
/// Jump And Link Register (indirect)
|
||||||
Jalr { offset: u32, base: Reg, dest: Reg },
|
Jalr { offset: u32, base: Reg, dest: Reg },
|
||||||
|
|
||||||
|
/// Branch Equal
|
||||||
Beq { offset: u32, src1: Reg, src2: Reg },
|
Beq { offset: u32, src1: Reg, src2: Reg },
|
||||||
|
/// Branch Not Equal
|
||||||
Bne { offset: u32, src1: Reg, src2: Reg },
|
Bne { offset: u32, src1: Reg, src2: Reg },
|
||||||
|
/// Branch Less Than (signed)
|
||||||
Blt { offset: u32, src1: Reg, src2: Reg },
|
Blt { offset: u32, src1: Reg, src2: Reg },
|
||||||
|
/// Branch Greater or Equal (signed)
|
||||||
Bge { offset: u32, src1: Reg, src2: Reg },
|
Bge { offset: u32, src1: Reg, src2: Reg },
|
||||||
|
/// Branch Less Than Unsigned
|
||||||
Bltu { offset: u32, src1: Reg, src2: Reg },
|
Bltu { offset: u32, src1: Reg, src2: Reg },
|
||||||
|
/// Branch Greater or Equal Unsigned
|
||||||
Bgeu { offset: u32, src1: Reg, src2: Reg },
|
Bgeu { offset: u32, src1: Reg, src2: Reg },
|
||||||
|
|
||||||
|
/// Load Byte (sign-ext)
|
||||||
Lb { offset: u32, dest: Reg, base: Reg },
|
Lb { offset: u32, dest: Reg, base: Reg },
|
||||||
|
/// Load Unsigned Byte (zero-ext)
|
||||||
Lbu { offset: u32, dest: Reg, base: Reg },
|
Lbu { offset: u32, dest: Reg, base: Reg },
|
||||||
|
/// Load Half (sign-ext)
|
||||||
Lh { offset: u32, dest: Reg, base: Reg },
|
Lh { offset: u32, dest: Reg, base: Reg },
|
||||||
|
/// Load Unsigned Half (zero-ext)
|
||||||
Lhu { offset: u32, dest: Reg, base: Reg },
|
Lhu { offset: u32, dest: Reg, base: Reg },
|
||||||
|
/// Load Word
|
||||||
Lw { offset: u32, dest: Reg, base: Reg },
|
Lw { offset: u32, dest: Reg, base: Reg },
|
||||||
|
|
||||||
|
/// Store Byte
|
||||||
Sb { offset: u32, src: Reg, base: Reg },
|
Sb { offset: u32, src: Reg, base: Reg },
|
||||||
|
/// Store Half
|
||||||
Sh { offset: u32, src: Reg, base: Reg },
|
Sh { offset: u32, src: Reg, base: Reg },
|
||||||
|
/// Store Word
|
||||||
Sw { offset: u32, src: Reg, base: Reg },
|
Sw { offset: u32, src: Reg, base: Reg },
|
||||||
|
|
||||||
|
/// Add Immediate
|
||||||
Addi { imm: u32, dest: Reg, src1: Reg },
|
Addi { imm: u32, dest: Reg, src1: Reg },
|
||||||
|
/// Set Less Than Immediate (signed)
|
||||||
Slti { imm: u32, dest: Reg, src1: Reg },
|
Slti { imm: u32, dest: Reg, src1: Reg },
|
||||||
|
/// Set Less Than Immediate Unsigned
|
||||||
Sltiu { imm: u32, dest: Reg, src1: Reg },
|
Sltiu { imm: u32, dest: Reg, src1: Reg },
|
||||||
|
/// XOR Immediate
|
||||||
Xori { imm: u32, dest: Reg, src1: Reg },
|
Xori { imm: u32, dest: Reg, src1: Reg },
|
||||||
|
/// OR Immediate
|
||||||
Ori { imm: u32, dest: Reg, src1: Reg },
|
Ori { imm: u32, dest: Reg, src1: Reg },
|
||||||
|
/// AND Immediate
|
||||||
Andi { imm: u32, dest: Reg, src1: Reg },
|
Andi { imm: u32, dest: Reg, src1: Reg },
|
||||||
|
/// Shift Left Logical Immediate
|
||||||
Slli { imm: u32, dest: Reg, src1: Reg },
|
Slli { imm: u32, dest: Reg, src1: Reg },
|
||||||
|
/// Shift Right Logical Immediate (unsigned)
|
||||||
Srli { imm: u32, dest: Reg, src1: Reg },
|
Srli { imm: u32, dest: Reg, src1: Reg },
|
||||||
|
/// Shift Right Arithmetic Immediate (signed)
|
||||||
Srai { imm: u32, dest: Reg, src1: Reg },
|
Srai { imm: u32, dest: Reg, src1: Reg },
|
||||||
|
|
||||||
|
/// Add
|
||||||
Add { dest: Reg, src1: Reg, src2: Reg },
|
Add { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Subtract
|
||||||
Sub { dest: Reg, src1: Reg, src2: Reg },
|
Sub { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Shift Left Logical
|
||||||
Sll { dest: Reg, src1: Reg, src2: Reg },
|
Sll { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Set Less Than (signed)
|
||||||
Slt { dest: Reg, src1: Reg, src2: Reg },
|
Slt { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Set Less Than Unsigned
|
||||||
Sltu { dest: Reg, src1: Reg, src2: Reg },
|
Sltu { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// XOR
|
||||||
Xor { dest: Reg, src1: Reg, src2: Reg },
|
Xor { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Shift Right Logical (unsigned)
|
||||||
Srl { dest: Reg, src1: Reg, src2: Reg },
|
Srl { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Shift Right Arithmetic (unsigned)
|
||||||
Sra { dest: Reg, src1: Reg, src2: Reg },
|
Sra { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// OR
|
||||||
Or { dest: Reg, src1: Reg, src2: Reg },
|
Or { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// AND
|
||||||
And { dest: Reg, src1: Reg, src2: Reg },
|
And { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Memory Fence
|
||||||
Fence { fence: Fence },
|
Fence { fence: Fence },
|
||||||
|
|
||||||
|
/// ECALL, call into environment
|
||||||
Ecall,
|
Ecall,
|
||||||
|
/// EBREAK, break into debugger
|
||||||
Ebreak,
|
Ebreak,
|
||||||
|
|
||||||
// M
|
// ------------- M extension -------------
|
||||||
|
/// Multiply
|
||||||
Mul { dest: Reg, src1: Reg, src2: Reg },
|
Mul { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Mul Upper Half Signed-Signed
|
||||||
Mulh { dest: Reg, src1: Reg, src2: Reg },
|
Mulh { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Mul Upper Half Signed-Unsigned
|
||||||
Mulhsu { dest: Reg, src1: Reg, src2: Reg },
|
Mulhsu { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Mul Upper Half Unsigned-Unsigned
|
||||||
Mulhu { dest: Reg, src1: Reg, src2: Reg },
|
Mulhu { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Divide (signed)
|
||||||
Div { dest: Reg, src1: Reg, src2: Reg },
|
Div { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Divide Unsigned
|
||||||
Divu { dest: Reg, src1: Reg, src2: Reg },
|
Divu { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Remainder (signed)
|
||||||
Rem { dest: Reg, src1: Reg, src2: Reg },
|
Rem { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
/// Remainder Unsigned
|
||||||
Remu { dest: Reg, src1: Reg, src2: Reg },
|
Remu { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
|
||||||
// A
|
// ------------- A extension -------------
|
||||||
|
/// Load-Reserved Word
|
||||||
LrW {
|
LrW {
|
||||||
order: AmoOrdering,
|
order: AmoOrdering,
|
||||||
dest: Reg,
|
dest: Reg,
|
||||||
addr: Reg,
|
addr: Reg,
|
||||||
},
|
},
|
||||||
|
/// Store-Conditional Word
|
||||||
ScW {
|
ScW {
|
||||||
order: AmoOrdering,
|
order: AmoOrdering,
|
||||||
dest: Reg,
|
dest: Reg,
|
||||||
addr: Reg,
|
addr: Reg,
|
||||||
src: Reg,
|
src: Reg,
|
||||||
},
|
},
|
||||||
|
/// Atomic Memory Operation
|
||||||
AmoW {
|
AmoW {
|
||||||
order: AmoOrdering,
|
order: AmoOrdering,
|
||||||
op: AmoOp,
|
op: AmoOp,
|
||||||
|
|
@ -337,7 +387,7 @@ impl Display for AmoOp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_extend32(value: u32, size: u32) -> u32 {
|
fn sign_extend(value: u32, size: u32) -> u32 {
|
||||||
assert!(size <= u32::BITS);
|
assert!(size <= u32::BITS);
|
||||||
let sign = value >> (size - 1);
|
let sign = value >> (size - 1);
|
||||||
let imm = if sign == 1 {
|
let imm = if sign == 1 {
|
||||||
|
|
@ -347,16 +397,6 @@ fn sign_extend32(value: u32, size: u32) -> u32 {
|
||||||
};
|
};
|
||||||
imm
|
imm
|
||||||
}
|
}
|
||||||
fn sign_extend16(value: u16, size: u16) -> u16 {
|
|
||||||
assert!(size <= u16::BITS as u16);
|
|
||||||
let sign = value >> (size - 1);
|
|
||||||
let imm = if sign == 1 {
|
|
||||||
(u16::MAX << size) | value
|
|
||||||
} else {
|
|
||||||
value
|
|
||||||
};
|
|
||||||
imm
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct InstCode(u32);
|
pub struct InstCode(u32);
|
||||||
|
|
@ -383,7 +423,7 @@ impl InstCode {
|
||||||
let this_size = from.end() - from.start() + 1;
|
let this_size = from.end() - from.start() + 1;
|
||||||
size = size.max(*to + this_size);
|
size = size.max(*to + this_size);
|
||||||
}
|
}
|
||||||
sign_extend32(imm, size)
|
sign_extend(imm, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opcode(self) -> u32 {
|
fn opcode(self) -> u32 {
|
||||||
|
|
@ -431,39 +471,55 @@ impl Debug for InstCode {
|
||||||
pub struct InstCodeC(u16);
|
pub struct InstCodeC(u16);
|
||||||
|
|
||||||
impl InstCodeC {
|
impl InstCodeC {
|
||||||
fn extract(self, range: RangeInclusive<u16>) -> u16 {
|
fn extract(self, range: RangeInclusive<u32>) -> u32 {
|
||||||
let end_span = 32 - (range.end() + 1);
|
let end_span = u16::BITS - (range.end() + 1);
|
||||||
(self.0 << (end_span)) >> (end_span + range.start())
|
((self.0 << (end_span)) >> (end_span + range.start())) as u32
|
||||||
}
|
}
|
||||||
fn immediate_u(self, mappings: &[(RangeInclusive<u16>, u16)]) -> u16 {
|
fn immediate_u(self, mappings: &[(RangeInclusive<u32>, u32)]) -> u32 {
|
||||||
let mut imm = 0;
|
let mut imm = 0;
|
||||||
for (from, to) in mappings {
|
for (from, to) in mappings {
|
||||||
let value = self.extract(from.clone());
|
let value = self.extract(from.clone());
|
||||||
imm |= value << to;
|
imm |= value << to;
|
||||||
}
|
}
|
||||||
imm
|
imm as u32
|
||||||
}
|
}
|
||||||
|
fn immediate_s(self, mappings: &[(RangeInclusive<u32>, u32)]) -> u32 {
|
||||||
fn immediate_s(self, mappings: &[(RangeInclusive<u16>, u16)]) -> u16 {
|
|
||||||
let mut imm = 0;
|
let mut imm = 0;
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
for (from, to) in mappings {
|
for (from, to) in mappings {
|
||||||
|
assert!(from.start() <= from.end());
|
||||||
let value = self.extract(from.clone());
|
let value = self.extract(from.clone());
|
||||||
imm |= value << to;
|
imm |= value << to;
|
||||||
let this_size = from.end() - from.start() + 1;
|
let this_size = from.end() - from.start() + 1;
|
||||||
size = size.max(*to + this_size);
|
size = size.max(*to + this_size);
|
||||||
}
|
}
|
||||||
sign_extend16(imm, size)
|
sign_extend(imm, size)
|
||||||
}
|
}
|
||||||
fn op(self) -> u16 {
|
fn quadrant(self) -> u16 {
|
||||||
self.0 & 0b11
|
self.0 & 0b11
|
||||||
}
|
}
|
||||||
fn funct3(self) -> u16 {
|
fn funct3(self) -> u32 {
|
||||||
self.extract(13..=15)
|
self.extract(13..=15)
|
||||||
}
|
}
|
||||||
|
/// rd/rs1 (7..=11)
|
||||||
fn rd(self) -> Reg {
|
fn rd(self) -> Reg {
|
||||||
Reg(self.extract(7..=11) as u32)
|
Reg(self.extract(7..=11) as u32)
|
||||||
}
|
}
|
||||||
|
fn rs2(self) -> Reg {
|
||||||
|
Reg(self.extract(2..=6) as u32)
|
||||||
|
}
|
||||||
|
/// rs1' (7..=9)
|
||||||
|
fn rs1_short(self) -> Reg {
|
||||||
|
let smol_reg = self.extract(7..=9);
|
||||||
|
// map to x8..=x15
|
||||||
|
Reg(smol_reg as u32 + 8)
|
||||||
|
}
|
||||||
|
/// rs2' (2..=4)
|
||||||
|
fn rs2_short(self) -> Reg {
|
||||||
|
let smol_reg = self.extract(2..=4);
|
||||||
|
// map to x8..=x15
|
||||||
|
Reg(smol_reg as u32 + 8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<InstCodeC> for InstCode {
|
impl From<InstCodeC> for InstCode {
|
||||||
|
|
@ -472,44 +528,191 @@ impl From<InstCodeC> for InstCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum IsCompressed {
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
|
||||||
impl Inst {
|
impl Inst {
|
||||||
pub fn decode(code: u32) -> Result<Inst, Status> {
|
pub fn decode(code: u32) -> Result<(Inst, IsCompressed), Status> {
|
||||||
let is_compressed = (code & 0b11) != 0b11;
|
let is_compressed = (code & 0b11) != 0b11;
|
||||||
if is_compressed {
|
if is_compressed {
|
||||||
Self::decode_compressed(code as u16)
|
Ok((Self::decode_compressed(code as u16)?, IsCompressed::Yes))
|
||||||
} else {
|
} else {
|
||||||
Self::decode_normal(code)
|
Ok((Self::decode_normal(code)?, IsCompressed::No))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_compressed(code: u16) -> Result<Inst, Status> {
|
fn decode_compressed(code: u16) -> Result<Inst, Status> {
|
||||||
let code = InstCodeC(code);
|
let code = InstCodeC(code);
|
||||||
|
if code.0 == 0 {
|
||||||
|
return Err(Status::IllegalInstruction(code.into(), "null instruction"));
|
||||||
|
}
|
||||||
|
|
||||||
let inst = match code.op() {
|
let inst = match code.quadrant() {
|
||||||
// C0
|
// C0
|
||||||
0b00 => todo!(),
|
0b00 => match code.funct3() {
|
||||||
|
// C.LW -> lw \dest \offset(\base)
|
||||||
|
0b010 => Inst::Lw {
|
||||||
|
offset: code.immediate_u(&[(10..=12, 3), (5..=5, 6), (6..=6, 2)]),
|
||||||
|
dest: code.rs2_short(),
|
||||||
|
base: code.rs1_short(),
|
||||||
|
},
|
||||||
|
// C.SW -> sw \src, \offset(\base)
|
||||||
|
0b110 => Inst::Sw {
|
||||||
|
offset: code.immediate_u(&[(10..=12, 3), (5..=5, 6), (6..=6, 2)]),
|
||||||
|
src: code.rs2_short(),
|
||||||
|
base: code.rs1_short(),
|
||||||
|
},
|
||||||
|
_ => return Err(Status::IllegalInstruction(code.into(), "funct3")),
|
||||||
|
},
|
||||||
// C1
|
// C1
|
||||||
0b01 => todo!(),
|
0b01 => match code.funct3() {
|
||||||
// C2
|
// C.ADDI -> addi \rd, \rd, \imm
|
||||||
0b10 => {
|
0b000 => Inst::Addi {
|
||||||
match code.funct3() {
|
imm: code.immediate_s(&[(2..=6, 0), (12..=12, 5)]),
|
||||||
// C.LDSP
|
dest: code.rd(),
|
||||||
010 => {
|
src1: code.rd(),
|
||||||
let dest = code.rd();
|
},
|
||||||
if dest.0 == 0 {
|
// C.JAL -> jal ra, \offset
|
||||||
return Err(Status::IllegalInstruction(code.into(), "rd"));
|
0b001 => Inst::Jal {
|
||||||
}
|
offset: code.immediate_s(&[
|
||||||
let imm = code.immediate_s(&[(12..=12, 5), (4..=6, 2), (2..=3, 6)]);
|
(2..=2, 5),
|
||||||
|
(3..=5, 1),
|
||||||
Inst::Lw {
|
(6..=6, 7),
|
||||||
offset: imm as u32,
|
(7..=7, 6),
|
||||||
dest,
|
(8..=8, 10),
|
||||||
base: Reg::SP,
|
(9..=10, 8),
|
||||||
|
(11..=11, 4),
|
||||||
|
(12..=12, 11),
|
||||||
|
]),
|
||||||
|
dest: Reg::RA,
|
||||||
|
},
|
||||||
|
// C.LI -> addi \rd, zero, \imm
|
||||||
|
0b010 => Inst::Addi {
|
||||||
|
imm: code.immediate_s(&[(2..=4, 0), (12..=12, 5)]),
|
||||||
|
dest: code.rd(),
|
||||||
|
src1: Reg::ZERO,
|
||||||
|
},
|
||||||
|
// C.J -> jal zero, \offset
|
||||||
|
0b101 => Inst::Jal {
|
||||||
|
offset: code.immediate_s(&[
|
||||||
|
(2..=2, 5),
|
||||||
|
(3..=5, 1),
|
||||||
|
(6..=6, 7),
|
||||||
|
(7..=7, 6),
|
||||||
|
(8..=8, 10),
|
||||||
|
(9..=10, 8),
|
||||||
|
(11..=11, 4),
|
||||||
|
(12..=12, 11),
|
||||||
|
]),
|
||||||
|
dest: Reg::ZERO,
|
||||||
|
},
|
||||||
|
0b011 => {
|
||||||
|
match code.rd().0 {
|
||||||
|
// C.ADDI16SP -> addi sp, sp, \imm
|
||||||
|
2 => Inst::Addi {
|
||||||
|
imm: code.immediate_s(&[
|
||||||
|
(2..=2, 2),
|
||||||
|
(3..=4, 7),
|
||||||
|
(5..=5, 6),
|
||||||
|
(6..=6, 4),
|
||||||
|
]),
|
||||||
|
dest: Reg::SP,
|
||||||
|
src1: Reg::SP,
|
||||||
|
},
|
||||||
|
// C.LUI -> lui \rd, \imm
|
||||||
|
_ => {
|
||||||
|
let uimm = code.immediate_s(&[(2..=6, 12), (12..=12, 17)]);
|
||||||
|
if uimm == 0 {
|
||||||
|
return Err(Status::IllegalInstruction(code.into(), "imm"));
|
||||||
|
}
|
||||||
|
Inst::Lui {
|
||||||
|
uimm,
|
||||||
|
dest: code.rd(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return Err(Status::IllegalInstruction(code.into(), "funct3")),
|
|
||||||
}
|
}
|
||||||
}
|
// C.BEQZ -> beq \rs1', zero, \offset
|
||||||
|
0b110 => Inst::Beq {
|
||||||
|
offset: code.immediate_s(&[
|
||||||
|
(2..=2, 5),
|
||||||
|
(3..=4, 1),
|
||||||
|
(5..=6, 6),
|
||||||
|
(10..=11, 3),
|
||||||
|
(12..=12, 8),
|
||||||
|
]),
|
||||||
|
src1: code.rs1_short(),
|
||||||
|
src2: Reg::ZERO,
|
||||||
|
},
|
||||||
|
// C.BEQZ -> bne \rs1', zero, \offset
|
||||||
|
0b111 => Inst::Bne {
|
||||||
|
offset: code.immediate_s(&[
|
||||||
|
(2..=2, 5),
|
||||||
|
(3..=4, 1),
|
||||||
|
(5..=6, 6),
|
||||||
|
(10..=11, 3),
|
||||||
|
(12..=12, 8),
|
||||||
|
]),
|
||||||
|
src1: code.rs1_short(),
|
||||||
|
src2: Reg::ZERO,
|
||||||
|
},
|
||||||
|
_ => return Err(Status::IllegalInstruction(code.into(), "funct3")),
|
||||||
|
},
|
||||||
|
// C2
|
||||||
|
0b10 => match code.funct3() {
|
||||||
|
// C.LWSP -> lw \reg \offset(sp)
|
||||||
|
0b010 => {
|
||||||
|
let dest = code.rd();
|
||||||
|
if dest.0 == 0 {
|
||||||
|
return Err(Status::IllegalInstruction(code.into(), "rd"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Inst::Lw {
|
||||||
|
offset: code.immediate_u(&[(12..=12, 5), (4..=6, 2), (2..=3, 6)]),
|
||||||
|
dest,
|
||||||
|
base: Reg::SP,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0b100 => {
|
||||||
|
let bit = code.extract(12..=12);
|
||||||
|
let rs2 = code.rs2();
|
||||||
|
let rd_rs1 = code.rd();
|
||||||
|
match (bit, rd_rs1.0, rs2.0) {
|
||||||
|
// C.JR -> jalr zero, 0(\rs1)
|
||||||
|
(0, _, 0) if rd_rs1.0 != 0 => Inst::Jalr {
|
||||||
|
offset: 0,
|
||||||
|
base: rd_rs1,
|
||||||
|
dest: Reg::ZERO,
|
||||||
|
},
|
||||||
|
// C.MV
|
||||||
|
(0, _, _) if rd_rs1.0 != 0 && rs2.0 != 0 => todo!(),
|
||||||
|
// C.EBREAK
|
||||||
|
(1, 0, 0) => Inst::Ebreak,
|
||||||
|
// C.JALR -> jalr ra, 0(\rs1)
|
||||||
|
(1, _, 0) if rd_rs1.0 != 0 => Inst::Jalr {
|
||||||
|
offset: 0,
|
||||||
|
base: rd_rs1,
|
||||||
|
dest: Reg::RA,
|
||||||
|
},
|
||||||
|
// C.ADD
|
||||||
|
(1, _, _) if rd_rs1.0 != 0 && rs2.0 != 0 => Inst::Add {
|
||||||
|
dest: todo!(),
|
||||||
|
src1: todo!(),
|
||||||
|
src2: todo!(),
|
||||||
|
},
|
||||||
|
_ => return Err(Status::IllegalInstruction(code.into(), "inst")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// C.SWSP -> sw \reg \offset(sp)
|
||||||
|
0b110 => Inst::Sw {
|
||||||
|
offset: code.immediate_u(&[(7..=8, 6), (9..=12, 2)]),
|
||||||
|
src: code.rs2(),
|
||||||
|
base: Reg::SP,
|
||||||
|
},
|
||||||
|
_ => return Err(Status::IllegalInstruction(code.into(), "funct3")),
|
||||||
|
},
|
||||||
_ => return Err(Status::IllegalInstruction(code.into(), "op")),
|
_ => return Err(Status::IllegalInstruction(code.into(), "op")),
|
||||||
};
|
};
|
||||||
Ok(inst)
|
Ok(inst)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
CC = clang -Wall -Wpedantic -target riscv32-unknown-linux-gnu -fuse-ld=lld -march=rv32i
|
CC = clang -Wall -Wpedantic -target riscv32-unknown-linux-gnu -fuse-ld=lld -march=rv32imac
|
||||||
CC_STATIC = $(CC) -static -nostdlib -nodefaultlibs
|
CC_STATIC = $(CC) -static -nostdlib -nodefaultlibs
|
||||||
|
|
||||||
RUSTC = rustc --target riscv32imac-unknown-none-elf
|
RUSTC = rustc --target riscv32imac-unknown-none-elf
|
||||||
|
|
||||||
all: init init1
|
all: init init1 x
|
||||||
|
|
||||||
init: init.c
|
init: init.c
|
||||||
$(CC_STATIC) init.c -o init
|
$(CC_STATIC) init.c -o init
|
||||||
|
|
||||||
init1: init1.rs
|
init1: init1.rs
|
||||||
$(RUSTC) init1.rs
|
$(RUSTC) init1.rs
|
||||||
|
|
||||||
|
x: x.s
|
||||||
|
$(CC_STATIC) x.s -o x
|
||||||
Loading…
Add table
Add a link
Reference in a new issue