#![expect(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: i16) -> u32 {
let opcode = 0b001_0011;
let function = 0b000;
i_type_instruction(
opcode,
source,
function,
destination,
immediate as u16 & 0xFFF,
)
}
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);
}
}