asm_riscv 0.1.0

RISC-V Assembly Encoder / Decoder.
Documentation
//! RISC-V 32-Bit Base Integer Instructions to compile into, with optional
//! extensions that can be enabled.
//! - RV32M Multiply Extension
//! - RV32A Atomic Extension
//! - RV32F Single-Precision Floating Point Extension
//! - RV32D Double-Precision Floating Point Extension
//!
//! # Ignored For Now
//! - RV32Q Quadruple-Precision Floating Point Extension
//! - RV32C Compression 16-bit Instructions
//! - All 64 bit extensions
//!
//! May be ported to other platforms with assembly translators.
//!
//! # RISC-V Compiler Notes
//! This is intended to help anyone who needs it, if they're building a compiler
//! to RISC-V.
//! - For speed: Make sure all loads and stores are 32-bit aligned
//! - For shifts: Shifting the width of the register is a no-op, to clear
//!   register $R use ADDI $R, $ZERO, 0.
//!
//! ## Psuedo-Instructions
//! - `nop`: `addi $zero, $zero, 0`
//! - `mv $d, $s`: `addi $d, $s, 0`
//! - `not $d, $s`: `ori $d, $s, -1`
//! - `neg $d, $s`: `sub $d, $zero, $s`
//! - `j offset`: `jal $zero, offset` (unconditional jump)
//! - `jal offset`: `jal $ra, offset` (near function call)
//! - `call offset`: (far function call)
//! ```asm
//! auipc $ra, offset[31:12] + offset[11]
//! jalr $ra, offset[11:0]($ra)
//! ```
//! - `ret`: `jalr $ra, 0($ra)`
//! - `beqz $r, offset`: `beq $r, $zero, offset`
//! - `bnez $r, offset`: `bne $r, $zero, offset`
//! - `bgez $r, offset`: `bge $r, $zero, offset`
//! - `bltz $r, offset`: `blt $r, $zero, offset`
//! - `bgt $r1, $r2, offset`: `blt $r2, $r1, offset`
//! - `ble $r1, $r2, offset`: `bge $r2, $r1, offset`
//! - `fence`: `fence IORW, IORW`
//! - `li $d, im`: `addi $d, $zero, im` (set immediate)
//! - `li $d, im`:
//! ```asm
//! lui $d, im[31:12] + im[11]
//! addi $d, $zero, im[11:0]
//! ```
//! - `la $d, symbol`:
//! ```asm
//! auipc $d, delta[31:12] + delta[11]
//! addi $d, $d, delta[11:0]
//! ```
//! - `lw $d, symbol`:
//! ```asm
//! auipc $d, delta[31:12] + delta[11]
//! lw $d, $d, delta[11:0](rd)
//! ```
//! - `sw $d, symbol, $t`:
//! ```asm
//! auipc $t, delta[31:12] + delta[11]
//! sw $d, $d, delta[11:0]($t)
//! ```
//! - `seqz $d, $s`: `sltiu $d, $s, 0`
//! - `snez $d, $s`: `sltu $d, $zero, $s`
//! Custom Pseudo-Instructions
//! - `zero $d`: `addi $r, $zero, 0` (set register to zero)
//! - `slt $d, $a, $b, $s`: (with multiply cpu feature enabled)
//! ```asm
//! # Option 1:
//! slt $d, $a, $b
//! mul $d, $d, $s
//! ```
//! - `slt $d, $a, $b, $s`: (without multiply cpu feature enabled)
//! ```asm
//! # Option 1 (branching, ugh):
//! blt $a, $b, 12 # 12: ④
//! addi $d, $zero, 0
//! jal $zero 8 # Skip next instruction
//! add $d, $zero, $s # ④
//!
//! # Option 2 (might be faster for without AND with multiply extension):
//! slt $d, $a, $b
//! slli $d, $d, 31
//! srai $d, $d, 31
//! and $d, $d, $s
//! ```
//! - `slt $d, $a, $b, $s, $e`: (`$d: if $a < $b { $s } else { $e }`)
//! ```asm
//! sub $s, $s, $e
//! slt $d, $a, $b, $s
//! add $d, $d, $e
//! add $s, $s, $e # can be elimated if s is dropped
//! ```
//! - `slt $d, $a, $b, $s, $e, $t`: (`$d: if $a < $b { $s } else { $e }`)
//! ```asm
//! sub $t, $s, $e
//! slt $d, $a, $b, $t
//! add $d, $d, $e
//! ```

#![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::*;

/// A RISC-V Register
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Reg {
    /// SPECIAL: Always 0
    ZERO = 0u8,
    /// Return address
    RA = 1,
    /// SPECIAL: Stack pointer
    SP = 2,
    /// Global pointer
    GP = 3,
    /// Thread pointer
    TP = 4,
    /// Temporary
    T0 = 5,
    /// Temporary
    T1 = 6,
    /// Temporary
    T2 = 7,
    /// Saved (Frame Pointer)
    S0 = 8,
    /// Saved
    S1 = 9,
    /// Function arguments / Return values
    A0 = 10,
    /// Function arguments / Return values
    A1 = 11,
    /// Function arguments
    A2 = 12,
    /// Function arguments
    A3 = 13,
    /// Function arguments
    A4 = 14,
    /// Function arguments
    A5 = 15,
    /// Function arguments
    A6 = 16,
    /// Function arguments
    A7 = 17,
    /// Saved
    S2 = 18,
    /// Saved
    S3 = 19,
    /// Saved
    S4 = 20,
    /// Saved
    S5 = 21,
    /// Saved
    S6 = 22,
    /// Saved
    S7 = 23,
    /// Saved
    S8 = 24,
    /// Saved
    S9 = 25,
    /// Saved
    S10 = 26,
    /// Saved
    S11 = 27,
    /// Temporary
    T3 = 28,
    /// Temporary
    T4 = 29,
    /// Temporary
    T5 = 30,
    /// Temporary
    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!(),
        }
    }
}

/// An assembly instruction (im is limited to 12 bits)
#[allow(clippy::enum_variant_names)]
#[allow(missing_docs)]
#[derive(Copy, Clone, Debug)]
pub enum I {
    //// One of 40 User mode instructions in the RV32I Base Instruction Set ////
    /// U: Set upper 20 bits to immediate value
    LUI { d: Reg, im: i32 },
    /// U: Add upper 20 bits to immediate value in program counter
    AUIPC { d: Reg, im: i32 },
    /// UJ: Jump and Link Relative
    JAL { d: Reg, im: i32 },
    /// I: Jump and Link, Register
    JALR { d: Reg, s: Reg, im: i16 },
    /// SB: 12-bit immediate offset Branch on Equal
    BEQ { s1: Reg, s2: Reg, im: i16 },
    /// SB: 12-bit immediate offset Branch on Not Equal
    BNE { s1: Reg, s2: Reg, im: i16 },
    /// SB: 12-bit immediate offset Branch on Less Than
    BLT { s1: Reg, s2: Reg, im: i16 },
    /// SB: 12-bit immediate offset Branch on Greater Than Or Equal To
    BGE { s1: Reg, s2: Reg, im: i16 },
    /// SB: 12-bit immediate offset Branch on Less Than (Unsigned)
    BLTU { s1: Reg, s2: Reg, im: i16 },
    /// SB: 12-bit immediate offset Branch on Greater Than Or Equal To (Unsigned)
    BGEU { s1: Reg, s2: Reg, im: i16 },
    /// I: Load Byte (`R[d]: M[R[s] + im]`)
    LB { d: Reg, s: Reg, im: i16 },
    /// I: Load Half-Word (`R[d]: M[R[s] + im]`)
    LH { d: Reg, s: Reg, im: i16 },
    /// I: Load Word (`R[d]: M[R[s] + im]`)
    LW { d: Reg, s: Reg, im: i16 },
    /// I: Load Byte Unsigned (`R[d]: M[R[s] + im]`)
    LBU { d: Reg, s: Reg, im: i16 },
    /// I: Load Half Unsigned (`R[d]: M[R[s] + im]`)
    LHU { d: Reg, s: Reg, im: i16 },
    /// S: Store Byte
    SB { s1: Reg, s2: Reg, im: i16 },
    /// S: Store Half Word
    SH { s1: Reg, s2: Reg, im: i16 },
    /// S: Store Word
    SW { s1: Reg, s2: Reg, im: i16 },
    /// I: Add Immediate (`R[d]: R[s] + im`)
    ADDI { d: Reg, s: Reg, im: i16 },
    /// I: Set 1 on Less Than, 0 Otherwise Immediate
    SLTI { d: Reg, s: Reg, im: i16 },
    /// I: Set 1 on Less Than, 0 Otherwise Immediate Unsigned
    SLTUI { d: Reg, s: Reg, im: i16 },
    /// I: Xor Immediate
    XORI { d: Reg, s: Reg, im: i16 },
    /// I: Or Immediate
    ORI { d: Reg, s: Reg, im: i16 },
    /// I: And Immediate
    ANDI { d: Reg, s: Reg, im: i16 },
    /// I: Logical Left Shift Immediate
    SLLI { d: Reg, s: Reg, im: i8 },
    /// I: Logical Right Shift Immediate
    SRLI { d: Reg, s: Reg, im: i8 },
    /// I: Arithmetic Shift Right Immediate (See SRA).
    SRAI { d: Reg, s: Reg, im: i8 },
    /// R: Add (`R[d]: R[s1] + R[s2]`)
    ADD { d: Reg, s1: Reg, s2: Reg },
    /// R: Subtract (`R[d]: R[s1] - R[s2]`)
    SUB { d: Reg, s1: Reg, s2: Reg },
    /// R: Logical Left Shift
    SLL { d: Reg, s1: Reg, s2: Reg },
    /// R: Set 1 on Less Than, 0 Otherwise
    SLT { d: Reg, s1: Reg, s2: Reg },
    /// R: Set 1 on Less Than, 0 Otherwise Unsigned
    SLTU { d: Reg, s1: Reg, s2: Reg },
    /// R: Xor
    XOR { d: Reg, s1: Reg, s2: Reg },
    /// R: Logical Right Shift
    SRL { d: Reg, s1: Reg, s2: Reg },
    /// R: Arithmetic Shift Right (Sign Bit Copied Rather Than Filling In Zeros)
    SRA { d: Reg, s1: Reg, s2: Reg },
    /// R: Or
    OR { d: Reg, s1: Reg, s2: Reg },
    /// R: And
    AND { d: Reg, s1: Reg, s2: Reg },
    /// I: Invoke a system call (Registers defined by ABI, not hardware)
    ECALL {},
    /// I: Debugger Breakpoint
    EBREAK {},
    /// I: Fence (Immediate Is Made Up Of Ordered High Order To Low Order Bits:)
    /// - fm(4), PI(1), PO(1), PR(1), PW(1), SI(1), SO(1), SR(1), SW(1)
    FENCE { im: i16 },
    //// Multiply Extension ////

    //// Atomic Extension ////

    //// Single-Precision Floating Point Extension ////

    //// Double-Precision Floating Point Extension ////

    //// Vector Extension ///

    //// SIMD Extension ////
}

impl I {
    /// - funct7: 7
    /// - src2:   5
    /// - src1:   5
    /// - funct3: 3
    /// - dst:    5
    /// - opcode: 7
    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)
    }

    /// - im:    12
    /// - src:    5
    /// - funct3: 3
    /// - dst:    5
    /// - opcode  7
    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)
    }

    /// - funct7: 7
    /// - im:    5
    /// - src:    5
    /// - funct3: 3
    /// - dst:    5
    /// - opcode  7
    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)
    }

    /// - im_h:  7
    /// - src2:   5
    /// - src1:   5
    /// - funct3: 3
    /// - im_l:  5
    /// - opcode  7
    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)
    }

    /// - im:    20
    /// - dst:    5
    /// - opcode  7
    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 {
    // Using match makes it easier to extend code in the future.
    #[allow(clippy::match_single_binding)]
    fn from(with: u32) -> Self {
        match with & 0b1111111 {
            // Load From RAM
            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),
            },
            // Misc. Memory Instructions
            0b0001111 => match I::from_i(with) {
                (_, 0b000, _, im) => FENCE { im },
                (_, funct, _, _mm) => panic!("Unknown funct3: {}", funct),
            },
            // Store To RAM
            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),
            },
            // Immediate Arithmetic
            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),
                },
            },
            // Add Upper Immediate To Program Counter
            0b0010111 => match I::from_u(with) {
                (d, im) => AUIPC { d, im },
            },
            // Register Arithmetic
            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),
            },
            // Load upper immediate
            0b0110111 => match I::from_u(with) {
                (d, im) => LUI { d, im },
            },
            // Branch on Condition
            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),
            },
            // Jump and link register
            0b1100111 => match I::from_i(with) {
                (d, 0b000, s, im) => JALR { d, s, im },
                (_d, f3, _s, _im) => panic!("Unknown F3:{}", f3),
            },
            // Jump and Link
            0b1101111 => match I::from_u(with) {
                (d, im) => JAL { d, im },
            },
            // Transfer Control
            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)
            }
        }
    }
}