| // Softshell testbench. |
| // |
| // SPDX-FileCopyrightText: (c) 2020 Harrison Pham <harrison@harrisonpham.com> |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| `timescale 1 ns / 1 ps |
| |
| `define MPRJ_IO_PADS 38 |
| `define MPRJ_PWR_PADS 4 /* vdda1, vccd1, vdda2, vccd2 */ |
| // `define USE_CUSTOM_DFFRAM |
| `define USE_OPENRAM |
| `define MEM_WORDS 256 |
| `define COLS 1 |
| |
| `ifdef GL |
| // NOTE: Make sure to keep this in sync with the actual RTL. |
| `define SHARED_MEM_WORDS 512 |
| `define MEM_TEST_STEP_SIZE_WORDS 123 |
| `else |
| `define MEM_TEST_STEP_SIZE_WORDS 1 |
| `endif |
| |
| // Models. |
| // `include "third_party/sky130/models/sram_1rw1r_32_256_8_sky130.v" |
| // `include "third_party/DFFRAM/models/DFFRAMBB.v" |
| // `include "third_party/DFFRAM/models/DFFRAM.v" |
| `include "third_party/picorv32/picosoc/spiflash.v" |
| |
| // Gatelevel models. |
| //`ifdef GL |
| `include "libs.ref/sky130_fd_sc_hd/verilog/primitives.v" |
| `include "libs.ref/sky130_fd_sc_hd/verilog/sky130_fd_sc_hd.v" |
| // `include "libs.ref/sky130_fd_sc_hvl/verilog/primitives.v" |
| // `include "libs.ref/sky130_fd_sc_hvl/verilog/sky130_fd_sc_hvl.v" |
| //`endif |
| |
| // Design. |
| `ifdef GL |
| `include "../../../gl/user_proj_example.v" |
| `else |
| `include "softshell_top.v" |
| `include "rv_core.v" |
| `include "pinmux.v" |
| `include "pcpi_flexio.v" |
| `include "third_party/verilog-wishbone/rtl/wb_arbiter_3.v" |
| `include "third_party/verilog-wishbone/rtl/wb_arbiter_4.v" |
| `include "third_party/verilog-wishbone/rtl/wb_arbiter_5.v" |
| `include "third_party/verilog-wishbone/rtl/arbiter.v" |
| `include "third_party/verilog-wishbone/rtl/priority_encoder.v" |
| `include "third_party/verilog-wishbone/rtl/wb_mux_3.v" |
| `include "third_party/verilog-wishbone/rtl/wb_mux_5.v" |
| `include "third_party/picorv32_wb/mem_ff_wb.v" |
| `include "third_party/picorv32_wb/simpleuart.v" |
| `include "third_party/picorv32_wb/spimemio.v" |
| `include "third_party/picorv32_wb/picorv32.v" |
| `include "third_party/picorv32_wb/gpio32_wb.v" |
| `include "third_party/wb2axip/rtl/afifo.v" |
| `endif |
| |
| module softshell_top_tb; |
| reg clk; |
| reg resetb; |
| |
| wire wb_clk_i; |
| wire wb_rst_i; |
| reg wb_stb_i; |
| reg wb_cyc_i; |
| reg wb_we_i; |
| reg [3:0] wb_sel_i; |
| reg [31:0] wb_dat_i; |
| reg [31:0] wb_adr_i; |
| wire wb_ack_o; |
| wire [31:0] wb_dat_o; |
| |
| reg [127:0] la_data_in; |
| wire [127:0] la_data_out; |
| reg [127:0] la_oen; |
| |
| wire [`MPRJ_IO_PADS-1:0] io_in; |
| wire [`MPRJ_IO_PADS-1:0] io_out; |
| wire [`MPRJ_IO_PADS-1:0] io_oeb; |
| |
| reg [`MPRJ_IO_PADS-1:0] io_in_reg; |
| |
| // Exclude flash pad and UART loopback. |
| assign io_in[37:32] = io_in_reg[37:32]; |
| assign io_in[30:14] = io_in_reg[30:14]; |
| |
| // UART loopback pin 32 (RX) to pin 31 (TX) |
| assign io_in[31] = (!io_oeb[30]) ? (io_out[30]) : (1'bz); |
| |
| always #50 clk = ~clk; |
| |
| assign wb_clk_i = clk; |
| assign wb_rst_i = ~resetb; |
| |
| integer i, address, data; |
| initial begin |
| $dumpfile("softshell_top_tb.fst"); |
| $dumpvars(0, softshell_top_tb); |
| |
| clk = 0; |
| resetb = 0; |
| |
| io_in_reg = {`MPRJ_IO_PADS{1'b0}}; |
| |
| la_data_in = 128'b0; |
| la_oen = 128'b0; |
| |
| wb_stb_i = 0; |
| wb_cyc_i = 0; |
| wb_sel_i = 4'b0; |
| wb_we_i = 0; |
| wb_adr_i = 32'b0; |
| wb_dat_i = 32'b0; |
| |
| #200; |
| resetb = 1; |
| #200; |
| $display("Reset complete"); |
| |
| $display("Holding CPUs in reset for RAM test"); |
| la_data_in[4:1] = 4'b1111; |
| |
| $display("Testing shared memory"); |
| for (i = 0; i < 32 * 4; i = i + 4) begin |
| address = 32'h3000_0000 + i; |
| data = $random; |
| write(address, data); |
| write(address + 4, ~data); |
| read_assert(address, data); |
| read_assert(address + 4, ~data); |
| end |
| for (i = 0; i < `SHARED_MEM_WORDS * 4; |
| i = i + 4 * `MEM_TEST_STEP_SIZE_WORDS) begin |
| address = 32'h3000_0000 + i; |
| data = i; |
| write(address, data); |
| read_assert(address, data); |
| end |
| for (i = 0; i < `SHARED_MEM_WORDS * 4; |
| i = i + 4 * `MEM_TEST_STEP_SIZE_WORDS) begin |
| address = 32'h3000_0000 + i; |
| data = i; |
| read_assert(address, data); |
| end |
| |
| $display("Releasing CPUs from reset"); |
| la_data_in[4:1] = 4'b1110; |
| |
| $display("Waiting for CPU GPIO toggles"); |
| // wait(io_out[7+14:0+14] != 8'h00); |
| wait(io_out[37] == 1'b1); |
| |
| $display("Finished"); |
| $finish; |
| end |
| |
| `ifndef GL |
| always begin |
| wait(uut.cpus[0].core.trap == 1'b1); |
| $error("CPU0 TRAP!"); |
| $finish; |
| end |
| |
| always begin |
| wait(uut.cpus[1].core.trap == 1'b1); |
| $error("CPU1 TRAP!"); |
| $finish; |
| end |
| `endif |
| |
| `ifdef GL |
| user_proj_example uut ( |
| .VPWR(1'b1), |
| .VGND(1'b0), |
| `else |
| softshell_top uut ( |
| `endif |
| .wb_clk_i(wb_clk_i), |
| .wb_rst_i(wb_rst_i), |
| |
| .wbs_stb_i(wb_stb_i), |
| .wbs_cyc_i(wb_cyc_i), |
| .wbs_we_i(wb_we_i), |
| .wbs_sel_i(wb_sel_i), |
| .wbs_dat_i(wb_dat_i), |
| .wbs_adr_i(wb_adr_i), |
| .wbs_ack_o(wb_ack_o), |
| .wbs_dat_o(wb_dat_o), |
| |
| // Logic Analyzer Signals |
| .la_data_in(la_data_in), |
| .la_data_out(la_data_out), |
| .la_oen(la_oen), |
| |
| // IOs |
| .io_in(io_in), |
| .io_out(io_out), |
| .io_oeb(io_oeb) |
| ); |
| |
| // Flash signals. |
| wire flash_csb; |
| wire flash_clk; |
| wire flash_io0; |
| wire flash_io1; |
| wire flash_io2; |
| wire flash_io3; |
| |
| assign flash_csb = (io_oeb[8] == 1'b0) ? (io_out[8]) : (1'bz); |
| assign flash_clk = (io_oeb[9] == 1'b0) ? (io_out[9]) : (1'bz); |
| assign flash_io0 = (io_oeb[10] == 1'b0) ? (io_out[10]) : (1'bz); |
| assign flash_io1 = (io_oeb[11] == 1'b0) ? (io_out[11]) : (1'bz); |
| assign flash_io2 = (io_oeb[12] == 1'b0) ? (io_out[12]) : (1'bz); |
| assign flash_io3 = (io_oeb[13] == 1'b0) ? (io_out[13]) : (1'bz); |
| assign io_in[10] = flash_io0; |
| assign io_in[11] = flash_io1; |
| assign io_in[12] = flash_io2; |
| assign io_in[13] = flash_io3; |
| |
| spiflash flash_model ( |
| .csb(flash_csb), |
| .clk(flash_clk), |
| .io0(flash_io0), |
| .io1(flash_io1), |
| .io2(flash_io2), |
| .io3(flash_io3) |
| ); |
| |
| task write; |
| input [31:0] addr; |
| input [31:0] data; |
| begin |
| @(posedge wb_clk_i) begin |
| wb_stb_i = 1; |
| wb_cyc_i = 1; |
| wb_sel_i = 4'hF; |
| wb_we_i = 1; |
| wb_adr_i = addr; |
| wb_dat_i = data; |
| $display("W [%0h]=%0h", addr, data); |
| end |
| // Wait for an ACK |
| wait(wb_ack_o == 1); |
| wait(wb_ack_o == 0); |
| wb_cyc_i = 0; |
| wb_stb_i = 0; |
| $display("W D"); |
| end |
| endtask |
| |
| task read; |
| input [31:0] addr; |
| begin |
| @(posedge wb_clk_i) begin |
| wb_stb_i = 1; |
| wb_cyc_i = 1; |
| wb_we_i = 0; |
| wb_adr_i = addr; |
| $display("R [%0h]", addr); |
| end |
| // Wait for an ACK |
| wait(wb_ack_o == 1); |
| wait(wb_ack_o == 0); |
| wb_cyc_i = 0; |
| wb_stb_i = 0; |
| $display("R D [%0h]=%0h", addr, wb_dat_o); |
| end |
| endtask |
| |
| task read_assert; |
| input [31:0] addr; |
| input [31:0] data; |
| begin |
| read(addr); |
| if (wb_dat_o != data) begin |
| $error("R!! %0h!=%0h", wb_dat_o, data); |
| $fatal; |
| end |
| end |
| endtask |
| |
| endmodule |