mirror of https://github.com/YosysHQ/picorv32.git
Added tracer support (under construction)
This commit is contained in:
parent
8043c90a04
commit
7094e61af7
|
@ -23,6 +23,7 @@
|
|||
/testbench_synth.vvp
|
||||
/testbench.gtkw
|
||||
/testbench.vcd
|
||||
/testbench.trace
|
||||
/check.smt2
|
||||
/check.vcd
|
||||
/synth.log
|
||||
|
|
4
Makefile
4
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
50
picorv32.v
50
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
62
testbench.v
62
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;
|
||||
|
|
Loading…
Reference in New Issue