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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// RISC-V Bitmanip (Bit Manipulation) Extension
// See https://github.com/riscv/riscv-bitmanip/releases/download/1.0.0/bitmanip-1.0.0.pdf

use ckb_vm_definitions::instructions as insts;

use super::utils::{self, funct3, funct7, opcode, rd, rs1, rs2};
use super::{set_instruction_length_4, Instruction, Itype, Register, Rtype};

pub fn factory<R: Register>(instruction_bits: u32, _: u32) -> Option<Instruction> {
    let bit_length = R::BITS;
    if bit_length != 32 && bit_length != 64 {
        return None;
    }
    let rv64 = bit_length == 64;
    let inst = match opcode(instruction_bits) {
        0b_0111011 => {
            let funct3_value = funct3(instruction_bits);
            let funct7_value = funct7(instruction_bits);
            let inst_opt = match (funct3_value, funct7_value) {
                (0b_000, 0b_0000100) => Some(insts::OP_ADDUW),
                (0b_001, 0b_0110000) => Some(insts::OP_ROLW),
                (0b_010, 0b_0010000) => Some(insts::OP_SH1ADDUW),
                (0b_100, 0b_0000100) => {
                    if rv64 && rs2(instruction_bits) == 0 {
                        Some(insts::OP_ZEXTH)
                    } else {
                        None
                    }
                }
                (0b_100, 0b_0010000) => Some(insts::OP_SH2ADDUW),
                (0b_101, 0b_0110000) => Some(insts::OP_RORW),
                (0b_110, 0b_0010000) => Some(insts::OP_SH3ADDUW),
                _ => None,
            };
            inst_opt.map(|inst| {
                Rtype::new(
                    inst,
                    rd(instruction_bits),
                    rs1(instruction_bits),
                    rs2(instruction_bits),
                )
                .0
            })
        }
        0b_0110011 => {
            let funct3_value = funct3(instruction_bits);
            let funct7_value = funct7(instruction_bits);
            let inst_opt = match (funct3_value, funct7_value) {
                (0b_111, 0b_0100000) => Some(insts::OP_ANDN),
                (0b_110, 0b_0100000) => Some(insts::OP_ORN),
                (0b_100, 0b_0100000) => Some(insts::OP_XNOR),
                (0b_001, 0b_0110000) => Some(insts::OP_ROL),
                (0b_101, 0b_0110000) => Some(insts::OP_ROR),
                (0b_001, 0b_0110100) => Some(insts::OP_BINV),
                (0b_001, 0b_0010100) => Some(insts::OP_BSET),
                (0b_001, 0b_0100100) => Some(insts::OP_BCLR),
                (0b_101, 0b_0100100) => Some(insts::OP_BEXT),
                (0b_010, 0b_0010000) => Some(insts::OP_SH1ADD),
                (0b_100, 0b_0010000) => Some(insts::OP_SH2ADD),
                (0b_110, 0b_0010000) => Some(insts::OP_SH3ADD),
                (0b_001, 0b_0000101) => Some(insts::OP_CLMUL),
                (0b_011, 0b_0000101) => Some(insts::OP_CLMULH),
                (0b_010, 0b_0000101) => Some(insts::OP_CLMULR),
                (0b_100, 0b_0000101) => Some(insts::OP_MIN),
                (0b_101, 0b_0000101) => Some(insts::OP_MINU),
                (0b_110, 0b_0000101) => Some(insts::OP_MAX),
                (0b_111, 0b_0000101) => Some(insts::OP_MAXU),
                _ => None,
            };
            inst_opt.map(|inst| {
                Rtype::new(
                    inst,
                    rd(instruction_bits),
                    rs1(instruction_bits),
                    rs2(instruction_bits),
                )
                .0
            })
        }
        0b_0010011 => {
            let funct3_value = funct3(instruction_bits);
            let funct7_value = funct7(instruction_bits);
            let rs2_value = rs2(instruction_bits);
            let inst_opt = match (funct7_value, funct3_value, rs2_value) {
                (0b_0010100, 0b_101, 0b_00111) => Some(insts::OP_ORCB),
                (0b_0110101, 0b_101, 0b_11000) => Some(insts::OP_REV8),
                (0b_0110000, 0b_001, 0b_00000) => Some(insts::OP_CLZ),
                (0b_0110000, 0b_001, 0b_00010) => Some(insts::OP_CPOP),
                (0b_0110000, 0b_001, 0b_00001) => Some(insts::OP_CTZ),
                (0b_0110000, 0b_001, 0b_00100) => Some(insts::OP_SEXTB),
                (0b_0110000, 0b_001, 0b_00101) => Some(insts::OP_SEXTH),
                _ => None,
            };
            if let Some(inst) = inst_opt {
                Some(
                    Rtype::new(
                        inst,
                        rd(instruction_bits),
                        rs1(instruction_bits),
                        rs2(instruction_bits),
                    )
                    .0,
                )
            } else {
                let inst_opt = match (funct7_value >> 1, funct3_value) {
                    (0b_010010, 0b_001) => Some(insts::OP_BCLRI),
                    (0b_010010, 0b_101) => Some(insts::OP_BEXTI),
                    (0b_011010, 0b_001) => Some(insts::OP_BINVI),
                    (0b_001010, 0b_001) => Some(insts::OP_BSETI),
                    (0b_011000, 0b_101) => Some(insts::OP_RORI),
                    _ => None,
                };
                inst_opt.map(|inst| {
                    Itype::new_u(
                        inst,
                        rd(instruction_bits),
                        rs1(instruction_bits),
                        utils::x(instruction_bits, 20, 6, 0),
                    )
                    .0
                })
            }
        }
        0b_0011011 => {
            let funct3_value = funct3(instruction_bits);
            let funct7_value = funct7(instruction_bits);
            let rs2_value = rs2(instruction_bits);

            match funct7_value {
                0b_0110000 => match funct3_value {
                    0b_001 => {
                        let inst_opt = match rs2_value {
                            0b_00000 => Some(insts::OP_CLZW),
                            0b_00010 => Some(insts::OP_CPOPW),
                            0b_00001 => Some(insts::OP_CTZW),
                            _ => None,
                        };
                        inst_opt.map(|inst| {
                            Rtype::new(inst, rd(instruction_bits), rs1(instruction_bits), rs2_value)
                                .0
                        })
                    }
                    0b_101 => Some(
                        Itype::new_u(
                            insts::OP_RORIW,
                            rd(instruction_bits),
                            rs1(instruction_bits),
                            utils::x(instruction_bits, 20, 5, 0),
                        )
                        .0,
                    ),
                    _ => None,
                },
                _ => {
                    if funct7_value >> 1 == 0b_000010 && funct3_value == 0b_001 {
                        Some(
                            Itype::new_u(
                                insts::OP_SLLIUW,
                                rd(instruction_bits),
                                rs1(instruction_bits),
                                utils::x(instruction_bits, 20, 6, 0),
                            )
                            .0,
                        )
                    } else {
                        None
                    }
                }
            }
        }
        _ => None,
    };

    inst.map(set_instruction_length_4)
}