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