| `timescale 1 ns / 1 ps |
| |
| `ifndef VERILATOR |
| module testbench #( |
| parameter VERBOSE = 0 |
| ); |
| reg clk = 1; |
| reg resetn = 1; |
| wire trap; |
| |
| always #5 clk = ~clk; |
| |
| initial begin |
| repeat (100) @(posedge clk); |
| resetn <= 0; |
| end |
| |
| initial begin |
| if ($test$plusargs("vcd")) begin |
| $dumpfile("testbench.vcd"); |
| $dumpvars(0, testbench); |
| end |
| repeat (1000000) @(posedge clk); |
| $display("TIMEOUT"); |
| $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); |
| $display("Finished writing testbench.trace."); |
| end |
| end |
| |
| picorv32_wrapper #( |
| .VERBOSE (VERBOSE) |
| ) top ( |
| .wb_clk(clk), |
| .wb_rst(resetn), |
| .trap(trap), |
| .trace_valid(trace_valid), |
| .trace_data(trace_data) |
| ); |
| endmodule |
| `endif |
| |
| module picorv32_wrapper #( |
| parameter VERBOSE = 0 |
| ) ( |
| input wb_clk, |
| input wb_rst, |
| output trap, |
| output trace_valid, |
| output [35:0] trace_data |
| ); |
| wire tests_passed; |
| reg [31:0] irq = 0; |
| wire mem_instr; |
| |
| reg [15:0] count_cycle = 0; |
| always @(posedge wb_clk) count_cycle <= !wb_rst ? count_cycle + 1 : 0; |
| |
| always @* begin |
| irq = 0; |
| irq[4] = &count_cycle[12:0]; |
| irq[5] = &count_cycle[15:0]; |
| end |
| |
| wire [31:0] wb_m2s_adr; |
| wire [31:0] wb_m2s_dat; |
| wire [3:0] wb_m2s_sel; |
| wire wb_m2s_we; |
| wire wb_m2s_cyc; |
| wire wb_m2s_stb; |
| wire [31:0] wb_s2m_dat; |
| wire wb_s2m_ack; |
| |
| wb_ram #( |
| .depth (128*1024), |
| .VERBOSE (VERBOSE) |
| ) ram ( // Wishbone interface |
| .wb_clk_i(wb_clk), |
| .wb_rst_i(wb_rst), |
| |
| .wb_adr_i(wb_m2s_adr), |
| .wb_dat_i(wb_m2s_dat), |
| .wb_stb_i(wb_m2s_stb), |
| .wb_cyc_i(wb_m2s_cyc), |
| .wb_dat_o(wb_s2m_dat), |
| .wb_ack_o(wb_s2m_ack), |
| .wb_sel_i(wb_m2s_sel), |
| .wb_we_i(wb_m2s_we), |
| |
| .mem_instr(mem_instr), |
| .tests_passed(tests_passed) |
| ); |
| |
| picorv32_wb #( |
| `ifndef SYNTH_TEST |
| `ifdef SP_TEST |
| .ENABLE_REGS_DUALPORT(0), |
| `endif |
| `ifdef COMPRESSED_ISA |
| .COMPRESSED_ISA(1), |
| `endif |
| .ENABLE_MUL(1), |
| .ENABLE_DIV(1), |
| .ENABLE_IRQ(1), |
| .ENABLE_TRACE(1) |
| `endif |
| ) uut ( |
| .trap (trap), |
| .irq (irq), |
| .trace_valid (trace_valid), |
| .trace_data (trace_data), |
| .mem_instr(mem_instr), |
| |
| .wb_clk_i(wb_clk), |
| .wb_rst_i(wb_rst), |
| |
| .wbm_adr_o(wb_m2s_adr), |
| .wbm_dat_i(wb_s2m_dat), |
| .wbm_stb_o(wb_m2s_stb), |
| .wbm_ack_i(wb_s2m_ack), |
| .wbm_cyc_o(wb_m2s_cyc), |
| .wbm_dat_o(wb_m2s_dat), |
| .wbm_we_o(wb_m2s_we), |
| .wbm_sel_o(wb_m2s_sel) |
| ); |
| |
| reg [1023:0] firmware_file; |
| initial begin |
| if (!$value$plusargs("firmware=%s", firmware_file)) |
| firmware_file = "firmware/firmware.hex"; |
| $readmemh(firmware_file, ram.mem); |
| end |
| |
| integer cycle_counter; |
| always @(posedge wb_clk) begin |
| cycle_counter <= !wb_rst ? cycle_counter + 1 : 0; |
| if (!wb_rst && trap) begin |
| `ifndef VERILATOR |
| repeat (10) @(posedge wb_clk); |
| `endif |
| $display("TRAP after %1d clock cycles", cycle_counter); |
| if (tests_passed) begin |
| $display("ALL TESTS PASSED."); |
| $finish; |
| end else begin |
| $display("ERROR!"); |
| if ($test$plusargs("noerror")) |
| $finish; |
| $stop; |
| end |
| end |
| end |
| endmodule |
| |
| /* ISC License |
| * |
| * Verilog on-chip RAM with Wishbone interface |
| * |
| * Copyright (C) 2014, 2016 Olof Kindgren <olof.kindgren@gmail.com> |
| * |
| * Permission to use, copy, modify, and/or distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| module wb_ram #( |
| parameter depth = 256, |
| parameter memfile = "", |
| parameter VERBOSE = 0 |
| ) ( |
| input wb_clk_i, |
| input wb_rst_i, |
| |
| input [31:0] wb_adr_i, |
| input [31:0] wb_dat_i, |
| input [3:0] wb_sel_i, |
| input wb_we_i, |
| input wb_cyc_i, |
| input wb_stb_i, |
| |
| output reg wb_ack_o, |
| output reg [31:0] wb_dat_o, |
| |
| input mem_instr, |
| output reg tests_passed |
| ); |
| |
| reg verbose; |
| initial verbose = $test$plusargs("verbose") || VERBOSE; |
| |
| initial tests_passed = 0; |
| |
| reg [31:0] adr_r; |
| wire valid = wb_cyc_i & wb_stb_i; |
| |
| always @(posedge wb_clk_i) begin |
| adr_r <= wb_adr_i; |
| // Ack generation |
| wb_ack_o <= valid & !wb_ack_o; |
| if (wb_rst_i) |
| begin |
| adr_r <= {32{1'b0}}; |
| wb_ack_o <= 1'b0; |
| end |
| end |
| |
| wire ram_we = wb_we_i & valid & wb_ack_o; |
| |
| wire [31:0] waddr = adr_r[31:2]; |
| wire [31:0] raddr = wb_adr_i[31:2]; |
| wire [3:0] we = {4{ram_we}} & wb_sel_i; |
| |
| wire [$clog2(depth/4)-1:0] raddr2 = raddr[$clog2(depth/4)-1:0]; |
| wire [$clog2(depth/4)-1:0] waddr2 = waddr[$clog2(depth/4)-1:0]; |
| |
| reg [31:0] mem [0:depth/4-1] /* verilator public */; |
| |
| always @(posedge wb_clk_i) begin |
| if (ram_we) begin |
| if (verbose) |
| $display("WR: ADDR=%08x DATA=%08x STRB=%04b", |
| adr_r, wb_dat_i, we); |
| |
| if (adr_r[31:0] == 32'h1000_0000) |
| if (verbose) begin |
| if (32 <= wb_dat_i[7:0] && wb_dat_i[7:0] < 128) |
| $display("OUT: '%c'", wb_dat_i[7:0]); |
| else |
| $display("OUT: %3d", wb_dat_i[7:0]); |
| end else begin |
| $write("%c", wb_dat_i[7:0]); |
| `ifndef VERILATOR |
| $fflush(); |
| `endif |
| end |
| else |
| if (adr_r[31:0] == 32'h2000_0000) |
| if (wb_dat_i[31:0] == 123456789) |
| tests_passed = 1; |
| end |
| end |
| |
| always @(posedge wb_clk_i) begin |
| if (waddr2 < 128 * 1024 / 4) begin |
| if (we[0]) |
| mem[waddr2][7:0] <= wb_dat_i[7:0]; |
| |
| if (we[1]) |
| mem[waddr2][15:8] <= wb_dat_i[15:8]; |
| |
| if (we[2]) |
| mem[waddr2][23:16] <= wb_dat_i[23:16]; |
| |
| if (we[3]) |
| mem[waddr2][31:24] <= wb_dat_i[31:24]; |
| |
| end |
| |
| if (valid & wb_ack_o & !ram_we) |
| if (verbose) |
| $display("RD: ADDR=%08x DATA=%08x%s", adr_r, mem[raddr2], mem_instr ? " INSN" : ""); |
| |
| wb_dat_o <= mem[raddr2]; |
| end |
| |
| initial begin |
| if (memfile != "") |
| $readmemh(memfile, mem); |
| end |
| endmodule |