1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#![allow(clippy::unreadable_literal)]
use rysk_tools_macro::base_instructions;

#[derive(Debug, Clone)]
pub enum MachineInstruction {
    Normal([u8; 4]),
    Compressed([u8; 2])
}

#[derive(Copy, Clone, Debug)]
pub enum Instruction {
    BaseInstruction(BaseInstruction),
    PseudoInstruction(PseudoInstruction)
}
impl Instruction {
    // Should be in-place in the future
    pub fn make_pseudo(instructions: &mut [Self]) -> (Self, &mut [Self]) {
        (instructions[0], &mut instructions[1..])
    }
}

/// Extract the destination register index from an instruction
macro_rules! destination {
    ($instruction:ident) => {
        ((($instruction[0] & 0x80) >> 7) | (($instruction[1] & 0x0F) << 1)) as _
    };
}
/// Extract the first source register index from an instruction
macro_rules! source1 {
    ($instruction:ident) => {
        ((($instruction[1] & 0x80) >> 7) | (($instruction[2] & 0x0F) << 1)) as _
    };
}
/// Extract the second source register index from an instruction
macro_rules! source2 {
    ($instruction:ident) => {
        ((($instruction[2] & 0xF0) >> 4) | (($instruction[3] & 0x01) << 4)) as _
    };
}

macro_rules! immediate_i {
    ($instruction:ident) => {
        {
            let extra = if $instruction[3] & 0x80 != 0 { 0xFF } else { 0 };
            i32::from_le_bytes([(($instruction[2] & 0xF0) >> 4) | (($instruction[3] & 0x0F) << 4), (($instruction[3] & 0xF0) >> 4) | (extra & 0xF0), extra, extra])
        }
    };
}
macro_rules! immediate_s {
    ($instruction:ident) => {
        {
            let extra = if $instruction[3] & 0x80 != 0 { 0xFF } else { 0 };
            i32::from_le_bytes([(($instruction[0] & 0x80) >> 7) | (($instruction[1] & 0x0F) << 1) | (($instruction[3] & 0x0E) << 4), (($instruction[3] & 0xF0) >> 4) | (extra & 0xF0), extra, extra])
        }
    };
}
macro_rules! immediate_b {
    ($instruction:ident) => {
        {
            let extra = if $instruction[3] & 0x80 != 0 { 0xFF } else { 0 };
            i32::from_le_bytes([
                (($instruction[1] & 0xF) << 1) | (($instruction[3] & 0x0E) << 4),
                (($instruction[3] & 0x70) >> 4) | (($instruction[0] & 0x80) >> 4) | (($instruction[3] & 0x80) >> 3) | (extra & 0xE0),
                extra,
                extra
            ])
        }
    };
}
macro_rules! immediate_u {
    ($instruction:ident) => {
        i32::from_le_bytes([0, $instruction[1] & 0xF0, $instruction[2], $instruction[3]])
    };
}
macro_rules! immediate_j {
    ($instruction:ident) => {
        {
            let signed = $instruction[3] & 0x80 != 0;
            i32::from_le_bytes([
                (($instruction[2] & 0xE0) >> 4) // 1-3
                    | (($instruction[3] & 0x0F) << 4), // 4-7
                (($instruction[3] & 0x70) >> 4) // 8-10
                    | (($instruction[2] & 0x10) >> 1) // 11
                    | ($instruction[1] & 0xF0), // 12-15
                ($instruction[2] & 0x0F) // 16-19
                    | (($instruction[3] & 0x80) >> 3) // 20
                    | if signed {0xE0} else {0},
                    if signed {0xFF} else {0}
            ])
        }
    };
}

// The heavy lifting is done by a proc macro as there is a lot of very repetitive code otherwise
base_instructions!{
    LUI -> U(0b0110111) { "Load Upper Immediate" },
    AUIPC -> U(0b0010111) { "Add Upper Immediate to Program Counter" },

    JAL -> J(0b1101111) { "Jump and Link" },
    JALR -> I(0b1100111, 0b000) { "Jump and Link Register" },
    BEQ -> B(0b1100011, 0b000) { "Branch if Equal" },
    BNE -> B(0b1100011, 0b001) { "Branch if Not Equal" },
    BLT -> B(0b1100011, 0b100) { "Branch if Less Than" },
    BGE -> B(0b1100011, 0b101) { "Branch if Greater Than or Equal" },
    BLTU -> B(0b1100011, 0b110) { "Branch if Less Than Unsigned" },
    BGEU -> B(0b1100011, 0b111) { "Branch if Greater Than or Equal Unsigned" },

    LB -> I(0b0000011, 0b000) { "Load Byte" },
    LH -> I(0b0000011, 0b001) { "Load Half" },
    LW -> I(0b0000011, 0b010) { "Load Word" },
    LBU -> I(0b0000011, 0b100) { "Load Byte Unsigned" },
    LHU -> I(0b0000011, 0b101) { "Load Half Unsigned" },
    SB -> S(0b0100011, 0b000) { "Store Byte" },
    SH -> S(0b0100011, 0b001) { "Store Half" },
    SW -> S(0b0100011, 0b010) { "Store Word" },

    ADDI -> I(0b0010011, 0b000) { "Add Immediate" },
    SLTI -> I(0b0010011, 0b010) { "Set if Less Than Immediate" },
    SLTIU -> I(0b0010011, 0b011) { "Set if Less Than Immediate Unsigned" },
    XORI -> I(0b0010011, 0b100) { "Exclusive Or Immediate" },
    ORI -> I(0b0010011, 0b110) { "Or Immediate" },
    ANDI -> I(0b0010011, 0b111) { "And Immediate" },

    SLLI -> SH(0b0010011, 0b001, 0b00000) { "Shift Left Logical Immediate" },
    SRLI -> SH(0b0010011, 0b101, 0b00000) { "Shift Right Logical Immediate" },
    SRAI -> SH(0b0010011, 0b101, 0b01000) { "Shift Right Arithmetic Immediate" },

    ADD -> R(0b0110011, 0b000, 0b0000000) { "Add" },
    SUB -> R(0b0110011, 0b000, 0b0100000) { "Subtract" },
    SLL -> R(0b0110011, 0b001, 0b0000000) { "Shift Left Logical" },
    SLT -> R(0b0110011, 0b010, 0b0000000) { "Set if Less Than" },
    SLTU -> R(0b0110011, 0b011, 0b0000000) { "Set if Less Than Unsigned" },
    XOR -> R(0b0110011, 0b100, 0b0000000) { "Exclusive Or" },
    SRL -> R(0b0110011, 0b101, 0b0100000) { "Shift Right Logical" },
    SRA -> R(0b0110011, 0b101, 0b0100000) { "Shift Right Arithmetic" },
    OR -> R(0b0110011, 0b110, 0b0000000) { "Or" },
    AND -> R(0b0110011, 0b111, 0b0000000) { "And" },

    FENCE -> I(0b1110011, 0b000) { "Fence" },
}

#[derive(Copy, Clone, Debug)]
pub enum PseudoInstruction {

}