#![allow(clippy::unusual_byte_groupings)]
pub const EBREAK: u32 = 0b000000000001_00000_000_00000_1110011;
pub fn lw(offset: u16, base: u8, width: u8, destination: u8) -> u32 {
let opcode = 0b000_0011;
i_type_instruction(opcode, base, width, destination, offset)
}
pub const fn sw(offset: u32, base: u32, width: u32, source: u32) -> u32 {
let opcode = 0b010_0011;
let offset_lower = offset & 0b11111;
let offset_upper = offset >> 5;
offset_upper << 25 | source << 20 | base << 15 | width << 12 | offset_lower << 7 | opcode
}
pub fn addi(source: u8, destination: u8, immediate: u16) -> u32 {
let opcode = 0b001_0011;
let function = 0b000;
i_type_instruction(opcode, source, function, destination, immediate)
}
pub fn csrr(rd: u8, csr: u16) -> u32 {
csrrs(rd, 0, csr)
}
pub fn csrrs(rd: u8, rs1: u8, csr: u16) -> u32 {
let opcode = 0b1110011;
let funct3 = 0b010;
i_type_instruction(opcode, rs1, funct3, rd, csr)
}
pub fn csrw(csr: u16, rs: u8) -> u32 {
csrrw(0, rs, csr)
}
pub fn csrrw(rd: u8, rs1: u8, csr: u16) -> u32 {
let opcode = 0b1110011;
let funct3 = 0b001;
i_type_instruction(opcode, rs1, funct3, rd, csr)
}
fn i_type_instruction(opcode: u8, rs1: u8, funct3: u8, rd: u8, imm: u16) -> u32 {
assert!(opcode <= 0x7f); assert!(rd <= 0x1f); assert!(funct3 <= 0x7); assert!(rs1 <= 0x1f); assert!(imm <= 0xfff);
(imm as u32) << 20
| (rs1 as u32) << 15
| (funct3 as u32) << 12
| (rd as u32) << 7
| opcode as u32
}
#[cfg(test)]
mod test {
use super::{csrr, csrw, lw, sw};
#[test]
fn assemble_csrr() {
let expected = 0x30402473;
let assembled = csrr(8, 0x304);
assert_eq!(assembled, expected);
}
#[test]
fn assemble_csrw() {
let expected = 0x30049073;
let assembled = csrw(0x300, 9);
assert_eq!(assembled, expected);
}
#[test]
fn assemble_sw() {
let expected = 0x00112223;
let assembled = sw(4, 2, 2, 1);
assert_eq!(assembled, expected);
}
#[test]
fn assemble_lw() {
let expected = 0x00822183;
let assembled = lw(8, 4, 2, 3);
assert_eq!(assembled, expected);
}
}