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