1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Linq; 9 using System.Text.RegularExpressions; 10 using System.Collections.Generic; 11 12 namespace Antmicro.Renode.Peripherals.CPU 13 { 14 public class TBMRiscVHelper 15 { TBMRiscVHelper()16 static TBMRiscVHelper() 17 { 18 // Precompile some regular expressions 19 VectorStoreRegex = new Regex(@"(vse|vsuxei|vsse|vsoxei)\d+", RegexOptions.Compiled | RegexOptions.IgnoreCase); 20 AddressOffset1Regex = new Regex(@"^\d*\((\w+)\)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); 21 AddressOffset2Regex = new Regex(@"^(\w+)\s*[-+]\s*(\d+|0x[0-9a-fA-F]+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); 22 ImmediateRegex = new Regex(@"^(-?\d+|0x[0-9a-fA-F]+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); 23 VectorRegisterRegex = new Regex(@"^v(\d+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); 24 FloatRegisterRegex = new Regex(@"^f(\d+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); 25 IntegerRegisterRegex = new Regex(@"^x(\d+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); 26 } 27 28 /// <summary> Generate list of inputs and output registers from operands. </summary> 29 /// <param name="mnemonic"> assembly instruction mnemonic </param> 30 /// <param name="operands"> operands </param> 31 /// <returns> inputs: input registers outputs: output registers </returns> AsmRegisters(string mnemonic, string[] operands)32 public static Tuple<string[], string[]> AsmRegisters(string mnemonic, string[] operands) 33 { 34 string[] inputOps; 35 string[] outputOps; 36 37 if(mnemonic == "sb" || mnemonic == "sh" || mnemonic == "sw" || mnemonic == "sbu" || mnemonic == "shu" || mnemonic == "fsw" || mnemonic == "fsd" || VectorStoreRegex.Match(mnemonic).Success) 38 { 39 // store 40 inputOps = operands; 41 outputOps = new string[0]; 42 } 43 else if(mnemonic == "j" || mnemonic == "jr" || mnemonic == "c.j" || mnemonic.StartsWith("b")) 44 { 45 // jump/branch 46 inputOps = operands; 47 outputOps = new string[0]; 48 } 49 else if((mnemonic == "jal" || mnemonic == "jalr") && operands.Length == 1) 50 { 51 // pseudo-instructions 52 inputOps = operands; 53 outputOps = new string[] { "x1" }; 54 } 55 else 56 { 57 // default behaviour: first operand is destination, remainder are outputs 58 inputOps = operands.Skip(1).ToArray(); 59 outputOps = operands.Take(1).ToArray(); 60 } 61 62 var inputs = inputOps.Select(o => InputReg(o)).Where(r => r != null).ToArray(); 63 var outputs = outputOps.Where(o => !o.StartsWith("0")).ToArray(); 64 65 // Add implicit inputs and outputs of instructions 66 if(mnemonic.StartsWith("vset")) 67 { 68 outputs = outputs.Concat(new string[] { "vtype", "vl" }).ToArray(); 69 } 70 else if(mnemonic.StartsWith("v")) 71 { 72 inputs = inputs.Concat(new string[] { "vtype", "vl", "vstart" }).ToArray(); 73 } 74 75 return Tuple.Create(Normalize(inputs), Normalize(outputs)); 76 } 77 78 /// <summary> Extract a register from an input operand. </summary> 79 /// <param name="operand"> input operand </param> 80 /// <returns> register or null </returns> InputReg(string operand)81 public static string InputReg(string operand) 82 { 83 var m = AddressOffset1Regex.Match(operand); 84 if(m.Success) 85 { 86 return m.Groups[1].Value; 87 } 88 89 m = AddressOffset2Regex.Match(operand); 90 if(m.Success) 91 { 92 return m.Groups[1].Value; 93 } 94 95 if(ImmediateRegex.Match(operand).Success) 96 { 97 return null; 98 } 99 100 return operand; 101 } 102 103 /// <summary> Replace ABI register names with their architectural names and remove duplicates. </summary> 104 /// <param name="rs"> list of registers. </param> 105 /// <returns> list of normalized registers </returns> Normalize(string[] rs)106 public static string[] Normalize(string[] rs) 107 { 108 var arch = rs.Select(r => ABINames.TryGetValue(r, out var a) ? a : r); 109 var result = new HashSet<string>(arch); 110 result.RemoveWhere(r => BogusRegisters.Contains(r)); 111 return result.ToArray(); 112 } 113 IsNop(string mnemonic)114 public static bool IsNop(string mnemonic) 115 { 116 return NopInstructions.Contains(mnemonic); 117 } 118 IsBranch(string mnemonic)119 public static bool IsBranch(string mnemonic) 120 { 121 return BranchInstructions.Contains(mnemonic); 122 } 123 IsFlush(string mnemonic)124 public static bool IsFlush(string mnemonic) 125 { 126 return FlushInstructions.Contains(mnemonic); 127 } 128 IsVctrl(string mnemonic)129 public static bool IsVctrl(string mnemonic) 130 { 131 return VectorControlInstructions.Contains(mnemonic); 132 } 133 IsVectorRegister(string reg)134 public static bool IsVectorRegister(string reg) 135 { 136 return VectorRegisterRegex.Match(reg).Success; 137 } 138 IsFloatRegister(string reg)139 public static bool IsFloatRegister(string reg) 140 { 141 return FloatRegisterRegex.Match(reg).Success; 142 } 143 IsIntegerRegister(string reg)144 public static bool IsIntegerRegister(string reg) 145 { 146 /// Assumes that ABI register names were replaced with their architectural names 147 /// (e.g. x0, x1, ... instead of zero, ra, ...). It is done by <see cref="Normalize"/>. 148 return IntegerRegisterRegex.Match(reg).Success; 149 } 150 IsVectorInstruction(string[] inputs, string[] outputs)151 public static bool IsVectorInstruction(string[] inputs, string[] outputs) 152 { 153 // Only vector instructions access vector registers 154 return inputs.Any(IsVectorRegister) || outputs.Any(IsVectorRegister); 155 } 156 157 /// <summary> Get selected element width (SEW) from vector selected element width register (vsew). </summary> 158 /// <param name="vsew"> vsew register value </param> 159 /// <returns> selected element width </returns> GetSelectedElementWidth(ulong vsew)160 public static byte GetSelectedElementWidth(ulong vsew) 161 { 162 switch(vsew) 163 { 164 case 0b000: 165 return 8; 166 case 0b001: 167 return 16; 168 case 0b010: 169 return 32; 170 case 0b011: 171 return 64; 172 default: 173 // Reserved 174 return 0; 175 } 176 } 177 178 /// <summary> Get vector length multiplier (LMUL) from vector length multiplier register (vlmul). </summary> 179 /// <param name="vlmul"> vlmul register value </param> 180 /// <returns> vector length multiplier </returns> GetVectorLengthMultiplier(ulong vlmul)181 public static float GetVectorLengthMultiplier(ulong vlmul) 182 { 183 switch(vlmul) 184 { 185 case 0b000: 186 return 1; 187 case 0b001: 188 return 2; 189 case 0b010: 190 return 4; 191 case 0b011: 192 return 8; 193 case 0b111: 194 return 1/2; 195 case 0b110: 196 return 1/4; 197 case 0b101: 198 return 1/8; 199 default: 200 // Reserved 201 return 0; 202 } 203 } 204 205 private static readonly Regex VectorStoreRegex; 206 private static readonly Regex AddressOffset1Regex; 207 private static readonly Regex AddressOffset2Regex; 208 private static readonly Regex ImmediateRegex; 209 private static readonly Regex VectorRegisterRegex; 210 private static readonly Regex FloatRegisterRegex; 211 private static readonly Regex IntegerRegisterRegex; 212 213 private static readonly Dictionary<string, string> ABINames = new Dictionary<string, string>() 214 { 215 {"zero", "x0"}, 216 {"ra", "x1"}, 217 {"sp", "x2"}, 218 {"gp", "x3"}, 219 {"tp", "x4"}, 220 {"t0", "x5"}, 221 {"t1", "x6"}, 222 {"t2", "x7"}, 223 {"s0", "x8"}, 224 {"s1", "x9"}, 225 {"a0", "x10"}, 226 {"a1", "x11"}, 227 {"a2", "x12"}, 228 {"a3", "x13"}, 229 {"a4", "x14"}, 230 {"a5", "x15"}, 231 {"a6", "x16"}, 232 {"a7", "x17"}, 233 {"s2", "x18"}, 234 {"s3", "x19"}, 235 {"s4", "x20"}, 236 {"s5", "x21"}, 237 {"s6", "x22"}, 238 {"s7", "x23"}, 239 {"s8", "x24"}, 240 {"s9", "x25"}, 241 {"s10", "x26"}, 242 {"s11", "x27"}, 243 {"t3", "x28"}, 244 {"t4", "x29"}, 245 {"t5", "x30"}, 246 {"t6", "x31"}, 247 // This is the RVV mask register (not exactly abi). 248 {"v0.t", "v0"}, 249 }; 250 251 private static readonly string[] BogusRegisters = 252 { 253 "x0", 254 "e8", 255 "e16", 256 "e32", 257 "e64", 258 "e128", 259 "m1", 260 "m2", 261 "m4", 262 "m8", 263 "m16", 264 "ta", 265 "tu", 266 "ma", 267 "mu", 268 }; 269 270 private static readonly string[] NopInstructions = 271 { 272 "nop", 273 "c.nop", 274 "fence", 275 "fence.i", 276 "sfence.vma", 277 "wfi", 278 }; 279 280 private static readonly string[] BranchInstructions = 281 { 282 "beq", 283 "bne", 284 "blt", 285 "bge", 286 "bltu", 287 "bgeu", 288 "jal", 289 "jalr", 290 "bnez", 291 "beqz", 292 "blez", 293 "bgez", 294 "bltz", 295 "bgtz", 296 "bleu", 297 "bgtu", 298 "j", 299 "c.j", 300 "jr", 301 "ret", 302 "sret", 303 "mret", 304 "ecall", 305 "ebreak", 306 }; 307 308 private static readonly string[] FlushInstructions = 309 { 310 "csrr", 311 "csrw", 312 "csrs", 313 "csrwi", 314 "csrrw", 315 "csrrs", 316 "csrrc", 317 "csrrwi", 318 "csrrsi", 319 "csrrci", 320 "fence", 321 "fence.i", 322 "sfence.vma", 323 }; 324 325 private static readonly string[] VectorControlInstructions = 326 { 327 "vsetivli", 328 "vsetvli", 329 "vsetvl", 330 }; 331 332 // Incomplete list of control/status registers. 333 private static readonly string[] CSRInstructions = 334 { 335 "cycle", 336 "cycleh", 337 "dcsr", 338 "dpc", 339 "dscratch0", 340 "dscratch1", 341 "fcsr", 342 "fflags", 343 "frm", 344 "hcounteren", 345 "hedeleg", 346 "hgatp", 347 "hgeie", 348 "hgeip", 349 "hideleg", 350 "hie", 351 "hip", 352 "hstatus", 353 "htimedelta", 354 "htimedeltah", 355 "htinst", 356 "htval", 357 "hvip", 358 "instret", 359 "instreth", 360 "marchid", 361 "mcause", 362 "mcontext", 363 "mcounteren", 364 "mcountinhibit", 365 "mcycle", 366 "medeleg", 367 "mepc", 368 "mhartid", 369 "mideleg", 370 "mie", 371 "mimpid", 372 "minstret", 373 "mintstatus", 374 "mip", 375 "misa", 376 "mnxti", 377 "mscratch", 378 "mscratchcsw", 379 "mscratchcswl", 380 "mstatus", 381 "mtinst", 382 "mtval", 383 "mtval2", 384 "mtvec", 385 "mtvt", 386 "mvendorid", 387 "pmpaddr0", 388 "pmpaddr1", 389 "pmpaddr10", 390 "pmpaddr11", 391 "pmpaddr12", 392 "pmpaddr13", 393 "pmpaddr14", 394 "pmpaddr15", 395 "pmpaddr2", 396 "pmpaddr3", 397 "pmpaddr4", 398 "pmpaddr5", 399 "pmpaddr6", 400 "pmpaddr7", 401 "pmpaddr8", 402 "pmpaddr9", 403 "pmpcfg0", 404 "pmpcfg1", 405 "pmpcfg2", 406 "pmpcfg3", 407 "satp", 408 "scause", 409 "scontext", 410 "scounteren", 411 "sedeleg", 412 "sentropy", 413 "sepc", 414 "sideleg", 415 "sie", 416 "sintstatus", 417 "sip", 418 "snxti", 419 "sscratch", 420 "sscratchcsw", 421 "sscratchcswl", 422 "sstatus", 423 "stval", 424 "stvec", 425 "stvt", 426 "tcontrol", 427 "tdata1", 428 "tdata2", 429 "tdata3", 430 "time", 431 "timeh", 432 "tinfo", 433 "tselect", 434 "ucause", 435 "uepc", 436 "uie", 437 "uintstatus", 438 "uip", 439 "unxti", 440 "uscratch", 441 "uscratchcsw", 442 "uscratchcswl", 443 "ustatus", 444 "utval", 445 "utvec", 446 "utvt", 447 "vcsr", 448 "vl", 449 "vlenb", 450 "vsatp", 451 "vscause", 452 "vsepc", 453 "vsie", 454 "vsip", 455 "vsscratch", 456 "vsstatus", 457 "vstart", 458 "vstval", 459 "vstvec", 460 "vtype", 461 "vxrm", 462 "vxsat", 463 }; 464 } 465 } 466