blob: 8d7d38641f5c31f6fbbc1a9892a2e5430107f784 [file] [log] [blame]
// SPDX-FileCopyrightText: 2020 Efabless Corporation
//
// 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.
// SPDX-License-Identifier: Apache-2.0
`default_nettype none
`timescale 1 ns / 1 ps
module io_ports_tb;
reg clock;
reg RSTB;
reg CSB;
reg power1, power2;
reg power3, power4;
wire gpio;
wire [37:0] mprj_io;
reg [31:0] loop_count, wdata;
reg [7:0] bdata;
reg [31:0] buffer [0:511]; // buffer for SPI flash memory
reg [31:0] index, byte_no, bit_index;
reg clock_sel;
reg my_reset;
reg homing_switch_x, homing_switch_y;
reg io_uart_tx;
reg io_uart_rx;
reg io_spi_cs, io_spi_clk, io_spi_mosi;
reg io_spi_miso;
reg io_dir_m1, io_dir_m2;
reg step1step, step2step;
reg pen_servo_control;
reg clk_muxed;
reg io_m1_io_qei_ch_a,
io_m1_io_qei_ch_b,
io_m2_io_qei_ch_a,
io_m2_io_qei_ch_b,
io_m3_io_qei_ch_a,
io_m3_io_qei_ch_b;
assign mprj_io[ 5] = clock_sel;
assign mprj_io[ 7] = 0; //io_m1_io_qei_ch_a;
assign mprj_io[ 8] = 0; //io_m1_io_qei_ch_b;
assign mprj_io[11] = 0; //io_m1_io_x_homed;
assign mprj_io[12] = 0; //io_m1_io_y_homed;
assign mprj_io[15] = my_reset;
assign mprj_io[16] = 0; //io_m2_io_qei_ch_a;
assign mprj_io[17] = 0; //io_m2_io_qei_ch_b;
assign mprj_io[20] = homing_switch_x; //io_m2_io_x_homed;
assign mprj_io[21] = homing_switch_y; //io_m2_io_y_homed;
assign mprj_io[27] = io_spi_miso;
assign mprj_io[28] = io_uart_rx;
assign mprj_io[30] = 0; //io_m3_io_qei_ch_a;
assign mprj_io[31] = 0; //io_m3_io_qei_ch_b;
assign mprj_io[34] = 0; //io_m3_io_x_homed;
assign mprj_io[35] = 0; //io_m3_io_y_homed;
always@(*)
begin
clk_muxed = mprj_io[ 6];
pen_servo_control = mprj_io[ 9];
step1step = mprj_io[19];
io_dir_m1 = mprj_io[22];
io_dir_m2 = mprj_io[23];
io_spi_mosi = mprj_io[24];
io_spi_clk = mprj_io[25];
io_spi_cs = mprj_io[26];
io_uart_tx = mprj_io[29];
step2step = mprj_io[33];
clock_sel = 1'b0;
io_uart_rx = io_uart_tx; // loopback
homing_switch_x = 0; // assume motors are homed
homing_switch_y = 0; // assume motors are homed
//io_m1_io_qei_ch_a = 1'b0;
//io_m1_io_qei_ch_b = 1'b0;
//io_m2_io_qei_ch_a = 1'b0;
//io_m2_io_qei_ch_b = 1'b0;
//io_m3_io_qei_ch_a = 1'b0;
//io_m3_io_qei_ch_b = 1'b0;
end
// External clock is used by default. Make this artificially fast for the
// simulation. Normally this would be a slow clock and the digital PLL
// would be the fast clock.
always #12.5 clock <= (clock === 1'b0);
initial begin
clock = 0;
end
`ifdef ENABLE_SDF
initial begin
$sdf_annotate("../../../sdf/user_proj_example.sdf", uut.mprj) ;
$sdf_annotate("../../../sdf/user_project_wrapper.sdf", uut.mprj.mprj) ;
$sdf_annotate("../../../mgmt_core_wrapper/sdf/DFFRAM.sdf", uut.soc.DFFRAM_0) ;
$sdf_annotate("../../../mgmt_core_wrapper/sdf/mgmt_core.sdf", uut.soc.core) ;
$sdf_annotate("../../../caravel/sdf/housekeeping.sdf", uut.housekeeping) ;
$sdf_annotate("../../../caravel/sdf/chip_io.sdf", uut.padframe) ;
$sdf_annotate("../../../caravel/sdf/mprj_logic_high.sdf", uut.mgmt_buffers.mprj_logic_high_inst) ;
$sdf_annotate("../../../caravel/sdf/mprj2_logic_high.sdf", uut.mgmt_buffers.mprj2_logic_high_inst) ;
$sdf_annotate("../../../caravel/sdf/mgmt_protect_hv.sdf", uut.mgmt_buffers.powergood_check) ;
$sdf_annotate("../../../caravel/sdf/mgmt_protect.sdf", uut.mgmt_buffers) ;
$sdf_annotate("../../../caravel/sdf/caravel_clocking.sdf", uut.clocking) ;
$sdf_annotate("../../../caravel/sdf/digital_pll.sdf", uut.pll) ;
$sdf_annotate("../../../caravel/sdf/xres_buf.sdf", uut.rstb_level) ;
$sdf_annotate("../../../caravel/sdf/user_id_programming.sdf", uut.user_id_value) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_bidir_1[0] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_bidir_1[1] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_bidir_2[0] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_bidir_2[1] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_bidir_2[2] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1[0] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1[1] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1[2] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1[3] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1[4] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1[5] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1[6] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1[7] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1[8] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1[9] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1[10] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1a[0] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1a[1] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1a[2] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1a[3] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1a[4] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_1a[5] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[0] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[1] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[2] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[3] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[4] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[5] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[6] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[7] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[8] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[9] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[10] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[11] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[12] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[13] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[14] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_control_block.sdf", uut.\gpio_control_in_2[15] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.\gpio_defaults_block_0[0] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.\gpio_defaults_block_0[1] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.\gpio_defaults_block_2[0] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.\gpio_defaults_block_2[1] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.\gpio_defaults_block_2[2] ) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_5) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_6) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_7) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_8) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_9) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_10) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_11) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_12) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_13) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_14) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_15) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_16) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_17) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_18) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_19) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_20) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_21) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_22) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_23) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_24) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_25) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_26) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_27) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_28) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_29) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_30) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_31) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_32) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_33) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_34) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_35) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_36) ;
$sdf_annotate("../../../caravel/sdf/gpio_defaults_block.sdf", uut.gpio_defaults_block_37) ;
// $sdf_annotate("../../synthesis/riscv_delays.sdf", RISCVCPU_tb.my_cpu,,"sdf.log","MAXIMUM");
end
`endif
wire [31:0] loop_count_divided;
assign loop_count_divided = loop_count >> 10;
always@(index or loop_count_divided)
begin
$display("Time: %d\t index: %d \t loop_count = %d", $time, index, loop_count);
end
//always@(*) $display("First few bytes of memory:\n io_ports_tb.uut.mprj.mprj.wb_inter_connect.imem.imem.imem.imem_ext.mem_0_0.mem[0] = %h \n\n", io_ports_tb.uut.mprj.mprj.wb_inter_connect.imem.imem.imem.imem_ext.mem_0_0.mem[0]); // debug
initial begin
$dumpfile("io_ports.vcd");
$dumpvars(0, io_ports_tb);
//$dumpvars(1, io_ports_tb.uut.mprj.mprj.clk_muxed, SoC_tb.index, io_ports_tb.uut.mprj.mprj.wb_inter_connect.uart.tx_data_r, SoC_tb.io_dir_m1, SoC_tb.io_dir_m2, SoC_tb.pen_servo_control, SoC_tb.step1step, SoC_tb.step2step);
//$monitor("Time: %d\t index: %d \t loop_count_divided = %d", $time, index, loop_count_divided);
$display("Starting reset sequence...");
my_reset = 1;
#2000;
my_reset = 0;
`ifdef GL
$display ("Testbench passed"); // gate-level simulation of SoC_Tile has already been carried out using Xcelium; as for Caravel, we trust Efabless to complete their work, since gate-level simulation of Caravel using iverilog is too time-consuming :)
`endif
wait(clk_muxed === 1'b1); // wait for management core to finish configuration of the GPIOs that are to be used as outputs
#2000;
my_reset = 1; // apply reset again
#2000;
my_reset = 0;
$display("Starting loading of program over SPI...");
$readmemh("imem.txt", buffer);
index = 0;
io_spi_miso = 0;
for (loop_count = 0; loop_count < 300000; loop_count = loop_count + 1)
begin
//$display("Loop count = %d\n", loop_count);
@ (posedge clock);
// transmit the instruction memory contents byte by byte over SPI
if (io_spi_mosi == 1)
begin
wdata = buffer[index];
index = index + 1; // increment byte index
//if (index == 2) $finish; // debug
repeat (431) @ (posedge clock);
for (byte_no = 0; byte_no < 4; byte_no = byte_no + 1)
begin
case (byte_no)
0: bdata = wdata[7:0];
1: bdata = wdata[15:8];
2: bdata = wdata[23:16];
3: bdata = wdata[31:24];
endcase
repeat (68) @ (posedge clock);
// transmit the selected byte bit by bit over SPI
for (bit_index = 0; bit_index < 8; bit_index = bit_index + 1)
begin
io_spi_miso = bdata[7 - bit_index];
repeat (8) @ (posedge clock);
end
@ (posedge clock);
io_spi_miso = 0;
end
end
end
$display("%c[1;31m",27);
$display("Testbench failed.");
// `ifdef GL
// $display ("Monitor: Timeout, Test Mega-Project IO Ports (GL) Failed");
// `else
// $display ("Monitor: Timeout, Test Mega-Project IO Ports (RTL) Failed");
// `endif
$display("%c[0m",27);
$finish;
end
initial // logic has been verified through practical demonstration using FPGA, hence this testbench is only checking connections by applying inputs and observing that the outputs are toggling as a result of the inputs
begin
wait(io_ports_tb.uut.mprj.mprj.wb_inter_connect.uart.tx_data_r == 8'd0); // wait till program transmits the coordinates (0, 0)
repeat(2) // wait for 2 pulses of pen_servo_control output
begin
@ (posedge pen_servo_control);
@ (negedge pen_servo_control);
end
wait(io_ports_tb.uut.mprj.mprj.wb_inter_connect.uart.tx_data_r == 8'd100); // wait for d i.e. the down command
@ (posedge io_dir_m2); // current coordinates are (0, 0) so no movement occurs i.e. no step pulses to motors; just check for change of direction output
wait(io_ports_tb.uut.mprj.mprj.wb_inter_connect.uart.tx_data_r == 8'd108); // wait for l i.e. the left command
wait(step1step == 1'b0);
wait(step2step == 1'b0);
@ (negedge io_dir_m1);
wait(step1step == 1'b1);
wait(step2step == 1'b1);
@ (negedge step1step);
wait(step2step == 1'b0);
#500000
$display("Testbench passed.");
// `ifdef GL
// $display("Monitor: Test 1 Mega-Project IO (GL) Passed");
// `else
// $display("Monitor: Test 1 Mega-Project IO (RTL) Passed");
// `endif
$finish;
end
initial begin
RSTB <= 1'b0;
CSB <= 1'b1; // Force CSB high
#2000;
RSTB <= 1'b1; // Release reset
#3_00_000;
CSB = 1'b0; // CSB can be released
end
initial begin // Power-up sequence
power1 <= 1'b0;
power2 <= 1'b0;
power3 <= 1'b0;
power4 <= 1'b0;
#100;
power1 <= 1'b1;
#100;
power2 <= 1'b1;
#100;
power3 <= 1'b1;
#100;
power4 <= 1'b1;
end
// always @(mprj_io) begin
// #1 $display("MPRJ-IO state = %b ", mprj_io[7:0]);
// end
wire flash_csb;
wire flash_clk;
wire flash_io0;
wire flash_io1;
wire VDD3V3;
wire VDD1V8;
wire VSS;
assign VDD3V3 = power1;
assign VDD1V8 = power2;
assign VSS = 1'b0;
caravel uut (
.vddio (VDD3V3),
.vddio_2 (VDD3V3),
.vssio (VSS),
.vssio_2 (VSS),
.vdda (VDD3V3),
.vssa (VSS),
.vccd (VDD1V8),
.vssd (VSS),
.vdda1 (VDD3V3),
.vdda1_2 (VDD3V3),
.vdda2 (VDD3V3),
.vssa1 (VSS),
.vssa1_2 (VSS),
.vssa2 (VSS),
.vccd1 (VDD1V8),
.vccd2 (VDD1V8),
.vssd1 (VSS),
.vssd2 (VSS),
.clock (clock),
.gpio (gpio),
.mprj_io (mprj_io),
.flash_csb(flash_csb),
.flash_clk(flash_clk),
.flash_io0(flash_io0),
.flash_io1(flash_io1),
.resetb (RSTB)
);
spiflash #(
.FILENAME("io_ports.hex")
) spiflash (
.csb(flash_csb),
.clk(flash_clk),
.io0(flash_io0),
.io1(flash_io1),
.io2(), // not used
.io3() // not used
);
endmodule
`default_nettype wire