../src/lowrisc_ibex_ibex_tracer_0.1/rtl/ibex_tracer.sv Cov: 100%
1: // Copyright lowRISC contributors.
2: // Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
3: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
4: // SPDX-License-Identifier: Apache-2.0
5:
6: /**
7: * Trace executed instructions in simulation
8: *
9: * This tracer takes execution information from the RISC-V Verification Interface (RVFI) and
10: * produces a text file with a human-readable trace.
11: *
12: * All traced instructions are written to a log file. By default, the log file is named
13: * trace_core_.log, with being the 8 digit hart ID of the core being traced.
14: *
15: * The file name base, defaulting to "trace_core" can be set using the "ibex_tracer_file_base"
16: * plusarg passed to the simulation, e.g. "+ibex_tracer_file_base=ibex_my_trace". The exact syntax
17: * of passing plusargs to a simulation depends on the simulator.
18: *
19: * The trace contains six columns, separated by tabs:
20: * - The simulation time
21: * - The clock cycle count since reset
22: * - The program counter (PC)
23: * - The instruction
24: * - The decoded instruction in the same format as objdump, together with the accessed registers and
25: * read/written memory values. Jumps and branches show the target address.
26: * This column may be omitted if the instruction does not decode into a long form.
27: * - Accessed registers and memory locations.
28: *
29: * Significant effort is spent to make the decoding produced by this tracer as similar as possible
30: * to the one produced by objdump. This simplifies the correlation between the static program
31: * information from the objdump-generated disassembly, and the runtime information from this tracer.
32: */
33: module ibex_tracer (
34: input logic clk_i,
35: input logic rst_ni,
36:
37: input logic [31:0] hart_id_i,
38:
39: // RVFI as described at https://github.com/SymbioticEDA/riscv-formal/blob/master/docs/rvfi.md
40: // The standard interface does not have _i/_o suffixes. For consistency with the standard the
41: // signals in this module don't have the suffixes either.
42: input logic rvfi_valid,
43: input logic [63:0] rvfi_order,
44: input logic [31:0] rvfi_insn,
45: input logic rvfi_trap,
46: input logic rvfi_halt,
47: input logic rvfi_intr,
48: input logic [ 1:0] rvfi_mode,
49: input logic [ 1:0] rvfi_ixl,
50: input logic [ 4:0] rvfi_rs1_addr,
51: input logic [ 4:0] rvfi_rs2_addr,
52: input logic [ 4:0] rvfi_rs3_addr,
53: input logic [31:0] rvfi_rs1_rdata,
54: input logic [31:0] rvfi_rs2_rdata,
55: input logic [31:0] rvfi_rs3_rdata,
56: input logic [ 4:0] rvfi_rd_addr,
57: input logic [31:0] rvfi_rd_wdata,
58: input logic [31:0] rvfi_pc_rdata,
59: input logic [31:0] rvfi_pc_wdata,
60: input logic [31:0] rvfi_mem_addr,
61: input logic [ 3:0] rvfi_mem_rmask,
62: input logic [ 3:0] rvfi_mem_wmask,
63: input logic [31:0] rvfi_mem_rdata,
64: input logic [31:0] rvfi_mem_wdata
65: );
66:
67: // These signals are part of RVFI, but not used in this module currently.
68: // Keep them as part of the interface to change the tracer more easily in the future. Assigning
69: // these signals to unused_* signals marks them explicitly as unused, an annotation picked up by
70: // linters, including Verilator lint.
71: logic [63:0] unused_rvfi_order = rvfi_order;
72: logic unused_rvfi_trap = rvfi_trap;
73: logic unused_rvfi_halt = rvfi_halt;
74: logic unused_rvfi_intr = rvfi_intr;
75: logic [ 1:0] unused_rvfi_mode = rvfi_mode;
76: logic [ 1:0] unused_rvfi_ixl = rvfi_ixl;
77:
78: import ibex_tracer_pkg::*;
79:
80: int file_handle;
81: string file_name;
82:
83: int unsigned cycle;
84: string decoded_str;
85: logic insn_is_compressed;
86:
87: // Data items accessed during this instruction
88: localparam RS1 = (1 << 0);
89: localparam RS2 = (1 << 1);
90: localparam RS3 = (1 << 2);
91: localparam RD = (1 << 3);
92: localparam MEM = (1 << 4);
93: logic [4:0] data_accessed;
94:
95: function automatic void printbuffer_dumpline();
96: string rvfi_insn_str;
97:
98: if (file_handle == 32'h0) begin
99: string file_name_base = "trace_core";
100: $value$plusargs("ibex_tracer_file_base=%s", file_name_base);
101: $sformat(file_name, "%s_%h.log", file_name_base, hart_id_i);
102:
103: $display("%m: Writing execution trace to %s", file_name);
104: file_handle = $fopen(file_name, "w");
105: $fwrite(file_handle, "Time\tCycle\tPC\tInsn\tDecoded instruction\tRegister and memory contents\n");
106: end
107:
108: // Write compressed instructions as four hex digits (16 bit word), and
109: // uncompressed ones as 8 hex digits (32 bit words).
110: if (insn_is_compressed) begin
111: rvfi_insn_str = $sformatf("%h", rvfi_insn[15:0]);
112: end else begin
113: rvfi_insn_str = $sformatf("%h", rvfi_insn);
114: end
115:
116: $fwrite(file_handle, "%15t\t%d\t%h\t%s\t%s\t", $time, cycle, rvfi_pc_rdata, rvfi_insn_str, decoded_str);
117:
118: if ((data_accessed & RS1) != 0) begin
119: $fwrite(file_handle, " %s:0x%08x", reg_addr_to_str(rvfi_rs1_addr), rvfi_rs1_rdata);
120: end
121: if ((data_accessed & RS2) != 0) begin
122: $fwrite(file_handle, " %s:0x%08x", reg_addr_to_str(rvfi_rs2_addr), rvfi_rs2_rdata);
123: end
124: if ((data_accessed & RS3) != 0) begin
125: $fwrite(file_handle, " %s:0x%08x", reg_addr_to_str(rvfi_rs3_addr), rvfi_rs3_rdata);
126: end
127: if ((data_accessed & RD) != 0) begin
128: $fwrite(file_handle, " %s=0x%08x", reg_addr_to_str(rvfi_rd_addr), rvfi_rd_wdata);
129: end
130: if ((data_accessed & MEM) != 0) begin
131: $fwrite(file_handle, " PA:0x%08x", rvfi_mem_addr);
132:
133: if (rvfi_mem_rmask != 4'b000) begin
134: $fwrite(file_handle, " store:0x%08x", rvfi_mem_wdata);
135: end
136: if (rvfi_mem_wmask != 4'b000) begin
137: $fwrite(file_handle, " load:0x%08x", rvfi_mem_rdata);
138: end
139: end
140:
141: $fwrite(file_handle, "\n");
142: endfunction
143:
144:
145: // Format register address with "x" prefix, left-aligned to a fixed width of 3 characters.
146: function automatic string reg_addr_to_str(input logic [4:0] addr);
147: if (addr < 10) begin
148: return $sformatf(" x%0d", addr);
149: end else begin
150: return $sformatf("x%0d", addr);
151: end
152: endfunction
153:
154: // Get a CSR name for a CSR address.
155: function automatic string get_csr_name(input logic [11:0] csr_addr);
156: unique case (csr_addr)
157: 12'd0: return "ustatus";
158: 12'd4: return "uie";
159: 12'd5: return "utvec";
160: 12'd64: return "uscratch";
161: 12'd65: return "uepc";
162: 12'd66: return "ucause";
163: 12'd67: return "utval";
164: 12'd68: return "uip";
165: 12'd1: return "fflags";
166: 12'd2: return "frm";
167: 12'd3: return "fcsr";
168: 12'd3072: return "cycle";
169: 12'd3073: return "time";
170: 12'd3074: return "instret";
171: 12'd3075: return "hpmcounter3";
172: 12'd3076: return "hpmcounter4";
173: 12'd3077: return "hpmcounter5";
174: 12'd3078: return "hpmcounter6";
175: 12'd3079: return "hpmcounter7";
176: 12'd3080: return "hpmcounter8";
177: 12'd3081: return "hpmcounter9";
178: 12'd3082: return "hpmcounter10";
179: 12'd3083: return "hpmcounter11";
180: 12'd3084: return "hpmcounter12";
181: 12'd3085: return "hpmcounter13";
182: 12'd3086: return "hpmcounter14";
183: 12'd3087: return "hpmcounter15";
184: 12'd3088: return "hpmcounter16";
185: 12'd3089: return "hpmcounter17";
186: 12'd3090: return "hpmcounter18";
187: 12'd3091: return "hpmcounter19";
188: 12'd3092: return "hpmcounter20";
189: 12'd3093: return "hpmcounter21";
190: 12'd3094: return "hpmcounter22";
191: 12'd3095: return "hpmcounter23";
192: 12'd3096: return "hpmcounter24";
193: 12'd3097: return "hpmcounter25";
194: 12'd3098: return "hpmcounter26";
195: 12'd3099: return "hpmcounter27";
196: 12'd3100: return "hpmcounter28";
197: 12'd3101: return "hpmcounter29";
198: 12'd3102: return "hpmcounter30";
199: 12'd3103: return "hpmcounter31";
200: 12'd3200: return "cycleh";
201: 12'd3201: return "timeh";
202: 12'd3202: return "instreth";
203: 12'd3203: return "hpmcounter3h";
204: 12'd3204: return "hpmcounter4h";
205: 12'd3205: return "hpmcounter5h";
206: 12'd3206: return "hpmcounter6h";
207: 12'd3207: return "hpmcounter7h";
208: 12'd3208: return "hpmcounter8h";
209: 12'd3209: return "hpmcounter9h";
210: 12'd3210: return "hpmcounter10h";
211: 12'd3211: return "hpmcounter11h";
212: 12'd3212: return "hpmcounter12h";
213: 12'd3213: return "hpmcounter13h";
214: 12'd3214: return "hpmcounter14h";
215: 12'd3215: return "hpmcounter15h";
216: 12'd3216: return "hpmcounter16h";
217: 12'd3217: return "hpmcounter17h";
218: 12'd3218: return "hpmcounter18h";
219: 12'd3219: return "hpmcounter19h";
220: 12'd3220: return "hpmcounter20h";
221: 12'd3221: return "hpmcounter21h";
222: 12'd3222: return "hpmcounter22h";
223: 12'd3223: return "hpmcounter23h";
224: 12'd3224: return "hpmcounter24h";
225: 12'd3225: return "hpmcounter25h";
226: 12'd3226: return "hpmcounter26h";
227: 12'd3227: return "hpmcounter27h";
228: 12'd3228: return "hpmcounter28h";
229: 12'd3229: return "hpmcounter29h";
230: 12'd3230: return "hpmcounter30h";
231: 12'd3231: return "hpmcounter31h";
232: 12'd256: return "sstatus";
233: 12'd258: return "sedeleg";
234: 12'd259: return "sideleg";
235: 12'd260: return "sie";
236: 12'd261: return "stvec";
237: 12'd262: return "scounteren";
238: 12'd320: return "sscratch";
239: 12'd321: return "sepc";
240: 12'd322: return "scause";
241: 12'd323: return "stval";
242: 12'd324: return "sip";
243: 12'd384: return "satp";
244: 12'd3857: return "mvendorid";
245: 12'd3858: return "marchid";
246: 12'd3859: return "mimpid";
247: 12'd3860: return "mhartid";
248: 12'd768: return "mstatus";
249: 12'd769: return "misa";
250: 12'd770: return "medeleg";
251: 12'd771: return "mideleg";
252: 12'd772: return "mie";
253: 12'd773: return "mtvec";
254: 12'd774: return "mcounteren";
255: 12'd832: return "mscratch";
256: 12'd833: return "mepc";
257: 12'd834: return "mcause";
258: 12'd835: return "mtval";
259: 12'd836: return "mip";
260: 12'd928: return "pmpcfg0";
261: 12'd929: return "pmpcfg1";
262: 12'd930: return "pmpcfg2";
263: 12'd931: return "pmpcfg3";
264: 12'd944: return "pmpaddr0";
265: 12'd945: return "pmpaddr1";
266: 12'd946: return "pmpaddr2";
267: 12'd947: return "pmpaddr3";
268: 12'd948: return "pmpaddr4";
269: 12'd949: return "pmpaddr5";
270: 12'd950: return "pmpaddr6";
271: 12'd951: return "pmpaddr7";
272: 12'd952: return "pmpaddr8";
273: 12'd953: return "pmpaddr9";
274: 12'd954: return "pmpaddr10";
275: 12'd955: return "pmpaddr11";
276: 12'd956: return "pmpaddr12";
277: 12'd957: return "pmpaddr13";
278: 12'd958: return "pmpaddr14";
279: 12'd959: return "pmpaddr15";
280: 12'd2816: return "mcycle";
281: 12'd2818: return "minstret";
282: 12'd2819: return "mhpmcounter3";
283: 12'd2820: return "mhpmcounter4";
284: 12'd2821: return "mhpmcounter5";
285: 12'd2822: return "mhpmcounter6";
286: 12'd2823: return "mhpmcounter7";
287: 12'd2824: return "mhpmcounter8";
288: 12'd2825: return "mhpmcounter9";
289: 12'd2826: return "mhpmcounter10";
290: 12'd2827: return "mhpmcounter11";
291: 12'd2828: return "mhpmcounter12";
292: 12'd2829: return "mhpmcounter13";
293: 12'd2830: return "mhpmcounter14";
294: 12'd2831: return "mhpmcounter15";
295: 12'd2832: return "mhpmcounter16";
296: 12'd2833: return "mhpmcounter17";
297: 12'd2834: return "mhpmcounter18";
298: 12'd2835: return "mhpmcounter19";
299: 12'd2836: return "mhpmcounter20";
300: 12'd2837: return "mhpmcounter21";
301: 12'd2838: return "mhpmcounter22";
302: 12'd2839: return "mhpmcounter23";
303: 12'd2840: return "mhpmcounter24";
304: 12'd2841: return "mhpmcounter25";
305: 12'd2842: return "mhpmcounter26";
306: 12'd2843: return "mhpmcounter27";
307: 12'd2844: return "mhpmcounter28";
308: 12'd2845: return "mhpmcounter29";
309: 12'd2846: return "mhpmcounter30";
310: 12'd2847: return "mhpmcounter31";
311: 12'd2944: return "mcycleh";
312: 12'd2946: return "minstreth";
313: 12'd2947: return "mhpmcounter3h";
314: 12'd2948: return "mhpmcounter4h";
315: 12'd2949: return "mhpmcounter5h";
316: 12'd2950: return "mhpmcounter6h";
317: 12'd2951: return "mhpmcounter7h";
318: 12'd2952: return "mhpmcounter8h";
319: 12'd2953: return "mhpmcounter9h";
320: 12'd2954: return "mhpmcounter10h";
321: 12'd2955: return "mhpmcounter11h";
322: 12'd2956: return "mhpmcounter12h";
323: 12'd2957: return "mhpmcounter13h";
324: 12'd2958: return "mhpmcounter14h";
325: 12'd2959: return "mhpmcounter15h";
326: 12'd2960: return "mhpmcounter16h";
327: 12'd2961: return "mhpmcounter17h";
328: 12'd2962: return "mhpmcounter18h";
329: 12'd2963: return "mhpmcounter19h";
330: 12'd2964: return "mhpmcounter20h";
331: 12'd2965: return "mhpmcounter21h";
332: 12'd2966: return "mhpmcounter22h";
333: 12'd2967: return "mhpmcounter23h";
334: 12'd2968: return "mhpmcounter24h";
335: 12'd2969: return "mhpmcounter25h";
336: 12'd2970: return "mhpmcounter26h";
337: 12'd2971: return "mhpmcounter27h";
338: 12'd2972: return "mhpmcounter28h";
339: 12'd2973: return "mhpmcounter29h";
340: 12'd2974: return "mhpmcounter30h";
341: 12'd2975: return "mhpmcounter31h";
342: 12'd803: return "mhpmevent3";
343: 12'd804: return "mhpmevent4";
344: 12'd805: return "mhpmevent5";
345: 12'd806: return "mhpmevent6";
346: 12'd807: return "mhpmevent7";
347: 12'd808: return "mhpmevent8";
348: 12'd809: return "mhpmevent9";
349: 12'd810: return "mhpmevent10";
350: 12'd811: return "mhpmevent11";
351: 12'd812: return "mhpmevent12";
352: 12'd813: return "mhpmevent13";
353: 12'd814: return "mhpmevent14";
354: 12'd815: return "mhpmevent15";
355: 12'd816: return "mhpmevent16";
356: 12'd817: return "mhpmevent17";
357: 12'd818: return "mhpmevent18";
358: 12'd819: return "mhpmevent19";
359: 12'd820: return "mhpmevent20";
360: 12'd821: return "mhpmevent21";
361: 12'd822: return "mhpmevent22";
362: 12'd823: return "mhpmevent23";
363: 12'd824: return "mhpmevent24";
364: 12'd825: return "mhpmevent25";
365: 12'd826: return "mhpmevent26";
366: 12'd827: return "mhpmevent27";
367: 12'd828: return "mhpmevent28";
368: 12'd829: return "mhpmevent29";
369: 12'd830: return "mhpmevent30";
370: 12'd831: return "mhpmevent31";
371: 12'd1952: return "tselect";
372: 12'd1953: return "tdata1";
373: 12'd1954: return "tdata2";
374: 12'd1955: return "tdata3";
375: 12'd1968: return "dcsr";
376: 12'd1969: return "dpc";
377: 12'd1970: return "dscratch";
378: 12'd512: return "hstatus";
379: 12'd514: return "hedeleg";
380: 12'd515: return "hideleg";
381: 12'd516: return "hie";
382: 12'd517: return "htvec";
383: 12'd576: return "hscratch";
384: 12'd577: return "hepc";
385: 12'd578: return "hcause";
386: 12'd579: return "hbadaddr";
387: 12'd580: return "hip";
388: 12'd896: return "mbase";
389: 12'd897: return "mbound";
390: 12'd898: return "mibase";
391: 12'd899: return "mibound";
392: 12'd900: return "mdbase";
393: 12'd901: return "mdbound";
394: 12'd800: return "mucounteren";
395: 12'd801: return "mscounteren";
396: 12'd802: return "mhcounteren";
397: default: return $sformatf("0x%x", csr_addr);
398: endcase
399: endfunction
400:
401: function automatic void decode_mnemonic(input string mnemonic);
402: decoded_str = mnemonic;
403: endfunction
404:
405: function automatic void decode_r_insn(input string mnemonic);
406: data_accessed = RS1 | RS2 | RD;
407: decoded_str = $sformatf("%s\tx%0d,x%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs1_addr,
408: rvfi_rs2_addr);
409: endfunction
410:
411: function automatic void decode_r1_insn(input string mnemonic);
412: data_accessed = RS1 | RD;
413: decoded_str = $sformatf("%s\tx%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs1_addr);
414: endfunction
415:
416: function automatic void decode_r_cmixcmov_insn(input string mnemonic);
417: data_accessed = RS1 | RS2 | RS3 | RD;
418: decoded_str = $sformatf("%s\tx%0d,x%0d,x%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs2_addr,
419: rvfi_rs1_addr, rvfi_rs3_addr);
420: endfunction
421:
422: function automatic void decode_r_funnelshift_insn(input string mnemonic);
423: data_accessed = RS1 | RS2 | RS3 | RD;
424: decoded_str = $sformatf("%s\tx%0d,x%0d,x%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs1_addr,
425: rvfi_rs3_addr, rvfi_rs2_addr);
426: endfunction
427:
428: function automatic void decode_i_insn(input string mnemonic);
429: data_accessed = RS1 | RD;
430: decoded_str = $sformatf("%s\tx%0d,x%0d,%0d", mnemonic, rvfi_rd_addr, rvfi_rs1_addr,
431: $signed({{20 {rvfi_insn[31]}}, rvfi_insn[31:20]}));
432: endfunction
433:
434: function automatic void decode_i_shift_insn(input string mnemonic);
435: // SLLI, SRLI, SRAI, SROI, SLOI, RORI
436: logic [4:0] shamt;
437: shamt = {rvfi_insn[24:20]};
438: data_accessed = RS1 | RD;
439: decoded_str = $sformatf("%s\tx%0d,x%0d,0x%0x", mnemonic, rvfi_rd_addr, rvfi_rs1_addr, shamt);
440: endfunction
441:
442: function automatic void decode_i_funnelshift_insn( input string mnemonic);
443: // fsri
444: logic [5:0] shamt;
445: shamt = {rvfi_insn[25:20]};
446: data_accessed = RS1 | RS3 | RD;
447: decoded_str = $sformatf("%s\tx%0d,x%0d,x%0d,0x%0x", mnemonic, rvfi_rd_addr, rvfi_rs1_addr,
448: rvfi_rs3_addr, shamt);
449: endfunction
450:
451: function automatic void decode_i_jalr_insn(input string mnemonic);
452: // JALR
453: data_accessed = RS1 | RD;
454: decoded_str = $sformatf("%s\tx%0d,%0d(x%0d)", mnemonic, rvfi_rd_addr,
455: $signed({{20 {rvfi_insn[31]}}, rvfi_insn[31:20]}), rvfi_rs1_addr);
456: endfunction
457:
458: function automatic void decode_u_insn(input string mnemonic);
459: data_accessed = RD;
460: decoded_str = $sformatf("%s\tx%0d,0x%0x", mnemonic, rvfi_rd_addr, {rvfi_insn[31:12]});
461: endfunction
462:
463: function automatic void decode_j_insn(input string mnemonic);
464: // JAL
465: data_accessed = RD;
466: decoded_str = $sformatf("%s\tx%0d,%0x", mnemonic, rvfi_rd_addr, rvfi_pc_wdata);
467: endfunction
468:
469: function automatic void decode_b_insn(input string mnemonic);
470: logic [31:0] branch_target;
471: logic [31:0] imm;
472:
473: // We cannot use rvfi_pc_wdata for conditional jumps.
474: imm = $signed({ {19 {rvfi_insn[31]}}, rvfi_insn[31], rvfi_insn[7],
475: rvfi_insn[30:25], rvfi_insn[11:8], 1'b0 });
476: branch_target = rvfi_pc_rdata + imm;
477:
478: data_accessed = RS1 | RS2 | RD;
479: decoded_str = $sformatf("%s\tx%0d,x%0d,%0x", mnemonic, rvfi_rs1_addr, rvfi_rs2_addr, branch_target);
480: endfunction
481:
482: function automatic void decode_csr_insn(input string mnemonic);
483: logic [11:0] csr;
484: string csr_name;
485: csr = rvfi_insn[31:20];
486: csr_name = get_csr_name(csr);
487:
488: data_accessed = RD;
489:
490: if (!rvfi_insn[14]) begin
491: data_accessed |= RS1;
492: decoded_str = $sformatf("%s\tx%0d,%s,x%0d", mnemonic, rvfi_rd_addr, csr_name, rvfi_rs1_addr);
493: end else begin
494: decoded_str = $sformatf("%s\tx%0d,%s,%0d", mnemonic, rvfi_rd_addr, csr_name, { 27'b0, rvfi_insn[19:15]});
495: end
496: endfunction
497:
498: function automatic void decode_cr_insn(input string mnemonic);
499: if (rvfi_rs2_addr == 5'b0) begin
500: if (rvfi_insn[12] == 1'b1) begin
501: // C.JALR
502: data_accessed = RS1 | RD;
503: end else begin
504: // C.JR
505: data_accessed = RS1;
506: end
507: decoded_str = $sformatf("%s\tx%0d", mnemonic, rvfi_rs1_addr);
508: end else begin
509: data_accessed = RS1 | RS2 | RD; // RS1 == RD
510: decoded_str = $sformatf("%s\tx%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs2_addr);
511: end
512: endfunction
513:
514: function automatic void decode_ci_cli_insn(input string mnemonic);
515: logic [5:0] imm;
516: imm = {rvfi_insn[12], rvfi_insn[6:2]};
517: data_accessed = RD;
518: decoded_str = $sformatf("%s\tx%0d,%0d", mnemonic, rvfi_rd_addr, $signed(imm));
519: endfunction
520:
521: function automatic void decode_ci_caddi_insn(input string mnemonic);
522: logic [5:0] nzimm;
523: nzimm = {rvfi_insn[12], rvfi_insn[6:2]};
524: data_accessed = RS1 | RD;
525: decoded_str = $sformatf("%s\tx%0d,%0d", mnemonic, rvfi_rd_addr, $signed(nzimm));
526: endfunction
527:
528: function automatic void decode_ci_caddi16sp_insn(input string mnemonic);
529: logic [9:0] nzimm;
530: nzimm = {rvfi_insn[12], rvfi_insn[4:3], rvfi_insn[5], rvfi_insn[2], rvfi_insn[6], 4'b0};
531: data_accessed = RS1 | RD;
532: decoded_str = $sformatf("%s\tx%0d,%0d", mnemonic, rvfi_rd_addr, $signed(nzimm));
533: endfunction
534:
535: function automatic void decode_ci_clui_insn(input string mnemonic);
536: logic [5:0] nzimm;
537: nzimm = {rvfi_insn[12], rvfi_insn[6:2]};
538: data_accessed = RD;
539: decoded_str = $sformatf("%s\tx%0d,0x%0x", mnemonic, rvfi_rd_addr, 20'($signed(nzimm)));
540: endfunction
541:
542: function automatic void decode_ci_cslli_insn(input string mnemonic);
543: logic [5:0] shamt;
544: shamt = {rvfi_insn[12], rvfi_insn[6:2]};
545: data_accessed = RS1 | RD;
546: decoded_str = $sformatf("%s\tx%0d,0x%0x", mnemonic, rvfi_rd_addr, shamt);
547: endfunction
548:
549: function automatic void decode_ciw_insn(input string mnemonic);
550: // C.ADDI4SPN
551: logic [9:0] nzuimm;
552: nzuimm = {rvfi_insn[10:7], rvfi_insn[12:11], rvfi_insn[5], rvfi_insn[6], 2'b00};
553: data_accessed = RD;
554: decoded_str = $sformatf("%s\tx%0d,x2,%0d", mnemonic, rvfi_rd_addr, nzuimm);
555: endfunction
556:
557: function automatic void decode_cb_sr_insn(input string mnemonic);
558: logic [5:0] shamt;
559: shamt = {rvfi_insn[12], rvfi_insn[6:2]};
560: data_accessed = RS1 | RD;
561: decoded_str = $sformatf("%s\tx%0d,0x%0x", mnemonic, rvfi_rs1_addr, shamt);
562: endfunction
563:
564: function automatic void decode_cb_insn(input string mnemonic);
565: logic [7:0] imm;
566: logic [31:0] jump_target;
567: if (rvfi_insn[15:13] == 3'b110 || rvfi_insn[15:13] == 3'b111) begin
568: // C.BNEZ and C.BEQZ
569: // We cannot use rvfi_pc_wdata for conditional jumps.
570: imm = {rvfi_insn[12], rvfi_insn[6:5], rvfi_insn[2], rvfi_insn[11:10], rvfi_insn[4:3]};
571: jump_target = rvfi_pc_rdata + 32'($signed({imm, 1'b0}));
572: data_accessed = RS1;
573: decoded_str = $sformatf("%s\tx%0d,%0x", mnemonic, rvfi_rs1_addr, jump_target);
574: end else if (rvfi_insn[15:13] == 3'b100) begin
575: // C.ANDI
576: imm = {{2{rvfi_insn[12]}}, rvfi_insn[12], rvfi_insn[6:2]};
577: data_accessed = RS1 | RD; // RS1 == RD
578: decoded_str = $sformatf("%s\tx%0d,%0d", mnemonic, rvfi_rd_addr, $signed(imm));
579: end else begin
580: imm = {rvfi_insn[12], rvfi_insn[6:2], 2'b00};
581: data_accessed = RS1;
582: decoded_str = $sformatf("%s\tx%0d,0x%0x", mnemonic, rvfi_rs1_addr, imm);
583: end
584: endfunction
585:
586: function automatic void decode_cs_insn(input string mnemonic);
587: data_accessed = RS1 | RS2 | RD; // RS1 == RD
588: decoded_str = $sformatf("%s\tx%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs2_addr);
589: endfunction
590:
591: function automatic void decode_cj_insn(input string mnemonic);
592: if (rvfi_insn[15:13] == 3'b001) begin
593: // C.JAL
594: data_accessed = RD;
595: end
596: decoded_str = $sformatf("%s\t%0x", mnemonic, rvfi_pc_wdata);
597: endfunction
598:
599: function automatic void decode_compressed_load_insn(input string mnemonic);
600: logic [7:0] imm;
601:
602: if (rvfi_insn[1:0] == OPCODE_C0) begin
603: // C.LW
604: imm = {1'b0, rvfi_insn[5], rvfi_insn[12:10], rvfi_insn[6], 2'b00};
605: end else begin
606: // C.LWSP
607: imm = {rvfi_insn[3:2], rvfi_insn[12], rvfi_insn[6:4], 2'b00};
608: end
609: data_accessed = RS1 | RD | MEM;
610: decoded_str = $sformatf("%s\tx%0d,%0d(x%0d)", mnemonic, rvfi_rd_addr, imm, rvfi_rs1_addr);
611: endfunction
612:
613: function automatic void decode_compressed_store_insn(input string mnemonic);
614: logic [7:0] imm;
615: if (rvfi_insn[1:0] == OPCODE_C0) begin
616: // C.SW
617: imm = {1'b0, rvfi_insn[5], rvfi_insn[12:10], rvfi_insn[6], 2'b00};
618: end else begin
619: // C.SWSP
620: imm = {rvfi_insn[8:7], rvfi_insn[12:9], 2'b00};
621: end
622: data_accessed = RS1 | RS2 | MEM;
623: decoded_str = $sformatf("%s\tx%0d,%0d(x%0d)", mnemonic, rvfi_rs2_addr, imm, rvfi_rs1_addr);
624: endfunction
625:
626: function automatic void decode_load_insn();
627: string mnemonic;
628:
629: /*
630: Gives wrong results in Verilator < 4.020.
631: See https://github.com/lowRISC/ibex/issues/372 and
632: https://www.veripool.org/issues/1536-Verilator-Misoptimization-in-if-and-case-with-default-statement-inside-a-function
633:
634: unique case (rvfi_insn[14:12])
635: 3'b000: mnemonic = "lb";
636: 3'b001: mnemonic = "lh";
637: 3'b010: mnemonic = "lw";
638: 3'b100: mnemonic = "lbu";
639: 3'b101: mnemonic = "lhu";
640: default: begin
641: decode_mnemonic("INVALID");
642: return;
643: end
644: endcase
645: */
646: logic [2:0] size;
647: size = rvfi_insn[14:12];
648: if (size == 3'b000) begin
649: mnemonic = "lb";
650: end else if (size == 3'b001) begin
651: mnemonic = "lh";
652: end else if (size == 3'b010) begin
653: mnemonic = "lw";
654: end else if (size == 3'b100) begin
655: mnemonic = "lbu";
656: end else if (size == 3'b101) begin
657: mnemonic = "lhu";
658: end else begin
659: decode_mnemonic("INVALID");
660: return;
661: end
662:
663:
664: data_accessed = RD | RS1 | MEM;
665: decoded_str = $sformatf("%s\tx%0d,%0d(x%0d)", mnemonic, rvfi_rd_addr,
666: $signed({{20 {rvfi_insn[31]}}, rvfi_insn[31:20]}), rvfi_rs1_addr);
667: endfunction
668:
669: function automatic void decode_store_insn();
670: string mnemonic;
671:
672: unique case (rvfi_insn[13:12])
673: 2'b00: mnemonic = "sb";
674: 2'b01: mnemonic = "sh";
675: 2'b10: mnemonic = "sw";
676: default: begin
677: decode_mnemonic("INVALID");
678: return;
679: end
680: endcase
681:
682: if (!rvfi_insn[14]) begin
683: // regular store
684: data_accessed = RS1 | RS2 | MEM;
685: decoded_str = $sformatf("%s\tx%0d,%0d(x%0d)", mnemonic, rvfi_rs2_addr,
686: $signed({ {20 {rvfi_insn[31]}}, rvfi_insn[31:25], rvfi_insn[11:7] }), rvfi_rs1_addr);
687: end else begin
688: decode_mnemonic("INVALID");
689: end
690: endfunction
691:
692: function automatic string get_fence_description(logic [3:0] bits);
693: string desc = "";
694: if (bits[3]) begin
695: desc = {desc, "i"};
696: end
697: if (bits[2]) begin
698: desc = {desc, "o"};
699: end
700: if (bits[1]) begin
701: desc = {desc, "r"};
702: end
703: if (bits[0]) begin
704: desc = {desc, "w"};
705: end
706: return desc;
707: endfunction
708:
709: function automatic void decode_fence();
710: string predecessor;
711: string successor;
712: predecessor = get_fence_description(rvfi_insn[27:24]);
713: successor = get_fence_description(rvfi_insn[23:20]);
714: decoded_str = $sformatf("fence\t%s,%s", predecessor, successor);
715: endfunction
716:
717: // cycle counter
718: always_ff @(posedge clk_i or negedge rst_ni) begin
719: if (!rst_ni) begin
720: cycle <= 0;
721: end else begin
722: cycle <= cycle + 1;
723: end
724: end
725:
726: // close output file for writing
727: final begin
728: if (file_handle != 32'h0) begin
729: $fclose(file_handle);
730: end
731: end
732:
733: // log execution
734: always_ff @(posedge clk_i) begin
735: if (rvfi_valid) begin
736: printbuffer_dumpline();
737: end
738: end
739:
740: always_comb begin
741: decoded_str = "";
742: data_accessed = 5'h0;
743: insn_is_compressed = 0;
744:
745: // Check for compressed instructions
746: if (rvfi_insn[1:0] != 2'b11) begin
747: insn_is_compressed = 1;
748: // Separate case to avoid overlapping decoding
749: if (rvfi_insn[15:13] == 3'b100 && rvfi_insn[1:0] == 2'b10) begin
750: if (rvfi_insn[12]) begin
751: if (rvfi_insn[11:2] == 10'h0) begin
752: decode_mnemonic("c.ebreak");
753: end else if (rvfi_insn[6:2] == 5'b0) begin
754: decode_cr_insn("c.jalr");
755: end else begin
756: decode_cr_insn("c.add");
757: end
758: end else begin
759: if (rvfi_insn[6:2] == 5'h0) begin
760: decode_cr_insn("c.jr");
761: end else begin
762: decode_cr_insn("c.mv");
763: end
764: end
765: end else begin
766: unique casez (rvfi_insn[15:0])
767: // C0 Opcodes
768: INSN_CADDI4SPN: begin
769: if (rvfi_insn[12:2] == 11'h0) begin
770: // Align with pseudo-mnemonic used by GNU binutils and LLVM's MC layer
771: decode_mnemonic("c.unimp");
772: end else begin
773: decode_ciw_insn("c.addi4spn");
774: end
775: end
776: INSN_CLW: decode_compressed_load_insn("c.lw");
777: INSN_CSW: decode_compressed_store_insn("c.sw");
778: // C1 Opcodes
779: INSN_CADDI: decode_ci_caddi_insn("c.addi");
780: INSN_CJAL: decode_cj_insn("c.jal");
781: INSN_CJ: decode_cj_insn("c.j");
782: INSN_CLI: decode_ci_cli_insn("c.li");
783: INSN_CLUI: begin
784: // These two instructions share opcode
785: if (rvfi_insn[11:7] == 5'd2) begin
786: decode_ci_caddi16sp_insn("c.addi16sp");
787: end else begin
788: decode_ci_clui_insn("c.lui");
789: end
790: end
791: INSN_CSRLI: decode_cb_sr_insn("c.srli");
792: INSN_CSRAI: decode_cb_sr_insn("c.srai");
793: INSN_CANDI: decode_cb_insn("c.andi");
794: INSN_CSUB: decode_cs_insn("c.sub");
795: INSN_CXOR: decode_cs_insn("c.xor");
796: INSN_COR: decode_cs_insn("c.or");
797: INSN_CAND: decode_cs_insn("c.and");
798: INSN_CBEQZ: decode_cb_insn("c.beqz");
799: INSN_CBNEZ: decode_cb_insn("c.bnez");
800: // C2 Opcodes
801: INSN_CSLLI: decode_ci_cslli_insn("c.slli");
802: INSN_CLWSP: decode_compressed_load_insn("c.lwsp");
803: INSN_SWSP: decode_compressed_store_insn("c.swsp");
804: default: decode_mnemonic("INVALID");
805: endcase
806: end
807: end else begin
808: unique casez (rvfi_insn)
809: // Regular opcodes
810: INSN_LUI: decode_u_insn("lui");
811: INSN_AUIPC: decode_u_insn("auipc");
812: INSN_JAL: decode_j_insn("jal");
813: INSN_JALR: decode_i_jalr_insn("jalr");
814: // BRANCH
815: INSN_BEQ: decode_b_insn("beq");
816: INSN_BNE: decode_b_insn("bne");
817: INSN_BLT: decode_b_insn("blt");
818: INSN_BGE: decode_b_insn("bge");
819: INSN_BLTU: decode_b_insn("bltu");
820: INSN_BGEU: decode_b_insn("bgeu");
821: // OPIMM
822: INSN_ADDI: begin
823: if (rvfi_insn == 32'h00_00_00_13) begin
824: // TODO: objdump doesn't decode this as nop currently, even though it would be helpful
825: // Decide what to do here: diverge from objdump, or make the trace less readable to
826: // users.
827: //decode_mnemonic("nop");
828: decode_i_insn("addi");
829: end else begin
830: decode_i_insn("addi");
831: end
832: end
833: INSN_SLTI: decode_i_insn("slti");
834: INSN_SLTIU: decode_i_insn("sltiu");
835: INSN_XORI: decode_i_insn("xori");
836: INSN_ORI: decode_i_insn("ori");
837: // Version 0.92 of the Bitmanip Extension defines the pseudo-instruction
838: // zext.b rd rs = andi rd, rs, 255.
839: // Currently instruction set simulators don't output this pseudo-instruction.
840: INSN_ANDI: decode_i_insn("andi");
841: // INSN_ANDI:begin
842: // casez (rvfi_insn)
843: // INSN_ZEXTB: decode_r1_insn("zext.b");
844: // default: decode_i_insn("andi");
845: // endcase
846: // end
847: INSN_SLLI: decode_i_shift_insn("slli");
848: INSN_SRLI: decode_i_shift_insn("srli");
849: INSN_SRAI: decode_i_shift_insn("srai");
850: // OP
851: INSN_ADD: decode_r_insn("add");
852: INSN_SUB: decode_r_insn("sub");
853: INSN_SLL: decode_r_insn("sll");
854: INSN_SLT: decode_r_insn("slt");
855: INSN_SLTU: decode_r_insn("sltu");
856: INSN_XOR: decode_r_insn("xor");
857: INSN_SRL: decode_r_insn("srl");
858: INSN_SRA: decode_r_insn("sra");
859: INSN_OR: decode_r_insn("or");
860: INSN_AND: decode_r_insn("and");
861: // SYSTEM (CSR manipulation)
862: INSN_CSRRW: decode_csr_insn("csrrw");
863: INSN_CSRRS: decode_csr_insn("csrrs");
864: INSN_CSRRC: decode_csr_insn("csrrc");
865: INSN_CSRRWI: decode_csr_insn("csrrwi");
866: INSN_CSRRSI: decode_csr_insn("csrrsi");
867: INSN_CSRRCI: decode_csr_insn("csrrci");
868: // SYSTEM (others)
869: INSN_ECALL: decode_mnemonic("ecall");
870: INSN_EBREAK: decode_mnemonic("ebreak");
871: INSN_MRET: decode_mnemonic("mret");
872: INSN_DRET: decode_mnemonic("dret");
873: INSN_WFI: decode_mnemonic("wfi");
874: // RV32M
875: INSN_PMUL: decode_r_insn("mul");
876: INSN_PMUH: decode_r_insn("mulh");
877: INSN_PMULHSU: decode_r_insn("mulhsu");
878: INSN_PMULHU: decode_r_insn("mulhu");
879: INSN_DIV: decode_r_insn("div");
880: INSN_DIVU: decode_r_insn("divu");
881: INSN_REM: decode_r_insn("rem");
882: INSN_REMU: decode_r_insn("remu");
883: // LOAD & STORE
884: INSN_LOAD: decode_load_insn();
885: INSN_STORE: decode_store_insn();
886: // MISC-MEM
887: INSN_FENCE: decode_fence();
888: INSN_FENCEI: decode_mnemonic("fence.i");
889: // RV32B - ZBB
890: INSN_SLOI: decode_i_shift_insn("sloi");
891: INSN_SROI: decode_i_shift_insn("sroi");
892: INSN_RORI: decode_i_shift_insn("rori");
893: INSN_SLO: decode_r_insn("slo");
894: INSN_SRO: decode_r_insn("sro");
895: INSN_ROL: decode_r_insn("rol");
896: INSN_ROR: decode_r_insn("ror");
897: INSN_MIN: decode_r_insn("min");
898: INSN_MAX: decode_r_insn("max");
899: INSN_MINU: decode_r_insn("minu");
900: INSN_MAXU: decode_r_insn("maxu");
901: INSN_XNOR: decode_r_insn("xnor");
902: INSN_ORN: decode_r_insn("orn");
903: INSN_ANDN: decode_r_insn("andn");
904: // Version 0.92 of the Bitmanip Extension defines the pseudo-instruction
905: // zext.h rd rs = pack rd, rs, zero.
906: // Currently instruction set simulators don't output this pseudo-instruction.
907: INSN_PACK: decode_r_insn("pack");
908: // INSN_PACK: begin
909: // casez (rvfi_insn)
910: // INSN_ZEXTH: decode_r1_insn("zext.h");
911: // default: decode_r_insn("pack");
912: // endcase
913: // end
914: INSN_PACKH: decode_r_insn("packh");
915: INSN_PACKU: decode_r_insn("packu");
916: INSN_CLZ: decode_r1_insn("clz");
917: INSN_CTZ: decode_r1_insn("ctz");
918: INSN_PCNT: decode_r1_insn("pcnt");
919: INSN_SEXTB: decode_r1_insn("sext.b");
920: INSN_SEXTH: decode_r1_insn("sext.h");
921: // RV32B - ZBS
922: INSN_SBCLRI: decode_i_insn("sbclri");
923: INSN_SBSETI: decode_i_insn("sbseti");
924: INSN_SBINVI: decode_i_insn("sbinvi");
925: INSN_SBEXTI: decode_i_insn("sbexti");
926: INSN_SBCLR: decode_r_insn("sbclr");
927: INSN_SBSET: decode_r_insn("sbset");
928: INSN_SBINV: decode_r_insn("sbinv");
929: INSN_SBEXT: decode_r_insn("sbext");
930: // RV32B - ZBE
931: INSN_BDEP: decode_r_insn("bdep");
932: INSN_BEXT: decode_r_insn("bext");
933: // RV32B - ZBP
934: INSN_GREV: decode_r_insn("grev");
935: INSN_GREVI: begin
936: unique casez (rvfi_insn)
937: INSN_REV_P: decode_r1_insn("rev.p");
938: INSN_REV2_N: decode_r1_insn("rev2.n");
939: INSN_REV_N: decode_r1_insn("rev.n");
940: INSN_REV4_B: decode_r1_insn("rev4.b");
941: INSN_REV2_B: decode_r1_insn("rev2.b");
942: INSN_REV_B: decode_r1_insn("rev.b");
943: INSN_REV8_H: decode_r1_insn("rev8.h");
944: INSN_REV4_H: decode_r1_insn("rev4.h");
945: INSN_REV2_H: decode_r1_insn("rev2.h");
946: INSN_REV_H: decode_r1_insn("rev.h");
947: INSN_REV16: decode_r1_insn("rev16");
948: INSN_REV8: decode_r1_insn("rev8");
949: INSN_REV4: decode_r1_insn("rev4");
950: INSN_REV2: decode_r1_insn("rev2");
951: INSN_REV: decode_r1_insn("rev");
952: default: decode_i_insn("grevi");
953: endcase
954: end
955: INSN_GORC: decode_r_insn("gorc");
956: INSN_GORCI: begin
957: unique casez (rvfi_insn)
958: INSN_ORC_P: decode_r1_insn("orc.p");
959: INSN_ORC2_N: decode_r1_insn("orc2.n");
960: INSN_ORC_N: decode_r1_insn("orc.n");
961: INSN_ORC4_B: decode_r1_insn("orc4.b");
962: INSN_ORC2_B: decode_r1_insn("orc2.b");
963: INSN_ORC_B: decode_r1_insn("orc.b");
964: INSN_ORC8_H: decode_r1_insn("orc8.h");
965: INSN_ORC4_H: decode_r1_insn("orc4.h");
966: INSN_ORC2_H: decode_r1_insn("orc2.h");
967: INSN_ORC_H: decode_r1_insn("orc.h");
968: INSN_ORC16: decode_r1_insn("orc16");
969: INSN_ORC8: decode_r1_insn("orc8");
970: INSN_ORC4: decode_r1_insn("orc4");
971: INSN_ORC2: decode_r1_insn("orc2");
972: INSN_ORC: decode_r1_insn("orc");
973: default: decode_i_insn("gorci");
974: endcase
975: end
976: INSN_SHFL: decode_r_insn("shfl");
977: INSN_SHFLI: begin
978: unique casez (rvfi_insn)
979: INSN_ZIP_N: decode_r1_insn("zip.n");
980: INSN_ZIP2_B: decode_r1_insn("zip2.b");
981: INSN_ZIP_B: decode_r1_insn("zip.b");
982: INSN_ZIP4_H: decode_r1_insn("zip4.h");
983: INSN_ZIP2_H: decode_r1_insn("zip2.h");
984: INSN_ZIP_H: decode_r1_insn("zip.h");
985: INSN_ZIP8: decode_r1_insn("zip8");
986: INSN_ZIP4: decode_r1_insn("zip4");
987: INSN_ZIP2: decode_r1_insn("zip2");
988: INSN_ZIP: decode_r1_insn("zip");
989: default: decode_i_insn("shfli");
990: endcase
991: end
992: INSN_UNSHFL: decode_r_insn("unshfl");
993: INSN_UNSHFLI: begin
994: unique casez (rvfi_insn)
995: INSN_UNZIP_N: decode_r1_insn("unzip.n");
996: INSN_UNZIP2_B: decode_r1_insn("unzip2.b");
997: INSN_UNZIP_B: decode_r1_insn("unzip.b");
998: INSN_UNZIP4_H: decode_r1_insn("unzip4.h");
999: INSN_UNZIP2_H: decode_r1_insn("unzip2.h");
1000: INSN_UNZIP_H: decode_r1_insn("unzip.h");
1001: INSN_UNZIP8: decode_r1_insn("unzip8");
1002: INSN_UNZIP4: decode_r1_insn("unzip4");
1003: INSN_UNZIP2: decode_r1_insn("unzip2");
1004: INSN_UNZIP: decode_r1_insn("unzip");
1005: default: decode_i_insn("unshfli");
1006: endcase
1007: end
1008:
1009: // RV32B - ZBT
1010: INSN_CMIX: decode_r_cmixcmov_insn("cmix");
1011: INSN_CMOV: decode_r_cmixcmov_insn("cmov");
1012: INSN_FSR: decode_r_funnelshift_insn("fsr");
1013: INSN_FSL: decode_r_funnelshift_insn("fsl");
1014: INSN_FSRI: decode_i_funnelshift_insn("fsri");
1015:
1016: // RV32B - ZBF
1017: INSN_BFP: decode_r_insn("bfp");
1018:
1019: // RV32B - ZBC
1020: INSN_CLMUL: decode_r_insn("clmul");
1021: INSN_CLMULR: decode_r_insn("clmulr");
1022: INSN_CLMULH: decode_r_insn("clmulh");
1023:
1024: // RV32B - ZBR
1025: INSN_CRC32_B: decode_r1_insn("crc32.b");
1026: INSN_CRC32_H: decode_r1_insn("crc32.h");
1027: INSN_CRC32_W: decode_r1_insn("crc32.w");
1028: INSN_CRC32C_B: decode_r1_insn("crc32c.b");
1029: INSN_CRC32C_H: decode_r1_insn("crc32c.h");
1030: INSN_CRC32C_W: decode_r1_insn("crc32c.w");
1031:
1032: default: decode_mnemonic("INVALID");
1033: endcase
1034: end
1035: end
1036:
1037: endmodule
1038: