aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2016-08-25 14:15:42 +0200
committerClifford Wolf <clifford@clifford.at>2016-08-25 14:15:42 +0200
commit7094e61af7dfe3c24ff4218557b209a1b09e5793 (patch)
tree4906b7411df5594f68dda674a29bee2d6a28e82f
parent8043c90a04031c1619d0be7b1aba717e4f9968ac (diff)
downloadpicorv32-7094e61af7dfe3c24ff4218557b209a1b09e5793.tar.gz
picorv32-7094e61af7dfe3c24ff4218557b209a1b09e5793.zip
Added tracer support (under construction)
-rw-r--r--.gitignore1
-rw-r--r--Makefile4
-rw-r--r--firmware/start.S4
-rw-r--r--picorv32.v50
-rw-r--r--showtrace.py50
-rw-r--r--testbench.v62
6 files changed, 157 insertions, 14 deletions
diff --git a/.gitignore b/.gitignore
index 846b1a5..4713dd8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@
/testbench_synth.vvp
/testbench.gtkw
/testbench.vcd
+/testbench.trace
/check.smt2
/check.vcd
/synth.log
diff --git a/Makefile b/Makefile
index e1511fd..bb73fd9 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ test: testbench.vvp firmware/firmware.hex
vvp -N testbench.vvp
testbench.vcd: testbench.vvp firmware/firmware.hex
- vvp -N $< +vcd
+ vvp -N $< +vcd +trace
view: testbench.vcd
gtkwave $< testbench.gtkw
@@ -131,7 +131,7 @@ clean:
riscv-gnu-toolchain-riscv32im riscv-gnu-toolchain-riscv32imc
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 \
- 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
diff --git a/firmware/start.S b/firmware/start.S
index e256cac..dda08ed 100644
--- a/firmware/start.S
+++ b/firmware/start.S
@@ -478,6 +478,10 @@ start:
sw a4,0(a0)
sw a5,0(a0)
+ li a0, 0x20000000
+ li a1, 123456789
+ sw a1,0(a0)
+
/* trap */
ebreak
diff --git a/picorv32.v b/picorv32.v
index 2d2cf94..a2dc8a2 100644
--- a/picorv32.v
+++ b/picorv32.v
@@ -58,6 +58,7 @@ module picorv32 #(
parameter [ 0:0] ENABLE_IRQ = 0,
parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
parameter [ 0:0] ENABLE_IRQ_TIMER = 1,
+ parameter [ 0:0] ENABLE_TRACE = 0,
parameter [ 0:0] REGS_INIT_ZERO = 0,
parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff,
@@ -96,7 +97,11 @@ module picorv32 #(
// IRQ Interface
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_ebreak = 1;
@@ -108,6 +113,10 @@ module picorv32 #(
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 [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out;
reg [31:0] cpuregs [0:regfile_size-1];
@@ -1016,6 +1025,7 @@ module picorv32 #(
reg latched_stalu;
reg latched_branch;
reg latched_compr;
+ reg latched_trace;
reg latched_is_lu;
reg latched_is_lh;
reg latched_is_lb;
@@ -1155,6 +1165,9 @@ module picorv32 #(
decoder_pseudo_trigger_q <= decoder_pseudo_trigger;
do_waitirq <= 0;
+ if (ENABLE_TRACE)
+ trace_valid <= 0;
+
if (!resetn) begin
reg_pc <= PROGADDR_RESET;
reg_next_pc <= PROGADDR_RESET;
@@ -1163,6 +1176,7 @@ module picorv32 #(
latched_store <= 0;
latched_stalu <= 0;
latched_branch <= 0;
+ latched_trace <= 0;
latched_is_lu <= 0;
latched_is_lh <= 0;
latched_is_lb <= 0;
@@ -1218,6 +1232,15 @@ module picorv32 #(
end
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_next_pc <= current_pc;
@@ -1253,6 +1276,8 @@ module picorv32 #(
`debug($display("-- %-0t", $time);)
irq_delay <= irq_active;
reg_next_pc <= current_pc + (compressed_instr ? 2 : 4);
+ if (ENABLE_TRACE)
+ latched_trace <= 1;
if (ENABLE_COUNTERS) begin
count_instr <= count_instr + 1;
if (!ENABLE_COUNTERS64) count_instr[63:32] <= 0;
@@ -1519,6 +1544,8 @@ module picorv32 #(
end
cpu_state_stmem: begin
+ if (ENABLE_TRACE)
+ reg_out <= reg_op2;
if (!mem_do_prefetch || mem_done) begin
if (!mem_do_wdata) begin
(* parallel_case, full_case *)
@@ -1527,6 +1554,10 @@ module picorv32 #(
instr_sh: mem_wordsize <= 1;
instr_sw: mem_wordsize <= 0;
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;
set_mem_do_wdata = 1;
end
@@ -1551,6 +1582,10 @@ module picorv32 #(
latched_is_lu <= is_lbu_lhu_lw;
latched_is_lh <= instr_lh;
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;
set_mem_do_rdata = 1;
end
@@ -1891,6 +1926,7 @@ module picorv32_axi #(
parameter [ 0:0] ENABLE_IRQ = 0,
parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
parameter [ 0:0] ENABLE_IRQ_TIMER = 1,
+ parameter [ 0:0] ENABLE_TRACE = 0,
parameter [ 0:0] REGS_INIT_ZERO = 0,
parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff,
@@ -1936,7 +1972,11 @@ module picorv32_axi #(
// IRQ interface
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 [31:0] mem_addr;
@@ -1993,6 +2033,7 @@ module picorv32_axi #(
.ENABLE_IRQ (ENABLE_IRQ ),
.ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ),
.ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ),
+ .ENABLE_TRACE (ENABLE_TRACE ),
.REGS_INIT_ZERO (REGS_INIT_ZERO ),
.MASKED_IRQ (MASKED_IRQ ),
.LATCHED_IRQ (LATCHED_IRQ ),
@@ -2021,7 +2062,10 @@ module picorv32_axi #(
.pcpi_ready(pcpi_ready),
.irq(irq),
- .eoi(eoi)
+ .eoi(eoi),
+
+ .trace_valid(trace_valid),
+ .trace_data (trace_data)
);
endmodule
diff --git a/showtrace.py b/showtrace.py
new file mode 100644
index 0000000..56c91ff
--- /dev/null
+++ b/showtrace.py
@@ -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
+
diff --git a/testbench.v b/testbench.v
index 23e81c9..dc7a7f3 100644
--- a/testbench.v
+++ b/testbench.v
@@ -15,6 +15,7 @@ module testbench #(
reg clk = 1;
reg resetn = 0;
+ wire trap;
always #5 clk = ~clk;
@@ -33,12 +34,32 @@ module testbench #(
$finish;
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 #(
.AXI_TEST (AXI_TEST),
.VERBOSE (VERBOSE)
) top (
- .clk (clk ),
- .resetn (resetn)
+ .clk(clk),
+ .resetn(resetn),
+ .trap(trap),
+ .trace_valid(trace_valid),
+ .trace_data(trace_data)
);
endmodule
`endif
@@ -48,10 +69,14 @@ module picorv32_wrapper #(
parameter VERBOSE = 0
) (
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;
always @* begin
@@ -107,7 +132,9 @@ module picorv32_wrapper #(
.mem_axi_rvalid (mem_axi_rvalid ),
.mem_axi_rready (mem_axi_rready ),
- .mem_axi_rdata (mem_axi_rdata )
+ .mem_axi_rdata (mem_axi_rdata ),
+
+ .tests_passed (tests_passed )
);
picorv32_axi #(
@@ -119,7 +146,8 @@ module picorv32_wrapper #(
`endif
.ENABLE_MUL(1),
.ENABLE_DIV(1),
- .ENABLE_IRQ(1)
+ .ENABLE_IRQ(1),
+ .ENABLE_TRACE(1)
) uut (
.clk (clk ),
.resetn (resetn ),
@@ -141,7 +169,9 @@ module picorv32_wrapper #(
.mem_axi_rvalid (mem_axi_rvalid ),
.mem_axi_rready (mem_axi_rready ),
.mem_axi_rdata (mem_axi_rdata ),
- .irq (irq )
+ .irq (irq ),
+ .trace_valid (trace_valid ),
+ .trace_data (trace_data )
);
reg [1023:0] firmware_file;
@@ -159,7 +189,13 @@ module picorv32_wrapper #(
repeat (10) @(posedge clk);
`endif
$display("TRAP after %1d clock cycles", cycle_counter);
- $finish;
+ if (tests_passed) begin
+ $display("ALL TESTS PASSED.");
+ $finish;
+ end else begin
+ $display("ERROR!");
+ $stop;
+ end
end
end
endmodule
@@ -189,7 +225,9 @@ module axi4_memory #(
output reg mem_axi_rvalid = 0,
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 */;
@@ -199,6 +237,8 @@ module axi4_memory #(
reg axi_test;
initial axi_test = $test$plusargs("axi_test") || AXI_TEST;
+ initial tests_passed = 0;
+
reg [63:0] xorshift64_state = 64'd88172645463325252;
task xorshift64_next;
@@ -292,6 +332,10 @@ module axi4_memory #(
$fflush();
`endif
end
+ end else
+ if (latched_waddr == 32'h2000_0000) begin
+ if (latched_wdata == 123456789)
+ tests_passed = 1;
end else begin
$display("OUT-OF-BOUNDS MEMORY WRITE TO %08x", latched_waddr);
$finish;