rrs_lib/
instruction_formats.rs

1// Copyright 2021 Gregory Chadwick <mail@gregchadwick.co.uk>
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5//! Structures and constants for instruction decoding
6//!
7//! The structures directly relate to the RISC-V instruction formats described in the
8//! specification. See the [RISC-V specification](https://riscv.org/technical/specifications/) for
9//! further details
10
11pub const OPCODE_LOAD: u32 = 0x03;
12pub const OPCODE_MISC_MEM: u32 = 0x0f;
13pub const OPCODE_OP_IMM: u32 = 0x13;
14pub const OPCODE_AUIPC: u32 = 0x17;
15pub const OPCODE_STORE: u32 = 0x23;
16pub const OPCODE_OP: u32 = 0x33;
17pub const OPCODE_LUI: u32 = 0x37;
18pub const OPCODE_BRANCH: u32 = 0x63;
19pub const OPCODE_JALR: u32 = 0x67;
20pub const OPCODE_JAL: u32 = 0x6f;
21pub const OPCODE_SYSTEM: u32 = 0x73;
22
23#[derive(Debug, PartialEq)]
24pub struct RType {
25    pub funct7: u32,
26    pub rs2: usize,
27    pub rs1: usize,
28    pub funct3: u32,
29    pub rd: usize,
30}
31
32impl RType {
33    pub fn new(insn: u32) -> RType {
34        RType {
35            funct7: (insn >> 25) & 0x7f,
36            rs2: ((insn >> 20) & 0x1f) as usize,
37            rs1: ((insn >> 15) & 0x1f) as usize,
38            funct3: (insn >> 12) & 0x7,
39            rd: ((insn >> 7) & 0x1f) as usize,
40        }
41    }
42}
43
44#[derive(Debug, PartialEq)]
45pub struct IType {
46    pub imm: i32,
47    pub rs1: usize,
48    pub funct3: u32,
49    pub rd: usize,
50}
51
52impl IType {
53    pub fn new(insn: u32) -> IType {
54        let uimm: i32 = ((insn >> 20) & 0x7ff) as i32;
55
56        let imm: i32 = if (insn & 0x8000_0000) != 0 {
57            uimm - (1 << 11)
58        } else {
59            uimm
60        };
61
62        IType {
63            imm,
64            rs1: ((insn >> 15) & 0x1f) as usize,
65            funct3: (insn >> 12) & 0x7,
66            rd: ((insn >> 7) & 0x1f) as usize,
67        }
68    }
69}
70
71#[derive(Debug, PartialEq)]
72pub struct ITypeShamt {
73    pub funct7: u32,
74    pub shamt: u32,
75    pub rs1: usize,
76    pub funct3: u32,
77    pub rd: usize,
78}
79
80impl ITypeShamt {
81    pub fn new(insn: u32) -> ITypeShamt {
82        let itype = IType::new(insn);
83        let shamt = (itype.imm as u32) & 0x1f;
84
85        ITypeShamt {
86            funct7: (insn >> 25) & 0x7f,
87            shamt,
88            rs1: itype.rs1,
89            funct3: itype.funct3,
90            rd: itype.rd,
91        }
92    }
93}
94
95#[derive(Debug, PartialEq)]
96pub struct SType {
97    pub imm: i32,
98    pub rs2: usize,
99    pub rs1: usize,
100    pub funct3: u32,
101}
102
103impl SType {
104    pub fn new(insn: u32) -> SType {
105        let uimm: i32 = (((insn >> 20) & 0x7e0) | ((insn >> 7) & 0x1f)) as i32;
106
107        let imm: i32 = if (insn & 0x8000_0000) != 0 {
108            uimm - (1 << 11)
109        } else {
110            uimm
111        };
112
113        SType {
114            imm,
115            rs2: ((insn >> 20) & 0x1f) as usize,
116            rs1: ((insn >> 15) & 0x1f) as usize,
117            funct3: (insn >> 12) & 0x7,
118        }
119    }
120}
121
122#[derive(Debug, PartialEq)]
123pub struct BType {
124    pub imm: i32,
125    pub rs2: usize,
126    pub rs1: usize,
127    pub funct3: u32,
128}
129
130impl BType {
131    pub fn new(insn: u32) -> BType {
132        let uimm: i32 =
133            (((insn >> 20) & 0x7e0) | ((insn >> 7) & 0x1e) | ((insn & 0x80) << 4)) as i32;
134
135        let imm: i32 = if (insn & 0x8000_0000) != 0 {
136            uimm - (1 << 12)
137        } else {
138            uimm
139        };
140
141        BType {
142            imm,
143            rs2: ((insn >> 20) & 0x1f) as usize,
144            rs1: ((insn >> 15) & 0x1f) as usize,
145            funct3: (insn >> 12) & 0x7,
146        }
147    }
148}
149
150#[derive(Debug, PartialEq)]
151pub struct UType {
152    pub imm: i32,
153    pub rd: usize,
154}
155
156impl UType {
157    pub fn new(insn: u32) -> UType {
158        UType {
159            imm: (insn & 0xffff_f000) as i32,
160            rd: ((insn >> 7) & 0x1f) as usize,
161        }
162    }
163}
164
165#[derive(Debug, PartialEq)]
166pub struct JType {
167    pub imm: i32,
168    pub rd: usize,
169}
170
171impl JType {
172    pub fn new(insn: u32) -> JType {
173        let uimm: i32 =
174            ((insn & 0xff000) | ((insn & 0x100000) >> 9) | ((insn >> 20) & 0x7fe)) as i32;
175
176        let imm: i32 = if (insn & 0x8000_0000) != 0 {
177            uimm - (1 << 20)
178        } else {
179            uimm
180        };
181
182        JType {
183            imm,
184            rd: ((insn >> 7) & 0x1f) as usize,
185        }
186    }
187}
188
189#[cfg(test)]
190
191mod tests {
192    use super::*;
193
194    #[test]
195    fn test_rtype() {
196        assert_eq!(
197            RType::new(0x0),
198            RType {
199                funct7: 0,
200                rs2: 0,
201                rs1: 0,
202                funct3: 0,
203                rd: 0
204            }
205        )
206    }
207
208    #[test]
209    fn test_itype() {
210        // addi x23, x31, 2047
211        assert_eq!(
212            IType::new(0x7fff8b93),
213            IType {
214                imm: 2047,
215                rs1: 31,
216                funct3: 0,
217                rd: 23
218            }
219        );
220
221        // addi x23, x31, -1
222        assert_eq!(
223            IType::new(0xffff8b93),
224            IType {
225                imm: -1,
226                rs1: 31,
227                funct3: 0,
228                rd: 23
229            }
230        );
231
232        // addi x23, x31, -2
233        assert_eq!(
234            IType::new(0xffef8b93),
235            IType {
236                imm: -2,
237                rs1: 31,
238                funct3: 0,
239                rd: 23
240            }
241        );
242
243        // ori x13, x7, 4
244        assert_eq!(
245            IType::new(0x8003e693),
246            IType {
247                imm: -2048,
248                rs1: 7,
249                funct3: 0b110,
250                rd: 13
251            }
252        );
253    }
254
255    #[test]
256    fn test_itype_shamt() {
257        // slli x12, x5, 13
258        assert_eq!(
259            ITypeShamt::new(0x00d29613),
260            ITypeShamt {
261                funct7: 0,
262                shamt: 13,
263                rs1: 5,
264                funct3: 0b001,
265                rd: 12
266            }
267        );
268
269        // srli x30, x19, 31
270        assert_eq!(
271            ITypeShamt::new(0x01f9df13),
272            ITypeShamt {
273                funct7: 0,
274                shamt: 31,
275                rs1: 19,
276                funct3: 0b101,
277                rd: 30
278            }
279        );
280
281        // srai x7, x23, 0
282        assert_eq!(
283            ITypeShamt::new(0x400bd393),
284            ITypeShamt {
285                funct7: 0b0100000,
286                shamt: 0,
287                rs1: 23,
288                funct3: 0b101,
289                rd: 7
290            }
291        );
292    }
293
294    #[test]
295    fn test_stype() {
296        // sb x31, -2048(x15)
297        assert_eq!(
298            SType::new(0x81f78023),
299            SType {
300                imm: -2048,
301                rs2: 31,
302                rs1: 15,
303                funct3: 0,
304            }
305        );
306
307        // sh x18, 2047(x3)
308        assert_eq!(
309            SType::new(0x7f219fa3),
310            SType {
311                imm: 2047,
312                rs2: 18,
313                rs1: 3,
314                funct3: 1,
315            }
316        );
317
318        // sw x8, 1(x23)
319        assert_eq!(
320            SType::new(0x008ba0a3),
321            SType {
322                imm: 1,
323                rs2: 8,
324                rs1: 23,
325                funct3: 2,
326            }
327        );
328
329        // sw x5, -1(x25)
330        assert_eq!(
331            SType::new(0xfe5cafa3),
332            SType {
333                imm: -1,
334                rs2: 5,
335                rs1: 25,
336                funct3: 2,
337            }
338        );
339
340        // sw x13, 7(x12)
341        assert_eq!(
342            SType::new(0x00d623a3),
343            SType {
344                imm: 7,
345                rs2: 13,
346                rs1: 12,
347                funct3: 2,
348            }
349        );
350
351        // sw x13, -7(x12)
352        assert_eq!(
353            SType::new(0xfed62ca3),
354            SType {
355                imm: -7,
356                rs2: 13,
357                rs1: 12,
358                funct3: 2,
359            }
360        );
361    }
362
363    #[test]
364    fn test_btype() {
365        // beq x10, x14, .-4096
366        assert_eq!(
367            BType::new(0x80e50063),
368            BType {
369                imm: -4096,
370                rs1: 10,
371                rs2: 14,
372                funct3: 0b000
373            }
374        );
375
376        // blt x3, x21, .+4094
377        assert_eq!(
378            BType::new(0x7f51cfe3),
379            BType {
380                imm: 4094,
381                rs1: 3,
382                rs2: 21,
383                funct3: 0b100
384            }
385        );
386
387        // bge x18, x0, .-2
388        assert_eq!(
389            BType::new(0xfe095fe3),
390            BType {
391                imm: -2,
392                rs1: 18,
393                rs2: 0,
394                funct3: 0b101
395            }
396        );
397
398        // bne x15, x16, .+2
399        assert_eq!(
400            BType::new(0x01079163),
401            BType {
402                imm: 2,
403                rs1: 15,
404                rs2: 16,
405                funct3: 0b001
406            }
407        );
408
409        // bgeu x31, x8, .+18
410        assert_eq!(
411            BType::new(0x008ff963),
412            BType {
413                imm: 18,
414                rs1: 31,
415                rs2: 8,
416                funct3: 0b111
417            }
418        );
419
420        // bgeu x31, x8, .-18
421        assert_eq!(
422            BType::new(0xfe8ff7e3),
423            BType {
424                imm: -18,
425                rs1: 31,
426                rs2: 8,
427                funct3: 0b111
428            }
429        );
430    }
431
432    #[test]
433    fn test_utype() {
434        // lui x0, 0xfffff
435        assert_eq!(
436            UType::new(0xfffff037),
437            UType {
438                imm: (0xfffff000 as u32) as i32,
439                rd: 0,
440            }
441        );
442
443        // lui x31, 0x0
444        assert_eq!(UType::new(0x00000fb7), UType { imm: 0x0, rd: 31 });
445
446        // lui x17, 0x123ab
447        assert_eq!(
448            UType::new(0x123ab8b7),
449            UType {
450                imm: 0x123ab000,
451                rd: 17,
452            }
453        );
454    }
455
456    #[test]
457    fn test_jtype() {
458        // jal x0, .+0xffffe
459        assert_eq!(
460            JType::new(0x7ffff06f),
461            JType {
462                imm: 0xffffe,
463                rd: 0,
464            }
465        );
466
467        // jal x31, .-0x100000
468        assert_eq!(
469            JType::new(0x80000fef),
470            JType {
471                imm: -0x100000,
472                rd: 31,
473            }
474        );
475
476        // jal x13, .-2
477        assert_eq!(JType::new(0xfffff6ef), JType { imm: -2, rd: 13 });
478
479        // jal x13, .+2
480        assert_eq!(JType::new(0x002006ef), JType { imm: 2, rd: 13 });
481
482        // jal x26, .-46
483        assert_eq!(JType::new(0xfd3ffd6f), JType { imm: -46, rd: 26 });
484
485        // jal x26, .+46
486        assert_eq!(JType::new(0x02e00d6f), JType { imm: 46, rd: 26 });
487    }
488}