Added tracer support (under construction)

This commit is contained in:
Clifford Wolf 2016-08-25 14:15:42 +02:00
parent 8043c90a04
commit 7094e61af7
6 changed files with 157 additions and 14 deletions

1
.gitignore vendored
View File

@ -23,6 +23,7 @@
/testbench_synth.vvp /testbench_synth.vvp
/testbench.gtkw /testbench.gtkw
/testbench.vcd /testbench.vcd
/testbench.trace
/check.smt2 /check.smt2
/check.vcd /check.vcd
/synth.log /synth.log

View File

@ -14,7 +14,7 @@ test: testbench.vvp firmware/firmware.hex
vvp -N testbench.vvp vvp -N testbench.vvp
testbench.vcd: testbench.vvp firmware/firmware.hex testbench.vcd: testbench.vvp firmware/firmware.hex
vvp -N $< +vcd vvp -N $< +vcd +trace
view: testbench.vcd view: testbench.vcd
gtkwave $< testbench.gtkw gtkwave $< testbench.gtkw
@ -131,7 +131,7 @@ clean:
riscv-gnu-toolchain-riscv32im riscv-gnu-toolchain-riscv32imc riscv-gnu-toolchain-riscv32im riscv-gnu-toolchain-riscv32imc
rm -vrf $(FIRMWARE_OBJS) $(TEST_OBJS) check.smt2 check.vcd synth.v synth.log \ rm -vrf $(FIRMWARE_OBJS) $(TEST_OBJS) check.smt2 check.vcd synth.v synth.log \
firmware/firmware.elf firmware/firmware.bin firmware/firmware.hex firmware/firmware.map \ firmware/firmware.elf firmware/firmware.bin firmware/firmware.hex firmware/firmware.map \
testbench.vvp testbench_sp.vvp testbench_synth.vvp testbench.vcd testbench.vvp testbench_sp.vvp testbench_synth.vvp testbench.vcd testbench.trace
.PHONY: test view test_sp test_axi test_synth download-tools toc clean .PHONY: test view test_sp test_axi test_synth download-tools toc clean

View File

@ -478,6 +478,10 @@ start:
sw a4,0(a0) sw a4,0(a0)
sw a5,0(a0) sw a5,0(a0)
li a0, 0x20000000
li a1, 123456789
sw a1,0(a0)
/* trap */ /* trap */
ebreak ebreak

View File

@ -58,6 +58,7 @@ module picorv32 #(
parameter [ 0:0] ENABLE_IRQ = 0, parameter [ 0:0] ENABLE_IRQ = 0,
parameter [ 0:0] ENABLE_IRQ_QREGS = 1, parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
parameter [ 0:0] ENABLE_IRQ_TIMER = 1, parameter [ 0:0] ENABLE_IRQ_TIMER = 1,
parameter [ 0:0] ENABLE_TRACE = 0,
parameter [ 0:0] REGS_INIT_ZERO = 0, parameter [ 0:0] REGS_INIT_ZERO = 0,
parameter [31:0] MASKED_IRQ = 32'h 0000_0000, parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff,
@ -96,7 +97,11 @@ module picorv32 #(
// IRQ Interface // IRQ Interface
input [31:0] irq, input [31:0] irq,
output reg [31:0] eoi output reg [31:0] eoi,
// Trace Interface
output reg trace_valid,
output reg [35:0] trace_data
); );
localparam integer irq_timer = 0; localparam integer irq_timer = 0;
localparam integer irq_ebreak = 1; localparam integer irq_ebreak = 1;
@ -108,6 +113,10 @@ module picorv32 #(
localparam WITH_PCPI = ENABLE_PCPI || ENABLE_MUL || ENABLE_DIV; localparam WITH_PCPI = ENABLE_PCPI || ENABLE_MUL || ENABLE_DIV;
localparam [35:0] TRACE_BRANCH = {4'b 0001, 32'b 0};
localparam [35:0] TRACE_ADDR = {4'b 0010, 32'b 0};
localparam [35:0] TRACE_IRQ = {4'b 1000, 32'b 0};
reg [63:0] count_cycle, count_instr; reg [63:0] count_cycle, count_instr;
reg [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out; reg [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out;
reg [31:0] cpuregs [0:regfile_size-1]; reg [31:0] cpuregs [0:regfile_size-1];
@ -1016,6 +1025,7 @@ module picorv32 #(
reg latched_stalu; reg latched_stalu;
reg latched_branch; reg latched_branch;
reg latched_compr; reg latched_compr;
reg latched_trace;
reg latched_is_lu; reg latched_is_lu;
reg latched_is_lh; reg latched_is_lh;
reg latched_is_lb; reg latched_is_lb;
@ -1155,6 +1165,9 @@ module picorv32 #(
decoder_pseudo_trigger_q <= decoder_pseudo_trigger; decoder_pseudo_trigger_q <= decoder_pseudo_trigger;
do_waitirq <= 0; do_waitirq <= 0;
if (ENABLE_TRACE)
trace_valid <= 0;
if (!resetn) begin if (!resetn) begin
reg_pc <= PROGADDR_RESET; reg_pc <= PROGADDR_RESET;
reg_next_pc <= PROGADDR_RESET; reg_next_pc <= PROGADDR_RESET;
@ -1163,6 +1176,7 @@ module picorv32 #(
latched_store <= 0; latched_store <= 0;
latched_stalu <= 0; latched_stalu <= 0;
latched_branch <= 0; latched_branch <= 0;
latched_trace <= 0;
latched_is_lu <= 0; latched_is_lu <= 0;
latched_is_lh <= 0; latched_is_lh <= 0;
latched_is_lb <= 0; latched_is_lb <= 0;
@ -1218,6 +1232,15 @@ module picorv32 #(
end end
endcase endcase
if (ENABLE_TRACE && latched_trace) begin
latched_trace <= 0;
trace_valid <= 1;
if (latched_branch)
trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_BRANCH | current_pc;
else
trace_data <= (irq_active ? TRACE_IRQ : 0) | (latched_stalu ? alu_out_q : reg_out);
end
reg_pc <= current_pc; reg_pc <= current_pc;
reg_next_pc <= current_pc; reg_next_pc <= current_pc;
@ -1253,6 +1276,8 @@ module picorv32 #(
`debug($display("-- %-0t", $time);) `debug($display("-- %-0t", $time);)
irq_delay <= irq_active; irq_delay <= irq_active;
reg_next_pc <= current_pc + (compressed_instr ? 2 : 4); reg_next_pc <= current_pc + (compressed_instr ? 2 : 4);
if (ENABLE_TRACE)
latched_trace <= 1;
if (ENABLE_COUNTERS) begin if (ENABLE_COUNTERS) begin
count_instr <= count_instr + 1; count_instr <= count_instr + 1;
if (!ENABLE_COUNTERS64) count_instr[63:32] <= 0; if (!ENABLE_COUNTERS64) count_instr[63:32] <= 0;
@ -1519,6 +1544,8 @@ module picorv32 #(
end end
cpu_state_stmem: begin cpu_state_stmem: begin
if (ENABLE_TRACE)
reg_out <= reg_op2;
if (!mem_do_prefetch || mem_done) begin if (!mem_do_prefetch || mem_done) begin
if (!mem_do_wdata) begin if (!mem_do_wdata) begin
(* parallel_case, full_case *) (* parallel_case, full_case *)
@ -1527,6 +1554,10 @@ module picorv32 #(
instr_sh: mem_wordsize <= 1; instr_sh: mem_wordsize <= 1;
instr_sw: mem_wordsize <= 0; instr_sw: mem_wordsize <= 0;
endcase endcase
if (ENABLE_TRACE) begin
trace_valid <= 1;
trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | (reg_op1 + decoded_imm);
end
reg_op1 <= reg_op1 + decoded_imm; reg_op1 <= reg_op1 + decoded_imm;
set_mem_do_wdata = 1; set_mem_do_wdata = 1;
end end
@ -1551,6 +1582,10 @@ module picorv32 #(
latched_is_lu <= is_lbu_lhu_lw; latched_is_lu <= is_lbu_lhu_lw;
latched_is_lh <= instr_lh; latched_is_lh <= instr_lh;
latched_is_lb <= instr_lb; latched_is_lb <= instr_lb;
if (ENABLE_TRACE) begin
trace_valid <= 1;
trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | (reg_op1 + decoded_imm);
end
reg_op1 <= reg_op1 + decoded_imm; reg_op1 <= reg_op1 + decoded_imm;
set_mem_do_rdata = 1; set_mem_do_rdata = 1;
end end
@ -1891,6 +1926,7 @@ module picorv32_axi #(
parameter [ 0:0] ENABLE_IRQ = 0, parameter [ 0:0] ENABLE_IRQ = 0,
parameter [ 0:0] ENABLE_IRQ_QREGS = 1, parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
parameter [ 0:0] ENABLE_IRQ_TIMER = 1, parameter [ 0:0] ENABLE_IRQ_TIMER = 1,
parameter [ 0:0] ENABLE_TRACE = 0,
parameter [ 0:0] REGS_INIT_ZERO = 0, parameter [ 0:0] REGS_INIT_ZERO = 0,
parameter [31:0] MASKED_IRQ = 32'h 0000_0000, parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff,
@ -1936,7 +1972,11 @@ module picorv32_axi #(
// IRQ interface // IRQ interface
input [31:0] irq, input [31:0] irq,
output [31:0] eoi output [31:0] eoi,
// Trace Interface
output trace_valid,
output [35:0] trace_data
); );
wire mem_valid; wire mem_valid;
wire [31:0] mem_addr; wire [31:0] mem_addr;
@ -1993,6 +2033,7 @@ module picorv32_axi #(
.ENABLE_IRQ (ENABLE_IRQ ), .ENABLE_IRQ (ENABLE_IRQ ),
.ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ), .ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ),
.ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ), .ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ),
.ENABLE_TRACE (ENABLE_TRACE ),
.REGS_INIT_ZERO (REGS_INIT_ZERO ), .REGS_INIT_ZERO (REGS_INIT_ZERO ),
.MASKED_IRQ (MASKED_IRQ ), .MASKED_IRQ (MASKED_IRQ ),
.LATCHED_IRQ (LATCHED_IRQ ), .LATCHED_IRQ (LATCHED_IRQ ),
@ -2021,7 +2062,10 @@ module picorv32_axi #(
.pcpi_ready(pcpi_ready), .pcpi_ready(pcpi_ready),
.irq(irq), .irq(irq),
.eoi(eoi) .eoi(eoi),
.trace_valid(trace_valid),
.trace_data (trace_data)
); );
endmodule endmodule

50
showtrace.py Normal file
View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
import sys, re, subprocess
trace_filename = sys.argv[1]
elf_filename = sys.argv[2]
insns = dict()
with subprocess.Popen(["riscv32-unknown-elf-objdump", "-d", elf_filename], stdout=subprocess.PIPE) as proc:
while True:
line = proc.stdout.readline().decode("ascii")
if line == '': break
match = re.match(r'^\s*([0-9a-f]+):\s+(\S+)\s*(.*)', line)
if match: insns[int(match.group(1), 16)] = (int(match.group(2), 16), match.group(3).replace("\t", " "))
with open(trace_filename, "r") as f:
pc = -1
last_irq = False
for line in f:
raw_data = int(line.replace("x", "0"), 16)
payload = raw_data & 0xffffffff
irq_active = (raw_data & 0x800000000) != 0
is_addr = (raw_data & 0x200000000) != 0
is_branch = (raw_data & 0x100000000) != 0
if irq_active and not last_irq:
pc = 0x10
if pc >= 0:
if pc in insns:
insn_opcode, insn_desc = insns[pc]
opcode_fmt = "%08x" if (insn_opcode & 3) == 3 else " %04x"
print(("%s %s%08x | %08x | " + opcode_fmt + " | %s") % ("IRQ" if irq_active else " ",
">" if is_branch else "@" if is_addr else "=", payload, pc, insn_opcode, insn_desc))
if not is_addr:
pc += 4 if (insn_opcode & 3) == 3 else 2
else:
print("%s %s%08x ** NO INFORMATION ON INSN AT %08x! **" % ("IRQ" if irq_active else " ",
">" if is_branch else "@" if is_addr else "=", payload, pc))
pc = -1
else:
print("%s %s%08x ** SKIPPING DATA UNTIL NEXT BRANCH **" % ("IRQ" if irq_active else " ",
">" if is_branch else "@" if is_addr else "=", payload))
if is_branch:
pc = payload
last_irq = irq_active

View File

@ -15,6 +15,7 @@ module testbench #(
reg clk = 1; reg clk = 1;
reg resetn = 0; reg resetn = 0;
wire trap;
always #5 clk = ~clk; always #5 clk = ~clk;
@ -33,12 +34,32 @@ module testbench #(
$finish; $finish;
end end
wire trace_valid;
wire [35:0] trace_data;
integer trace_file;
initial begin
if ($test$plusargs("trace")) begin
trace_file = $fopen("testbench.trace", "w");
repeat (10) @(posedge clk);
while (!trap) begin
@(posedge clk);
if (trace_valid)
$fwrite(trace_file, "%x\n", trace_data);
end
$fclose(trace_file);
end
end
picorv32_wrapper #( picorv32_wrapper #(
.AXI_TEST (AXI_TEST), .AXI_TEST (AXI_TEST),
.VERBOSE (VERBOSE) .VERBOSE (VERBOSE)
) top ( ) top (
.clk (clk ), .clk(clk),
.resetn (resetn) .resetn(resetn),
.trap(trap),
.trace_valid(trace_valid),
.trace_data(trace_data)
); );
endmodule endmodule
`endif `endif
@ -48,10 +69,14 @@ module picorv32_wrapper #(
parameter VERBOSE = 0 parameter VERBOSE = 0
) ( ) (
input clk, input clk,
input resetn input resetn,
output trap,
output trace_valid,
output [35:0] trace_data
); );
wire trap; wire trap;
wire tests_passed;
reg [31:0] irq; reg [31:0] irq;
always @* begin always @* begin
@ -107,7 +132,9 @@ module picorv32_wrapper #(
.mem_axi_rvalid (mem_axi_rvalid ), .mem_axi_rvalid (mem_axi_rvalid ),
.mem_axi_rready (mem_axi_rready ), .mem_axi_rready (mem_axi_rready ),
.mem_axi_rdata (mem_axi_rdata ) .mem_axi_rdata (mem_axi_rdata ),
.tests_passed (tests_passed )
); );
picorv32_axi #( picorv32_axi #(
@ -119,7 +146,8 @@ module picorv32_wrapper #(
`endif `endif
.ENABLE_MUL(1), .ENABLE_MUL(1),
.ENABLE_DIV(1), .ENABLE_DIV(1),
.ENABLE_IRQ(1) .ENABLE_IRQ(1),
.ENABLE_TRACE(1)
) uut ( ) uut (
.clk (clk ), .clk (clk ),
.resetn (resetn ), .resetn (resetn ),
@ -141,7 +169,9 @@ module picorv32_wrapper #(
.mem_axi_rvalid (mem_axi_rvalid ), .mem_axi_rvalid (mem_axi_rvalid ),
.mem_axi_rready (mem_axi_rready ), .mem_axi_rready (mem_axi_rready ),
.mem_axi_rdata (mem_axi_rdata ), .mem_axi_rdata (mem_axi_rdata ),
.irq (irq ) .irq (irq ),
.trace_valid (trace_valid ),
.trace_data (trace_data )
); );
reg [1023:0] firmware_file; reg [1023:0] firmware_file;
@ -159,7 +189,13 @@ module picorv32_wrapper #(
repeat (10) @(posedge clk); repeat (10) @(posedge clk);
`endif `endif
$display("TRAP after %1d clock cycles", cycle_counter); $display("TRAP after %1d clock cycles", cycle_counter);
if (tests_passed) begin
$display("ALL TESTS PASSED.");
$finish; $finish;
end else begin
$display("ERROR!");
$stop;
end
end end
end end
endmodule endmodule
@ -189,7 +225,9 @@ module axi4_memory #(
output reg mem_axi_rvalid = 0, output reg mem_axi_rvalid = 0,
input mem_axi_rready, input mem_axi_rready,
output reg [31:0] mem_axi_rdata output reg [31:0] mem_axi_rdata,
output reg tests_passed
); );
reg [31:0] memory [0:64*1024/4-1] /* verilator public */; reg [31:0] memory [0:64*1024/4-1] /* verilator public */;
@ -199,6 +237,8 @@ module axi4_memory #(
reg axi_test; reg axi_test;
initial axi_test = $test$plusargs("axi_test") || AXI_TEST; initial axi_test = $test$plusargs("axi_test") || AXI_TEST;
initial tests_passed = 0;
reg [63:0] xorshift64_state = 64'd88172645463325252; reg [63:0] xorshift64_state = 64'd88172645463325252;
task xorshift64_next; task xorshift64_next;
@ -292,6 +332,10 @@ module axi4_memory #(
$fflush(); $fflush();
`endif `endif
end end
end else
if (latched_waddr == 32'h2000_0000) begin
if (latched_wdata == 123456789)
tests_passed = 1;
end else begin end else begin
$display("OUT-OF-BOUNDS MEMORY WRITE TO %08x", latched_waddr); $display("OUT-OF-BOUNDS MEMORY WRITE TO %08x", latched_waddr);
$finish; $finish;