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