#![no_std]
#![doc(
html_logo_url = "https://ardaku.github.io/mm/logo.svg",
html_favicon_url = "https://ardaku.github.io/mm/icon.svg",
html_root_url = "https://docs.rs/asm_riscv"
)]
#![deny(unsafe_code)]
#![warn(
anonymous_parameters,
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
nonstandard_style,
rust_2018_idioms,
single_use_lifetimes,
trivial_casts,
trivial_numeric_casts,
unreachable_pub,
unused_extern_crates,
unused_qualifications,
variant_size_differences
)]
use Reg::*;
use I::*;
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Reg {
ZERO = 0u8,
RA = 1,
SP = 2,
GP = 3,
TP = 4,
T0 = 5,
T1 = 6,
T2 = 7,
S0 = 8,
S1 = 9,
A0 = 10,
A1 = 11,
A2 = 12,
A3 = 13,
A4 = 14,
A5 = 15,
A6 = 16,
A7 = 17,
S2 = 18,
S3 = 19,
S4 = 20,
S5 = 21,
S6 = 22,
S7 = 23,
S8 = 24,
S9 = 25,
S10 = 26,
S11 = 27,
T3 = 28,
T4 = 29,
T5 = 30,
T6 = 31,
}
impl From<u32> for Reg {
fn from(reg: u32) -> Self {
match reg {
0 => ZERO,
1 => RA,
2 => SP,
3 => GP,
4 => TP,
5 => T0,
6 => T1,
7 => T2,
8 => S0,
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,
_ => unreachable!(),
}
}
}
#[allow(clippy::enum_variant_names)]
#[allow(missing_docs)]
#[derive(Copy, Clone, Debug)]
pub enum I {
LUI { d: Reg, im: i32 },
AUIPC { d: Reg, im: i32 },
JAL { d: Reg, im: i32 },
JALR { d: Reg, s: Reg, im: i16 },
BEQ { s1: Reg, s2: Reg, im: i16 },
BNE { s1: Reg, s2: Reg, im: i16 },
BLT { s1: Reg, s2: Reg, im: i16 },
BGE { s1: Reg, s2: Reg, im: i16 },
BLTU { s1: Reg, s2: Reg, im: i16 },
BGEU { s1: Reg, s2: Reg, im: i16 },
LB { d: Reg, s: Reg, im: i16 },
LH { d: Reg, s: Reg, im: i16 },
LW { d: Reg, s: Reg, im: i16 },
LBU { d: Reg, s: Reg, im: i16 },
LHU { d: Reg, s: Reg, im: i16 },
SB { s1: Reg, s2: Reg, im: i16 },
SH { s1: Reg, s2: Reg, im: i16 },
SW { s1: Reg, s2: Reg, im: i16 },
ADDI { d: Reg, s: Reg, im: i16 },
SLTI { d: Reg, s: Reg, im: i16 },
SLTUI { d: Reg, s: Reg, im: i16 },
XORI { d: Reg, s: Reg, im: i16 },
ORI { d: Reg, s: Reg, im: i16 },
ANDI { d: Reg, s: Reg, im: i16 },
SLLI { d: Reg, s: Reg, im: i8 },
SRLI { d: Reg, s: Reg, im: i8 },
SRAI { d: Reg, s: Reg, im: i8 },
ADD { d: Reg, s1: Reg, s2: Reg },
SUB { d: Reg, s1: Reg, s2: Reg },
SLL { d: Reg, s1: Reg, s2: Reg },
SLT { d: Reg, s1: Reg, s2: Reg },
SLTU { d: Reg, s1: Reg, s2: Reg },
XOR { d: Reg, s1: Reg, s2: Reg },
SRL { d: Reg, s1: Reg, s2: Reg },
SRA { d: Reg, s1: Reg, s2: Reg },
OR { d: Reg, s1: Reg, s2: Reg },
AND { d: Reg, s1: Reg, s2: Reg },
ECALL {},
EBREAK {},
FENCE { im: i16 },
}
impl I {
fn r(
opcode: u32,
d: Reg,
funct3: u32,
s1: Reg,
s2: Reg,
funct7: u32,
) -> u32 {
let dst: u32 = (d as u8).into();
let src1: u32 = (s1 as u8).into();
let src2: u32 = (s2 as u8).into();
let mut out = opcode;
out |= dst << 7;
out |= funct3 << 12;
out |= src1 << 15;
out |= src2 << 20;
out |= funct7 << 25;
out
}
fn from_r(instruction: u32) -> (Reg, u32, Reg, Reg, u32) {
let d = Reg::from((instruction & (0b11111 << 7)) >> 7);
let funct3 = (instruction & (0b111 << 12)) >> 12;
let s1 = Reg::from((instruction & (0b11111 << 15)) >> 15);
let s2 = Reg::from((instruction & (0b11111 << 20)) >> 20);
let funct7 = instruction >> 25;
(d, funct3, s1, s2, funct7)
}
fn i(opcode: u32, d: Reg, funct3: u32, s: Reg, im: i16) -> u32 {
let im: u32 = (im as u16).into();
let dst: u32 = (d as u8).into();
let src: u32 = (s as u8).into();
let mut out = opcode;
out |= dst << 7;
out |= funct3 << 12;
out |= src << 15;
out |= im << 20;
out
}
fn from_i(instruction: u32) -> (Reg, u32, Reg, i16) {
let d = Reg::from((instruction & (0b11111 << 7)) >> 7);
let funct3 = (instruction & (0b111 << 12)) >> 12;
let s = Reg::from((instruction & (0b11111 << 15)) >> 15);
let im = ((instruction >> 20) as u16) as i16;
(d, funct3, s, im)
}
fn i7(
opcode: u32,
d: Reg,
funct3: u32,
s: Reg,
im: i8,
funct7: u32,
) -> u32 {
let im = im as u8;
let im: u32 = im.into();
let dst: u32 = (d as u8).into();
let src: u32 = (s as u8).into();
let mut out = opcode;
out |= dst << 7;
out |= funct3 << 12;
out |= src << 15;
out |= im << 20;
out |= funct7 << 25;
out
}
fn from_i7(instruction: u32) -> (Reg, u32, Reg, i8, u32) {
let d = Reg::from((instruction & (0b11111 << 7)) >> 7);
let funct3 = (instruction & (0b111 << 12)) >> 12;
let s = Reg::from((instruction & (0b11111 << 15)) >> 15);
let im = ((instruction & (0b11111 << 20)) >> 20) as u8;
let funct7 = instruction >> 25;
(d, funct3, s, im as i8, funct7)
}
fn s(opcode: u32, funct3: u32, s1: Reg, s2: Reg, im: i16) -> u32 {
let im: u32 = (im as u16).into();
let src1: u32 = (s1 as u8).into();
let src2: u32 = (s2 as u8).into();
let mut out = opcode;
out |= (im & 0b11111) << 7;
out |= funct3 << 12;
out |= src1 << 15;
out |= src2 << 20;
out |= (im >> 5) << 25;
out
}
fn from_s(instruction: u32) -> (u32, Reg, Reg, i16) {
let mut im = ((instruction & (0b11111 << 7)) >> 7) as u16;
let funct3 = (instruction & (0b111 << 12)) >> 12;
let s1 = Reg::from((instruction & (0b11111 << 15)) >> 15);
let s2 = Reg::from((instruction & (0b11111 << 20)) >> 20);
im |= ((instruction >> 25) as u16) << 5;
(funct3, s1, s2, im as i16)
}
fn u(opcode: u32, d: Reg, im: i32) -> u32 {
let im = im as u32;
let dst: u32 = (d as u8).into();
let mut out = opcode;
out |= dst << 7;
out |= im << 12;
out
}
fn from_u(instruction: u32) -> (Reg, i32) {
let d = Reg::from((instruction & (0b11111 << 7)) >> 7);
let im = instruction >> 12;
(d, im as i32)
}
}
impl From<I> for u32 {
fn from(with: I) -> Self {
match with {
LUI { d, im } => I::u(0b0110111, d, im),
AUIPC { d, im } => I::u(0b0010111, d, im),
JAL { d, im } => I::u(0b1101111, d, im),
JALR { d, s, im } => I::i(0b1100111, d, 0b000, s, im),
BEQ { s1, s2, im } => I::s(0b1100011, 0b000, s1, s2, im),
BNE { s1, s2, im } => I::s(0b1100011, 0b001, s1, s2, im),
BLT { s1, s2, im } => I::s(0b1100011, 0b100, s1, s2, im),
BGE { s1, s2, im } => I::s(0b1100011, 0b101, s1, s2, im),
BLTU { s1, s2, im } => I::s(0b1100011, 0b110, s1, s2, im),
BGEU { s1, s2, im } => I::s(0b1100011, 0b111, s1, s2, im),
LB { d, s, im } => I::i(0b0000011, d, 0b000, s, im),
LH { d, s, im } => I::i(0b0000011, d, 0b001, s, im),
LW { d, s, im } => I::i(0b0000011, d, 0b010, s, im),
LBU { d, s, im } => I::i(0b0000011, d, 0b100, s, im),
LHU { d, s, im } => I::i(0b0000011, d, 0b101, s, im),
ADDI { d, s, im } => I::i(0b0010011, d, 0b000, s, im),
SLTI { d, s, im } => I::i(0b0010011, d, 0b010, s, im),
SLTUI { d, s, im } => I::i(0b0010011, d, 0b011, s, im),
XORI { d, s, im } => I::i(0b0010011, d, 0b100, s, im),
ORI { d, s, im } => I::i(0b0010011, d, 0b110, s, im),
ANDI { d, s, im } => I::i(0b0010011, d, 0b111, s, im),
SLLI { d, s, im } => I::i7(0b0010011, d, 0b001, s, im, 0b0000000),
SRLI { d, s, im } => I::i7(0b0010011, d, 0b101, s, im, 0b0000000),
SRAI { d, s, im } => I::i7(0b0010011, d, 0b101, s, im, 0b0100000),
SB { s1, s2, im } => I::s(0b0100011, 0b000, s1, s2, im),
SH { s1, s2, im } => I::s(0b0100011, 0b001, s1, s2, im),
SW { s1, s2, im } => I::s(0b0100011, 0b010, s1, s2, im),
ADD { d, s1, s2 } => I::r(0b0110011, d, 0b000, s1, s2, 0b0000000),
SUB { d, s1, s2 } => I::r(0b0110011, d, 0b000, s1, s2, 0b0100000),
SLL { d, s1, s2 } => I::r(0b0110011, d, 0b001, s1, s2, 0b0000000),
SLT { d, s1, s2 } => I::r(0b0110011, d, 0b010, s1, s2, 0b0000000),
SLTU { d, s1, s2 } => I::r(0b0110011, d, 0b011, s1, s2, 0b0000000),
XOR { d, s1, s2 } => I::r(0b0110011, d, 0b100, s1, s2, 0b0000000),
SRL { d, s1, s2 } => I::r(0b0110011, d, 0b101, s1, s2, 0b0000000),
SRA { d, s1, s2 } => I::r(0b0110011, d, 0b101, s1, s2, 0b0100000),
OR { d, s1, s2 } => I::r(0b0110011, d, 0b110, s1, s2, 0b0000000),
AND { d, s1, s2 } => I::r(0b0110011, d, 0b111, s1, s2, 0b0000000),
ECALL {} => I::i(0b1110011, ZERO, 0b000, ZERO, 0b000000000000),
EBREAK {} => I::i(0b1110011, ZERO, 0b000, ZERO, 0b000000000001),
FENCE { im } => I::i(0b0001111, ZERO, 0b000, ZERO, im),
}
}
}
impl From<u32> for I {
#[allow(clippy::match_single_binding)]
fn from(with: u32) -> Self {
match with & 0b1111111 {
0b0000011 => match I::from_i(with) {
(d, 0b000, s, im) => LB { d, s, im },
(d, 0b001, s, im) => LH { d, s, im },
(d, 0b010, s, im) => LW { d, s, im },
(d, 0b100, s, im) => LBU { d, s, im },
(d, 0b101, s, im) => LHU { d, s, im },
(_, funct, _, _mm) => panic!("Unknown funct3: {}", funct),
},
0b0001111 => match I::from_i(with) {
(_, 0b000, _, im) => FENCE { im },
(_, funct, _, _mm) => panic!("Unknown funct3: {}", funct),
},
0b0100011 => match I::from_s(with) {
(0b000, s1, s2, im) => SB { s1, s2, im },
(0b001, s1, s2, im) => SH { s1, s2, im },
(0b010, s1, s2, im) => SW { s1, s2, im },
(funct, _s, _z, _mm) => panic!("Unknown funct3: {}", funct),
},
0b0010011 => match I::from_i(with) {
(d, 0b000, s, im) => ADDI { d, s, im },
(d, 0b010, s, im) => SLTI { d, s, im },
(d, 0b011, s, im) => SLTUI { d, s, im },
(d, 0b100, s, im) => XORI { d, s, im },
(d, 0b110, s, im) => ORI { d, s, im },
(d, 0b111, s, im) => ANDI { d, s, im },
_ => match I::from_i7(with) {
(d, 0b001, s, im, 0b0000000) => SLLI { d, s, im },
(d, 0b101, s, im, 0b0000000) => SRLI { d, s, im },
(d, 0b101, s, im, 0b0100000) => SRAI { d, s, im },
(_, funct, _, _, _) => panic!("Unknown funct3: {}", funct),
},
},
0b0010111 => match I::from_u(with) {
(d, im) => AUIPC { d, im },
},
0b0110011 => match I::from_r(with) {
(d, 0b000, s1, s2, 0b0000000) => ADD { d, s1, s2 },
(d, 0b000, s1, s2, 0b0100000) => SUB { d, s1, s2 },
(d, 0b001, s1, s2, 0b0000000) => SLL { d, s1, s2 },
(d, 0b010, s1, s2, 0b0000000) => SLT { d, s1, s2 },
(d, 0b011, s1, s2, 0b0000000) => SLTU { d, s1, s2 },
(d, 0b100, s1, s2, 0b0000000) => XOR { d, s1, s2 },
(d, 0b101, s1, s2, 0b0000000) => SRL { d, s1, s2 },
(d, 0b101, s1, s2, 0b0100000) => SRA { d, s1, s2 },
(d, 0b110, s1, s2, 0b0000000) => OR { d, s1, s2 },
(d, 0b111, s1, s2, 0b0000000) => AND { d, s1, s2 },
(_, f3, _s, _z, f7) => panic!("Unknown F3:{} F7:{}", f3, f7),
},
0b0110111 => match I::from_u(with) {
(d, im) => LUI { d, im },
},
0b1100011 => match I::from_s(with) {
(0b000, s1, s2, im) => BEQ { s1, s2, im },
(0b001, s1, s2, im) => BNE { s1, s2, im },
(0b100, s1, s2, im) => BLT { s1, s2, im },
(0b101, s1, s2, im) => BGE { s1, s2, im },
(0b110, s1, s2, im) => BLTU { s1, s2, im },
(0b111, s1, s2, im) => BGEU { s1, s2, im },
(funct, _s, _z, _mm) => panic!("Unknown funct3: {}", funct),
},
0b1100111 => match I::from_i(with) {
(d, 0b000, s, im) => JALR { d, s, im },
(_d, f3, _s, _im) => panic!("Unknown F3:{}", f3),
},
0b1101111 => match I::from_u(with) {
(d, im) => JAL { d, im },
},
0b1110011 => match I::from_i(with) {
(ZERO, 0b000, ZERO, 0b000000000000) => ECALL {},
(ZERO, 0b000, ZERO, 0b000000000001) => EBREAK {},
_ => panic!("Unknown Environment Control Transfer"),
},
o => {
panic!("Failed to parse RISC-V Assembly, Unknown Opcode {}", o)
}
}
}
}