compiler/
lib/
examples/
std/
arch/
rv64/
tests/
decode.rad
14.6 KiB
emit.rad
24.4 KiB
encode.rad
19.9 KiB
isel.rad
41.1 KiB
printer.rad
13.0 KiB
tests.rad
15.7 KiB
rv64.rad
13.0 KiB
collections/
lang/
sys/
arch.rad
65 B
collections.rad
36 B
fmt.rad
3.8 KiB
intrinsics.rad
206 B
io.rad
1.2 KiB
lang.rad
222 B
mem.rad
2.2 KiB
sys.rad
167 B
testing.rad
2.4 KiB
tests.rad
11.6 KiB
vec.rad
3.1 KiB
std.rad
231 B
scripts/
seed/
test/
vim/
.gitignore
353 B
.gitsigners
112 B
LICENSE
1.1 KiB
Makefile
3.1 KiB
README
2.5 KiB
std.lib
987 B
std.lib.test
252 B
lib/std/arch/rv64/decode.rad
raw
| 1 | //! RV64 instruction decoder. |
| 2 | //! |
| 3 | //! Decodes 32-bit instruction words into structured representations. |
| 4 | |
| 5 | use super::encode; |
| 6 | |
| 7 | /////////////////////// |
| 8 | // Field Extraction // |
| 9 | /////////////////////// |
| 10 | |
| 11 | /// Extract opcode (bits 6:0). |
| 12 | pub fn opcode(instr: u32) -> u32 { |
| 13 | return instr & 0x7F; |
| 14 | } |
| 15 | |
| 16 | /// Extract rd (bits 11:7). |
| 17 | pub fn rd(instr: u32) -> u8 { |
| 18 | return ((instr >> 7) & 0x1F) as u8; |
| 19 | } |
| 20 | |
| 21 | /// Extract funct3 (bits 14:12). |
| 22 | pub fn funct3(instr: u32) -> u32 { |
| 23 | return (instr >> 12) & 0x07; |
| 24 | } |
| 25 | |
| 26 | /// Extract rs1 (bits 19:15). |
| 27 | pub fn rs1(instr: u32) -> u8 { |
| 28 | return ((instr >> 15) & 0x1F) as u8; |
| 29 | } |
| 30 | |
| 31 | /// Extract rs2 (bits 24:20). |
| 32 | pub fn rs2(instr: u32) -> u8 { |
| 33 | return ((instr >> 20) & 0x1F) as u8; |
| 34 | } |
| 35 | |
| 36 | /// Extract funct7 (bits 31:25). |
| 37 | pub fn funct7(instr: u32) -> u32 { |
| 38 | return instr >> 25; |
| 39 | } |
| 40 | |
| 41 | ////////////////////////// |
| 42 | // Immediate Extraction // |
| 43 | ////////////////////////// |
| 44 | |
| 45 | /// Extract I-type immediate (sign-extended). |
| 46 | pub fn immI(instr: u32) -> i32 { |
| 47 | let imm = instr >> 20; |
| 48 | if (imm & 0x800) != 0 { |
| 49 | return (imm | 0xFFFFF000) as i32; |
| 50 | } |
| 51 | return imm as i32; |
| 52 | } |
| 53 | |
| 54 | /// Extract S-type immediate (sign-extended). |
| 55 | pub fn immS(instr: u32) -> i32 { |
| 56 | let lo = (instr >> 7) & 0x1F; |
| 57 | let hi = (instr >> 25) & 0x7F; |
| 58 | let imm = (hi << 5) | lo; |
| 59 | if (imm & 0x800) != 0 { |
| 60 | return (imm | 0xFFFFF000) as i32; |
| 61 | } |
| 62 | return imm as i32; |
| 63 | } |
| 64 | |
| 65 | /// Extract B-type immediate (sign-extended). |
| 66 | pub fn immB(instr: u32) -> i32 { |
| 67 | let imm11 = (instr >> 7) & 0x1; |
| 68 | let imm4_1 = (instr >> 8) & 0xF; |
| 69 | let imm10_5 = (instr >> 25) & 0x3F; |
| 70 | let imm12 = (instr >> 31) & 0x1; |
| 71 | let imm = (imm12 << 12) | (imm11 << 11) | (imm10_5 << 5) | (imm4_1 << 1); |
| 72 | if (imm & 0x1000) != 0 { |
| 73 | return (imm | 0xFFFFE000) as i32; |
| 74 | } |
| 75 | return imm as i32; |
| 76 | } |
| 77 | |
| 78 | /// Extract J-type immediate (sign-extended). |
| 79 | pub fn immJ(instr: u32) -> i32 { |
| 80 | let imm19_12 = (instr >> 12) & 0xFF; |
| 81 | let imm11 = (instr >> 20) & 0x1; |
| 82 | let imm10_1 = (instr >> 21) & 0x3FF; |
| 83 | let imm20 = (instr >> 31) & 0x1; |
| 84 | let imm = (imm20 << 20) | (imm19_12 << 12) | (imm11 << 11) | (imm10_1 << 1); |
| 85 | if (imm & 0x100000) != 0 { |
| 86 | return (imm | 0xFFE00000) as i32; |
| 87 | } |
| 88 | return imm as i32; |
| 89 | } |
| 90 | |
| 91 | /// Extract U-type immediate (upper 20 bits, sign-extended). |
| 92 | pub fn immU(instr: u32) -> i32 { |
| 93 | let imm = instr >> 12; |
| 94 | if (imm & 0x80000) != 0 { |
| 95 | return (imm | 0xFFF00000) as i32; |
| 96 | } |
| 97 | return imm as i32; |
| 98 | } |
| 99 | |
| 100 | ///////////////////////// |
| 101 | // Decoded Instruction // |
| 102 | ///////////////////////// |
| 103 | |
| 104 | /// Decoded RV64 instruction. |
| 105 | pub union Instr { |
| 106 | // R-type ALU. |
| 107 | Add { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 108 | Sub { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 109 | Sll { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 110 | Slt { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 111 | Sltu { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 112 | Xor { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 113 | Srl { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 114 | Sra { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 115 | Or { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 116 | And { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 117 | |
| 118 | // R-type M extension. |
| 119 | Mul { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 120 | Mulh { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 121 | Mulhsu { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 122 | Mulhu { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 123 | Div { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 124 | Divu { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 125 | Rem { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 126 | Remu { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 127 | |
| 128 | // R-type RV64 word operations. |
| 129 | Addw { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 130 | Subw { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 131 | Sllw { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 132 | Srlw { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 133 | Sraw { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 134 | Mulw { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 135 | Divw { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 136 | Divuw { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 137 | Remw { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 138 | Remuw { rd: super::Reg, rs1: super::Reg, rs2: super::Reg }, |
| 139 | |
| 140 | // I-type ALU. |
| 141 | Addi { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 142 | Slti { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 143 | Sltiu { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 144 | Xori { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 145 | Ori { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 146 | Andi { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 147 | Slli { rd: super::Reg, rs1: super::Reg, shamt: i32 }, |
| 148 | Srli { rd: super::Reg, rs1: super::Reg, shamt: i32 }, |
| 149 | Srai { rd: super::Reg, rs1: super::Reg, shamt: i32 }, |
| 150 | |
| 151 | // I-type RV64 word immediate operations. |
| 152 | Addiw { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 153 | Slliw { rd: super::Reg, rs1: super::Reg, shamt: i32 }, |
| 154 | Srliw { rd: super::Reg, rs1: super::Reg, shamt: i32 }, |
| 155 | Sraiw { rd: super::Reg, rs1: super::Reg, shamt: i32 }, |
| 156 | |
| 157 | // Load instructions. |
| 158 | Lb { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 159 | Lh { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 160 | Lw { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 161 | Ld { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 162 | Lbu { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 163 | Lhu { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 164 | Lwu { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 165 | |
| 166 | // Store instructions. |
| 167 | Sb { rs2: super::Reg, rs1: super::Reg, imm: i32 }, |
| 168 | Sh { rs2: super::Reg, rs1: super::Reg, imm: i32 }, |
| 169 | Sw { rs2: super::Reg, rs1: super::Reg, imm: i32 }, |
| 170 | Sd { rs2: super::Reg, rs1: super::Reg, imm: i32 }, |
| 171 | |
| 172 | // Branch instructions. |
| 173 | Beq { rs1: super::Reg, rs2: super::Reg, imm: i32 }, |
| 174 | Bne { rs1: super::Reg, rs2: super::Reg, imm: i32 }, |
| 175 | Blt { rs1: super::Reg, rs2: super::Reg, imm: i32 }, |
| 176 | Bge { rs1: super::Reg, rs2: super::Reg, imm: i32 }, |
| 177 | Bltu { rs1: super::Reg, rs2: super::Reg, imm: i32 }, |
| 178 | Bgeu { rs1: super::Reg, rs2: super::Reg, imm: i32 }, |
| 179 | |
| 180 | // Jump instructions. |
| 181 | Jal { rd: super::Reg, imm: i32 }, |
| 182 | Jalr { rd: super::Reg, rs1: super::Reg, imm: i32 }, |
| 183 | |
| 184 | // Upper immediate. |
| 185 | Lui { rd: super::Reg, imm: i32 }, |
| 186 | Auipc { rd: super::Reg, imm: i32 }, |
| 187 | |
| 188 | // System. |
| 189 | Ecall, |
| 190 | Ebreak, |
| 191 | |
| 192 | // Unknown/invalid instruction. |
| 193 | Unknown { bits: u32 }, |
| 194 | } |
| 195 | |
| 196 | /// Decode a 32-bit instruction word into an [`Instr`]. |
| 197 | pub fn decode(instr: u32) -> Instr { |
| 198 | let op = opcode(instr); |
| 199 | let f3 = funct3(instr); |
| 200 | let f7 = funct7(instr); |
| 201 | let rd = super::reg(rd(instr)); |
| 202 | let rs1 = super::reg(rs1(instr)); |
| 203 | let rs2 = super::reg(rs2(instr)); |
| 204 | |
| 205 | match op { |
| 206 | case encode::OP_LUI => { |
| 207 | return Instr::Lui { rd, imm: immU(instr) }; |
| 208 | }, |
| 209 | case encode::OP_AUIPC => { |
| 210 | return Instr::Auipc { rd, imm: immU(instr) }; |
| 211 | }, |
| 212 | case encode::OP_JAL => { |
| 213 | return Instr::Jal { rd, imm: immJ(instr) }; |
| 214 | }, |
| 215 | case encode::OP_JALR => { |
| 216 | return Instr::Jalr { rd, rs1, imm: immI(instr) }; |
| 217 | }, |
| 218 | case encode::OP_BRANCH => { |
| 219 | let imm = immB(instr); |
| 220 | match f3 { |
| 221 | case encode::F3_BEQ => return Instr::Beq { rs1, rs2, imm }, |
| 222 | case encode::F3_BNE => return Instr::Bne { rs1, rs2, imm }, |
| 223 | case encode::F3_BLT => return Instr::Blt { rs1, rs2, imm }, |
| 224 | case encode::F3_BGE => return Instr::Bge { rs1, rs2, imm }, |
| 225 | case encode::F3_BLTU => return Instr::Bltu { rs1, rs2, imm }, |
| 226 | case encode::F3_BGEU => return Instr::Bgeu { rs1, rs2, imm }, |
| 227 | else => return Instr::Unknown { bits: instr }, |
| 228 | } |
| 229 | }, |
| 230 | case encode::OP_LOAD => { |
| 231 | let imm = immI(instr); |
| 232 | match f3 { |
| 233 | case encode::F3_BYTE => return Instr::Lb { rd, rs1, imm }, |
| 234 | case encode::F3_HALF => return Instr::Lh { rd, rs1, imm }, |
| 235 | case encode::F3_WORD => return Instr::Lw { rd, rs1, imm }, |
| 236 | case encode::F3_DWORD => return Instr::Ld { rd, rs1, imm }, |
| 237 | case encode::F3_BYTE_U => return Instr::Lbu { rd, rs1, imm }, |
| 238 | case encode::F3_HALF_U => return Instr::Lhu { rd, rs1, imm }, |
| 239 | case encode::F3_WORD_U => return Instr::Lwu { rd, rs1, imm }, |
| 240 | else => return Instr::Unknown { bits: instr }, |
| 241 | } |
| 242 | }, |
| 243 | case encode::OP_STORE => { |
| 244 | let imm = immS(instr); |
| 245 | match f3 { |
| 246 | case encode::F3_BYTE => return Instr::Sb { rs2, rs1, imm }, |
| 247 | case encode::F3_HALF => return Instr::Sh { rs2, rs1, imm }, |
| 248 | case encode::F3_WORD => return Instr::Sw { rs2, rs1, imm }, |
| 249 | case encode::F3_DWORD => return Instr::Sd { rs2, rs1, imm }, |
| 250 | else => return Instr::Unknown { bits: instr }, |
| 251 | } |
| 252 | }, |
| 253 | case encode::OP_IMM => { |
| 254 | let imm = immI(instr); |
| 255 | match f3 { |
| 256 | case encode::F3_ADD => return Instr::Addi { rd, rs1, imm }, |
| 257 | case encode::F3_SLT => return Instr::Slti { rd, rs1, imm }, |
| 258 | case encode::F3_SLTU => return Instr::Sltiu { rd, rs1, imm }, |
| 259 | case encode::F3_XOR => return Instr::Xori { rd, rs1, imm }, |
| 260 | case encode::F3_OR => return Instr::Ori { rd, rs1, imm }, |
| 261 | case encode::F3_AND => return Instr::Andi { rd, rs1, imm }, |
| 262 | case encode::F3_SLL => return Instr::Slli { rd, rs1, shamt: imm & 0x3F }, |
| 263 | case encode::F3_SRL => { |
| 264 | let shamt = imm & 0x3F; |
| 265 | if (imm & 0x400) != 0 { |
| 266 | return Instr::Srai { rd, rs1, shamt }; |
| 267 | } else { |
| 268 | return Instr::Srli { rd, rs1, shamt }; |
| 269 | } |
| 270 | }, |
| 271 | else => return Instr::Unknown { bits: instr }, |
| 272 | } |
| 273 | }, |
| 274 | case encode::OP_OP => { |
| 275 | if f7 == encode::F7_MUL { |
| 276 | match f3 { |
| 277 | case encode::F3_ADD => return Instr::Mul { rd, rs1, rs2 }, |
| 278 | case encode::F3_SLL => return Instr::Mulh { rd, rs1, rs2 }, |
| 279 | case encode::F3_SLT => return Instr::Mulhsu { rd, rs1, rs2 }, |
| 280 | case encode::F3_SLTU => return Instr::Mulhu { rd, rs1, rs2 }, |
| 281 | case encode::F3_XOR => return Instr::Div { rd, rs1, rs2 }, |
| 282 | case encode::F3_SRL => return Instr::Divu { rd, rs1, rs2 }, |
| 283 | case encode::F3_OR => return Instr::Rem { rd, rs1, rs2 }, |
| 284 | case encode::F3_AND => return Instr::Remu { rd, rs1, rs2 }, |
| 285 | else => return Instr::Unknown { bits: instr }, |
| 286 | } |
| 287 | } else { |
| 288 | match f3 { |
| 289 | case encode::F3_ADD => { |
| 290 | if f7 == encode::F7_SUB { |
| 291 | return Instr::Sub { rd, rs1, rs2 }; |
| 292 | } else { |
| 293 | return Instr::Add { rd, rs1, rs2 }; |
| 294 | } |
| 295 | }, |
| 296 | case encode::F3_SLL => return Instr::Sll { rd, rs1, rs2 }, |
| 297 | case encode::F3_SLT => return Instr::Slt { rd, rs1, rs2 }, |
| 298 | case encode::F3_SLTU => return Instr::Sltu { rd, rs1, rs2 }, |
| 299 | case encode::F3_XOR => return Instr::Xor { rd, rs1, rs2 }, |
| 300 | case encode::F3_SRL => { |
| 301 | if f7 == encode::F7_SRA { |
| 302 | return Instr::Sra { rd, rs1, rs2 }; |
| 303 | } else { |
| 304 | return Instr::Srl { rd, rs1, rs2 }; |
| 305 | } |
| 306 | }, |
| 307 | case encode::F3_OR => return Instr::Or { rd, rs1, rs2 }, |
| 308 | case encode::F3_AND => return Instr::And { rd, rs1, rs2 }, |
| 309 | else => return Instr::Unknown { bits: instr }, |
| 310 | } |
| 311 | } |
| 312 | }, |
| 313 | case encode::OP_IMM32 => { |
| 314 | let imm = immI(instr); |
| 315 | match f3 { |
| 316 | case encode::F3_ADD => return Instr::Addiw { rd, rs1, imm }, |
| 317 | case encode::F3_SLL => return Instr::Slliw { rd, rs1, shamt: imm & 0x1F }, |
| 318 | case encode::F3_SRL => { |
| 319 | let shamt = imm & 0x1F; |
| 320 | if (imm & 0x400) != 0 { |
| 321 | return Instr::Sraiw { rd, rs1, shamt }; |
| 322 | } else { |
| 323 | return Instr::Srliw { rd, rs1, shamt }; |
| 324 | } |
| 325 | }, |
| 326 | else => return Instr::Unknown { bits: instr }, |
| 327 | } |
| 328 | }, |
| 329 | case encode::OP_OP32 => { |
| 330 | if f7 == encode::F7_MUL { |
| 331 | match f3 { |
| 332 | case encode::F3_ADD => return Instr::Mulw { rd, rs1, rs2 }, |
| 333 | case encode::F3_XOR => return Instr::Divw { rd, rs1, rs2 }, |
| 334 | case encode::F3_SRL => return Instr::Divuw { rd, rs1, rs2 }, |
| 335 | case encode::F3_OR => return Instr::Remw { rd, rs1, rs2 }, |
| 336 | case encode::F3_AND => return Instr::Remuw { rd, rs1, rs2 }, |
| 337 | else => return Instr::Unknown { bits: instr }, |
| 338 | } |
| 339 | } else { |
| 340 | match f3 { |
| 341 | case encode::F3_ADD => { |
| 342 | if f7 == encode::F7_SUB { |
| 343 | return Instr::Subw { rd, rs1, rs2 }; |
| 344 | } else { |
| 345 | return Instr::Addw { rd, rs1, rs2 }; |
| 346 | } |
| 347 | }, |
| 348 | case encode::F3_SLL => return Instr::Sllw { rd, rs1, rs2 }, |
| 349 | case encode::F3_SRL => { |
| 350 | if f7 == encode::F7_SRA { |
| 351 | return Instr::Sraw { rd, rs1, rs2 }; |
| 352 | } else { |
| 353 | return Instr::Srlw { rd, rs1, rs2 }; |
| 354 | } |
| 355 | }, |
| 356 | else => return Instr::Unknown { bits: instr }, |
| 357 | } |
| 358 | } |
| 359 | }, |
| 360 | case encode::OP_SYSTEM => { |
| 361 | let imm = immI(instr); |
| 362 | if imm == 0 { |
| 363 | return Instr::Ecall; |
| 364 | } else if imm == 1 { |
| 365 | return Instr::Ebreak; |
| 366 | } else { |
| 367 | return Instr::Unknown { bits: instr }; |
| 368 | } |
| 369 | }, |
| 370 | else => { |
| 371 | return Instr::Unknown { bits: instr }; |
| 372 | } |
| 373 | } |
| 374 | } |