From 209529e1829af1efe5cee0a64264e53c2ae8656c Mon Sep 17 00:00:00 2001 From: Lucas Clemente Vella Date: Tue, 19 Sep 2023 20:46:19 +0100 Subject: [PATCH] Parsing .insn assembly directive. --- riscv/build.rs | 5 ++- riscv/src/lib.rs | 71 +++++++++++++++++++++++++++++++++++++ riscv/src/riscv_asm.lalrpop | 10 +++++- 3 files changed, 84 insertions(+), 2 deletions(-) diff --git a/riscv/build.rs b/riscv/build.rs index 0374a153e..c5977c1e9 100644 --- a/riscv/build.rs +++ b/riscv/build.rs @@ -12,7 +12,10 @@ fn main() { } fn build_lalrpop() { - lalrpop::process_root().unwrap(); + lalrpop::Configuration::new() + .emit_rerun_directives(true) + .process_current_dir() + .unwrap(); } fn build_instruction_tests() { diff --git a/riscv/src/lib.rs b/riscv/src/lib.rs index 31797c0bf..72be3acba 100644 --- a/riscv/src/lib.rs +++ b/riscv/src/lib.rs @@ -329,3 +329,74 @@ fn output_files_from_cargo_build_plan( assemblies } + +/// Maps an instruction in .insn syntax to Statement::Instruction() in the expected format. +/// +/// See https://www.rowleydownload.co.uk/arm/documentation/gnu/as/RISC_002dV_002dFormats.html +pub fn map_insn_i( + opcode6: Expression, + func3: Expression, + rd: Register, + rs1: Register, + simm12: Expression, +) -> Statement { + let (Expression::Number(opcode6), Expression::Number(func3)) = (opcode6, func3) else { + panic!("Only literal opcode and function are supported in .insn syntax"); + }; + + // These are almost all instructions in RISC-V Instruction Set Manual that + // we are supposed to implement and roughly fits the pattern of the I-type + // instruction. Only "csr*i" instructions are missing. + + // First we try to match the instructions that uses the I-type encoding + // ordinarily, i.e. where all fields are what they are supposed to be: + let name = match (opcode6, func3) { + (0b1100111, 0b000) => "jalr", + (0b0000011, 0b000) => "lb", + (0b0000011, 0b001) => "lh", + (0b0000011, 0b010) => "lw", + (0b0000011, 0b100) => "lbu", + (0b0000011, 0b101) => "lhu", + (0b0010011, 0b000) => "addi", + (0b0010011, 0b010) => "slti", + (0b0010011, 0b011) => "sltiu", + (0b0010011, 0b100) => "xori", + (0b0010011, 0b110) => "ori", + (0b0010011, 0b111) => "andi", + (0b1110011, 0b001) => "csrrw", + (0b1110011, 0b010) => "csrrs", + (0b1110011, 0b011) => "csrrc", + // won't interpret "csr*i" instructions because it is too weird to + // encode an immediate as a register + opfunc => { + // We now try the instructions that take certain liberties with the + // I-type encoding, and don't use the standard arguments for it. + let name = match opfunc { + (0b0001111, 0b000) => "fence", + (0b0001111, 0b001) => "fence.i", + (0b1110011, 0b000) => { + let Expression::Number(simm12) = simm12 else { + panic!( + "Only literal simm12 is supported for ecall and ebreak instructions" + ); + }; + match simm12 { + 0 => "ecall", + 1 => "ebreak", + _ => panic!("unknown instruction"), + } + } + _ => panic!("unsupported .insn instruction"), + }; + return Statement::Instruction(name.to_string(), Vec::new()); + } + }; + + let args = vec![ + Argument::Register(rd), + Argument::Register(rs1), + Argument::Expression(simm12), + ]; + + Statement::Instruction(name.to_string(), args) +} diff --git a/riscv/src/riscv_asm.lalrpop b/riscv/src/riscv_asm.lalrpop index 34d15e58d..0ab997521 100644 --- a/riscv/src/riscv_asm.lalrpop +++ b/riscv/src/riscv_asm.lalrpop @@ -13,7 +13,7 @@ use std::str::FromStr; use asm_utils::ast::{unescape_string, BinaryOpKind as BOp, UnaryOpKind as UOp, new_binary_op as bin_op, new_unary_op as un_op, new_function_op as fn_op}; -use crate::{Argument, Register, Statement, FunctionKind as FOp, Expression}; +use crate::{Argument, Register, Statement, FunctionKind as FOp, Expression, map_insn_i}; grammar; @@ -67,9 +67,17 @@ Directive: Statement = { } Instruction: Statement = { + , => Statement::Instruction(<>) } +InsnDirective: Statement = { + ".insn" "i" "," "," "," "," => map_insn_i(opcode6, func3, rd, rs1, simm12), + ".insn" "i" "," "," "," "(" ")" => map_insn_i(opcode6, func3, rd, rs1, simm12) + // TODO: implement the other kinds of .insn instructions. + // See https://www.rowleydownload.co.uk/arm/documentation/gnu/as/RISC_002dV_002dFormats.html +} + Arguments: Vec = { => vec![], "," )*> => { list.push(end); list }