lib_rv32_asm/
parse.rs

1use std::collections::HashMap;
2
3use lib_rv32_common::{constants::*, parse_int};
4
5use crate::error::AssemblerError;
6
7/// Convert an instruction to it's tokens, stripping out whitespace,
8/// parenthesis, and commas.
9#[macro_export]
10macro_rules! tokenize {
11    ($s:expr) => {
12        $s.replace(",", " ")
13            .replace("\n", " ")
14            .replace("(", " ")
15            .replace(")", " ")
16            .to_ascii_lowercase()
17            .split_whitespace()
18            .map(|s| s.to_owned())
19            .collect();
20    };
21}
22
23/// Match an operation to the correct opcode.
24pub fn match_opcode(op: &str) -> Result<u8, AssemblerError> {
25    let opcode = match op {
26        "add" | "sub" | "sll" | "slt" | "sltu" | "xor" | "sra" | "or" | "and" => OPCODE_ARITHMETIC,
27        "addi" | "slli" | "slti" | "xori" | "srai" | "ori" | "andi" => OPCODE_ARITHMETIC_IMM,
28        "lui" => OPCODE_LUI,
29        "auipc" => OPCODE_AUIPC,
30        "jal" => OPCODE_JAL,
31        "jalr" => OPCODE_JALR,
32        "beq" | "bne" | "blt" | "bge" | "bgeu" => OPCODE_BRANCH,
33        "lb" | "lbu" | "lh" | "lhu" | "lw" => OPCODE_LOAD,
34        "sb" | "sh" | "sw" => OPCODE_STORE,
35        _ => return Err(AssemblerError::InvalidOperationError),
36    };
37    Ok(opcode)
38}
39
40/// Match a register number or name to its integer number.
41pub fn match_register(reg: &str) -> Result<u8, AssemblerError> {
42    if reg.starts_with('x') {
43        match reg.strip_prefix('x').unwrap().parse() {
44            Ok(n) => Ok(n),
45            Err(_) => Err(AssemblerError::NoSuchRegisterError),
46        }
47    } else {
48        match REG_NAMES.iter().position(|e| *e == reg) {
49            Some(n) => Ok(n as u8),
50            None => Err(AssemblerError::NoSuchRegisterError),
51        }
52    }
53}
54
55/// Parse a label or an immediate literal into an integer.
56pub fn parse_imm(s: &str, labels: &HashMap<String, u32>, pc: u32) -> Result<u32, AssemblerError> {
57    let num = parse_int!(i64, s);
58    match num {
59        Err(_) => {
60            let label = labels.get(s);
61            if let Some(v) = label {
62                Ok((*v).wrapping_sub(pc))
63            } else {
64                Err(AssemblerError::InvalidImmediateError)
65            }
66        }
67        Ok(d) => Ok(d as u32),
68    }
69}
70
71/// Match an operation to the correct func3.
72#[macro_export]
73macro_rules! match_func3 {
74    ($t:expr) => {
75        match $t {
76            "beq" => FUNC3_BEQ,
77            "bne" => FUNC3_BNE,
78            "blt" => FUNC3_BLT,
79            "bge" => FUNC3_BGE,
80            "bltu" => FUNC3_BLTU,
81            "bgeu" => FUNC3_BGEU,
82            "lb" => FUNC3_LB,
83            "lbu" => FUNC3_LBU,
84            "lh" => FUNC3_LH,
85            "lhu" => FUNC3_LHU,
86            "lw" => FUNC3_LW,
87            "sb" => FUNC3_SB,
88            "sh" => FUNC3_SH,
89            "sw" => FUNC3_SW,
90            "add" | "addi" | "sub" => FUNC3_ADD_SUB,
91            "sll" | "slli" => FUNC3_SLL,
92            "slt" | "slti" => FUNC3_SLT,
93            "sltu" => FUNC3_SLTU,
94            "xor" | "xori" => FUNC3_XOR,
95            "sra" | "srai" | "srl" | "srli" => FUNC3_SR,
96            "or" | "ori" => FUNC3_OR,
97            "and" | "andi" => FUNC3_AND,
98            _ => unreachable!(),
99        }
100    };
101}
102
103/// Match an operation to the correct func7.
104#[macro_export]
105macro_rules! match_func7 {
106    ($t:expr) => {
107        match $t {
108            "add" | "addi" => FUNC7_ADD,
109            "sub" => FUNC7_SUB,
110            "sra" | "srai" => FUNC7_SRA,
111            "srl" | "srli" => FUNC7_SRL,
112            _ => unreachable!(),
113        }
114    };
115}