Add features to instruction tracer

This commit is contained in:
Florian Zaruba 2017-05-30 20:18:13 +02:00
parent da62924f81
commit 00b11efc6f
3 changed files with 159 additions and 176 deletions

View file

@ -1,19 +1,49 @@
// Author: Florian Zaruba, ETH Zurich - Andreas Traber, ACP
// Date: 30.05.2017
// Description: Instruction tracer single instruction item
//
// Copyright (C) 2017 ETH Zurich, University of Bologna
// All rights reserved.
//
// This code is under development and not yet released to the public.
// Until it is released, the code is under the copyright of ETH Zurich and
// the University of Bologna, and may contain confidential and/or unpublished
// work. Any reuse/redistribution is strictly forbidden without written
// permission from ETH Zurich.
//
// Bug fixes and contributions will eventually be released under the
// SolderPad open hardware license in the context of the PULP platform
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
//
class instruction_trace_item;
time simtime;
integer cycles;
logic [31:0] pc;
logic [31:0] instr;
string str;
function new ();
// keep a couple of general purpose information inside this instruction item
time simtime;
longint unsigned cycle;
scoreboard_entry sbe;
logic [31:0] pc;
logic [31:0] instr;
logic [63:0] reg_file [32];
logic [4:0] read_regs [$];
logic [4:0] result_regs [$];
logic [63:0] result;
// constructor creating a new instruction trace item, e.g.: a single instruction with all relevant information
function new (time simtime, longint unsigned cycle, scoreboard_entry sbe, logic [31:0] instr, logic [63:0] reg_file [32], logic [63:0] result);
this.simtime = simtime;
this.cycle = cycle;
this.pc = sbe.pc;
this.sbe = sbe;
this.instr = instr;
this.reg_file = reg_file;
this.result = result;
endfunction
function string regAddrToStr(logic [5:0] addr);
return $sformatf("x%0d", addr);
return $sformatf("x%0d:", addr);
endfunction
function string printInstr(logic [63:0] instr);
function string printInstr();
string s;
casex (instr)
@ -55,7 +85,7 @@ class instruction_trace_item;
// FENCE
INSTR_FENCE: s = this.printMnemonic("fence");
INSTR_FENCEI: s = this.printMnemonic("fencei");
// SYSTEM (CSR man ipulation)
// SYSTEM (CSR manipulation)
INSTR_CSRRW: s = this.printCSRInstr("csrrw");
INSTR_CSRRS: s = this.printCSRInstr("csrrs");
INSTR_CSRRC: s = this.printCSRInstr("csrrc");
@ -67,29 +97,31 @@ class instruction_trace_item;
INSTR_EBREAK: s = this.printMnemonic("ebreak");
INSTR_ERET: s = this.printMnemonic("eret");
INSTR_WFI: s = this.printMnemonic("wfi");
// opcodes with custom decoding
{25'b?, OPCODE_LOAD}: s = this.printLoadInstr();
{25'b?, OPCODE_STORE}: s = this.printStoreInstr();
// loads and stores
INSTR_LOAD: s = this.printLoadInstr();
INSTR_STORE: s = this.printStoreInstr();
default: s = this.printMnemonic("INVALID");
endcase
s = $sformatf("%t %15d %h %h %-36s", simtime,
cycle,
sbe.pc,
instr,
s);
foreach (result_regs[i]) begin
if (result_regs[i] != 0)
s = $sformatf(s, " %-4s%16x", regAddrToStr(result_regs[i]), this.result);
end
foreach (read_regs[i]) begin
if (read_regs[i] != 0)
s = $sformatf(s, " %-4s%16x", regAddrToStr(read_regs[i]), reg_file[read_regs[i]]);
end
return s;
// $fwrite(f, "%t %15d %h %h %-36s", simtime,
// cycles,
// pc,
// instr,
// str);
// foreach(regs_write[i]) begin
// if (regs_write[i].addr != 0)
// $fwrite(f, " %s=%08x", regAddrToStr(regs_write[i].addr), regs_write[i].value);
// end
// foreach(regs_read[i]) begin
// if (regs_read[i].addr != 0)
// $fwrite(f, " %s:%08x", regAddrToStr(regs_read[i].addr), regs_read[i].value);
// end
// if (mem_access.size() > 0) begin
// mem_acc = mem_access.pop_front();
@ -104,165 +136,100 @@ class instruction_trace_item;
endfunction // printMnemonic
function string printRInstr(input string mnemonic);
// return $sformatf("%-16s x%0d, x%0d, x%0d", mnemonic, rd, rs1, rs2);
return mnemonic;
result_regs.push_back(sbe.rd);
read_regs.push_back(sbe.rs1);
read_regs.push_back(sbe.rs2);
return $sformatf("%-16s x%0d, x%0d, x%0d", mnemonic, sbe.rd, sbe.rs1, sbe.rs2);
endfunction // printRInstr
function string printIInstr(input string mnemonic);
// begin
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rd, 'x});
// str = $sformatf("%-16s x%0d, x%0d, %0d", mnemonic, rd, rs1, $signed(imm_i_type));
// end
return mnemonic;
result_regs.push_back(sbe.rd);
read_regs.push_back(sbe.rs1);
return $sformatf("%-16s x%0d, x%0d, %0d", mnemonic, sbe.rd, sbe.rs1, $signed(sbe.result));
endfunction // printIInstr
function string printIuInstr(input string mnemonic);
// begin
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rd, 'x});
// str = $sformatf("%-16s x%0d, x%0d, 0x%0x", mnemonic, rd, rs1, imm_i_type);
// end
return mnemonic;
result_regs.push_back(sbe.rd);
read_regs.push_back(sbe.rs1);
return $sformatf("%-16s x%0d, x%0d, 0x%0x", mnemonic, sbe.rd, sbe.rs1, sbe.result);
endfunction // printIuInstr
function string printSBInstr(input string mnemonic);
// begin
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rd, 'x});
// str = $sformatf("%-16s x%0d, x%0d, 0x%0x", mnemonic, rd, rs1, imm_i_type);
// end
return mnemonic;
result_regs.push_back(sbe.rd);
read_regs.push_back(sbe.rs1);
return $sformatf("%-16s x%0d, x%0d, 0x%0x", mnemonic, sbe.rd, sbe.rs1, sbe.result);
endfunction // printIuInstr
function string printUInstr(input string mnemonic);
// begin
// regs_write.push_back('{rd, 'x});
// str = $sformatf("%-16s x%0d, 0x%0h", mnemonic, rd, {imm_u_type[31:12], 12'h000});
// end
return mnemonic;
result_regs.push_back(sbe.rd);
return $sformatf("%-16s x%0d, 0x%0h", mnemonic, sbe.rd, sbe.result);
endfunction // printUInstr
function string printUJInstr(input string mnemonic);
// begin
// regs_write.push_back('{rd, 'x});
// str = $sformatf("%-16s x%0d, %0d", mnemonic, rd, $signed(imm_uj_type));
// end
return mnemonic;
result_regs.push_back(sbe.rd);
return $sformatf("%-16s x%0d, %0d", mnemonic, sbe.rd, $signed(sbe.result));
endfunction // printUJInstr
function string printCSRInstr(input string mnemonic);
// logic [11:0] csr;
// begin
// csr = instr[31:20];
// regs_write.push_back('{rd, 'x});
result_regs.push_back(sbe.rd);
read_regs.push_back(sbe.rs1);
// if (instr[14] == 1'b0) begin
// regs_read.push_back('{rs1, rs1_value});
// str = $sformatf("%-16s x%0d, x%0d, 0x%h", mnemonic, rd, rs1, csr);
// end else begin
// str = $sformatf("%-16s x%0d, 0x%h, 0x%h", mnemonic, rd, imm_z_type, csr);
// end
// end
return mnemonic;
if (instr[14] == 1'b0) begin
return $sformatf("%-16s x%0d, x%0d, 0x%h", mnemonic, sbe.rd, sbe.rs1, sbe.result[11:0]);
end else begin
return $sformatf("%-16s x%0d, 0x%h, 0x%h", mnemonic, sbe.rd, sbe.rs1, sbe.result[11:0]);
end
endfunction // printCSRInstr
function string printLoadInstr();
// string mnemonic;
// logic [2:0] size;
// begin
// // detect reg-reg load and find size
// size = instr[14:12];
// if (instr[14:12] == 3'b111)
// size = instr[30:28];
string mnemonic;
// case (size)
// 3'b000: mnemonic = "lb";
// 3'b001: mnemonic = "lh";
// 3'b010: mnemonic = "lw";
// 3'b100: mnemonic = "lbu";
// 3'b101: mnemonic = "lhu";
// 3'b110: mnemonic = "p.elw";
// 3'b011,
// 3'b111: begin
// printMnemonic("INVALID");
// return;
// end
// endcase
case (instr[14:12])
3'b000: mnemonic = "lb";
3'b001: mnemonic = "lh";
3'b010: mnemonic = "lw";
3'b100: mnemonic = "lbu";
3'b101: mnemonic = "lhu";
3'b110: mnemonic = "lwu";
3'b011: mnemonic = "ld";
default: return printMnemonic("INVALID");
endcase
// regs_write.push_back('{rd, 'x});
result_regs.push_back(sbe.rd);
read_regs.push_back(sbe.rs1);
// if (instr[14:12] != 3'b111) begin
// // regular load
// if (instr[6:0] != OPCODE_LOAD_POST) begin
// regs_read.push_back('{rs1, rs1_value});
// str = $sformatf("%-16s x%0d, %0d(x%0d)", mnemonic, rd, $signed(imm_i_type), rs1);
// end else begin
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rs1, 'x});
// str = $sformatf("p.%-14s x%0d, %0d(x%0d!)", mnemonic, rd, $signed(imm_i_type), rs1);
// end
// end else begin
// // reg-reg load
// if (instr[6:0] != OPCODE_LOAD_POST) begin
// regs_read.push_back('{rs2, rs2_value});
// regs_read.push_back('{rs1, rs1_value});
// str = $sformatf("%-16s x%0d, x%0d(x%0d)", mnemonic, rd, rs2, rs1);
// end else begin
// regs_read.push_back('{rs2, rs2_value});
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rs1, 'x});
// str = $sformatf("p.%-14s x%0d, x%0d(x%0d!)", mnemonic, rd, rs2, rs1);
// end
// end
// end
return "";
return $sformatf("%-16s x%0d, %0d(x%0d)", mnemonic, sbe.rd, $signed(sbe.result), sbe.rs1);
endfunction
function string printStoreInstr();
// string mnemonic;
// begin
string mnemonic;
// case (instr[13:12])
// 2'b00: mnemonic = "sb";
// 2'b01: mnemonic = "sh";
// 2'b10: mnemonic = "sw";
// 2'b11: begin
// printMnemonic("INVALID");
// return;
// end
// endcase
case (instr[14:12])
3'b000: mnemonic = "sb";
3'b001: mnemonic = "sh";
3'b010: mnemonic = "sw";
3'b011: mnemonic = "sd";
default: return printMnemonic("INVALID");
endcase
read_regs.push_back(sbe.rs1);
read_regs.push_back(sbe.rs2);
return $sformatf("%-16s x%0d, %0d(x%0d)", mnemonic, sbe.rs2, $signed(sbe.result), sbe.rs1);
// if (instr[14] == 1'b0) begin
// // regular store
// if (instr[6:0] != OPCODE_STORE_POST) begin
// regs_read.push_back('{rs2, rs2_value});
// regs_read.push_back('{rs1, rs1_value});
// str = $sformatf("%-16s x%0d, %0d(x%0d)", mnemonic, rs2, $signed(imm_s_type), rs1);
// end else begin
// regs_read.push_back('{rs2, rs2_value});
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rs1, 'x});
// str = $sformatf("p.%-14s x%0d, %0d(x%0d!)", mnemonic, rs2, $signed(imm_s_type), rs1);
// end
// end else begin
// // reg-reg store
// if (instr[6:0] != OPCODE_STORE_POST) begin
// regs_read.push_back('{rs2, rs2_value});
// regs_read.push_back('{rs3, rs3_value});
// regs_read.push_back('{rs1, rs1_value});
// str = $sformatf("p.%-14s x%0d, x%0d(x%0d)", mnemonic, rs2, rs3, rs1);
// end else begin
// regs_read.push_back('{rs2, rs2_value});
// regs_read.push_back('{rs3, rs3_value});
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rs1, 'x});
// str = $sformatf("p.%-14s x%0d, x%0d(x%0d!)", mnemonic, rs2, rs3, rs1);
// end
// end
// end
return "";
endfunction // printSInstr
function string printMulInstr();

View file

@ -17,12 +17,6 @@
// University of Bologna.
//
// keep the instruction and scoreboard entry together
typedef struct {
fetch_entry fetch_entry;
scoreboard_entry sbe;
} issue_entry;
class instruction_tracer;
// interface to the core
@ -30,9 +24,13 @@ class instruction_tracer;
// keep the decoded instructions in a queue
fetch_entry decode_queue [$];
// keep the issued instructions in a queue
issue_entry issue_queue [$];
fetch_entry issue_queue [$];
// issue scoreboard entries
scoreboard_entry issue_sbe_queue [$];
scoreboard_entry issue_sbe;
// shadow copy of the register file
logic [63:0] reg_file [31];
logic [63:0] reg_file [32];
// 64 bit clock tick count
longint unsigned clk_ticks;
@ -41,8 +39,11 @@ class instruction_tracer;
endfunction : new
task trace();
fetch_entry decode_instruction;
issue_entry issue_instruction;
fetch_entry decode_instruction, issue_instruction, issue_commit_instruction;
scoreboard_entry commit_instruction;
// initialize register 0
reg_file [0] = 0;
forever begin
// new cycle, we are only interested if reset is de-asserted
@ -58,17 +59,22 @@ class instruction_tracer;
decode_instruction = fetch_entry'(tracer_if.pck.fetch);
decode_queue.push_back(decode_instruction);
end
// -------------------
// Instruction Issue
// -------------------
// we got a new issue ack, so put the element from the decode queue to
// the issue queue
if (tracer_if.pck.issue_ack) begin
issue_instruction.fetch_entry = decode_queue.pop_front();
issue_instruction.sbe = scoreboard_entry'(tracer_if.pck.issue_sbe);
issue_instruction = decode_queue.pop_front();
issue_queue.push_back(issue_instruction);
printInstr(issue_instruction.sbe.pc, issue_instruction.fetch_entry.instruction);
issue_sbe_queue.push_back(scoreboard_entry'(tracer_if.pck.issue_sbe));
end
// -----------------
// Physical Address
// -----------------
// -----------
// Write Back
// -----------
@ -82,8 +88,11 @@ class instruction_tracer;
// --------------
// we are committing an instruction
if (tracer_if.pck.commit_ack) begin
// printInstr(issue_instruction.instruction);
// $display("Committing: %0h", tracer_if.pck.commit_instr);
commit_instruction = scoreboard_entry'(tracer_if.pck.commit_instr);
issue_commit_instruction = issue_queue.pop_front();
issue_sbe = issue_sbe_queue.pop_front();
// the scoreboards issue entry still contains the immediate value as a result
printInstr(issue_sbe, issue_commit_instruction.instruction, tracer_if.pck.wdata);
end
// --------------
@ -112,12 +121,15 @@ class instruction_tracer;
this.flushDecode();
for (int i = 0; i < issue_queue.size(); i++) begin
issue_queue.delete(i);
// by definition they must have the same size
issue_sbe_queue.delete(i);
end
endfunction;
function void printInstr(logic [63:0] pc, logic [63:0] instr);
instruction_trace_item iti = new;
$display("Time: %t Cycle: %d PC: %h Instruction: %s Instr: %0h", $time(), clk_ticks, pc, iti.printInstr(instr), instr);
function void printInstr(scoreboard_entry sbe, logic [63:0] instr, logic [63:0] result);
instruction_trace_item iti = new ($time, clk_ticks, sbe, instr, this.reg_file, result);
$display(iti.printInstr());
// $display("Time: %t Cycle: %d PC: %h Instruction: %s", $time(), clk_ticks, sbe.pc, iti.printInstr());
endfunction;

View file

@ -70,4 +70,8 @@ parameter INSTR_PMUL = { 7'b0000001, 10'b?, 3'b000, 5'b?, OPCODE_OP };
parameter INSTR_DIV = { 7'b0000001, 10'b?, 3'b100, 5'b?, OPCODE_OP };
parameter INSTR_DIVU = { 7'b0000001, 10'b?, 3'b101, 5'b?, OPCODE_OP };
parameter INSTR_REM = { 7'b0000001, 10'b?, 3'b110, 5'b?, OPCODE_OP };
parameter INSTR_REMU = { 7'b0000001, 10'b?, 3'b111, 5'b?, OPCODE_OP };
parameter INSTR_REMU = { 7'b0000001, 10'b?, 3'b111, 5'b?, OPCODE_OP };
// Load/Stores
parameter INSTR_LOAD = {25'b?, OPCODE_LOAD};
parameter INSTR_STORE = {25'b?, OPCODE_STORE};