In my specific situation, I am trying to perform a status register read. It consists of a single 8-bit opcode sent on the SI line, and then response data sent back on the SO line until CS is set back to high.
On my system, there is an array of LEDs which I am using to display the data in the status register.
In my testbench, I am manually setting the SDO line so that there is some random data there - this is to mimic the behaviour of the status register.
The testbench inspecting the flash module seems to be correct:
The testbench at top level UUT seems to be correct in all ways except that no data is being output to the LEDs:
Why are the leds not being set in the top level testbench?
The code generating these testbenches is here:
main.v
is the top level system file:
module main #(
parameter COUNT_WIDTH = 3,
parameter [COUNT_WIDTH-1:0] MAX_COUNT = 6000000 - 1
)(
input clk,
output reg [7:0] led,
output reg [3:0] col,
output wire cs,
output wire sck,
output wire sdi,
input sdo
);
// SPI wiring for flash_read module
wire flash_done;
reg start_flash;
wire [7:0] flash_data_out;
// Flash read module instantiation
flash_status flash_stat (
.clk(clk), // 12MHz System clock
.start(start_flash), // Start signal to begin reading
.data_out(flash_data_out), // Data read from flash
.done(flash_done), // Done signal to indicate completion
.CS(cs), // Chip Select (active low)
.SCK(sck), // SPI Clock (Mode 0)
.SI(sdi), // SPI MOSI (Master Output Slave Input)
.SO(sdo) // SPI MISO (Master Input Slave Output)
);
// LEDs wiring
wire [7:0] led_wire;
assign led_wire = led;
wire [3:0] col_wire;
assign col_wire = col;
// LED state
reg [7:0] row_0 = 8'b0;
reg [7:0] row_1 = 8'b0;
reg [7:0] row_2 = 8'b0;
reg [7:0] row_3 = 8'b0;
// Instantiate the LED scan module
LedScan scan (
.clk(clk),
.leds0(flash_data_out),
.leds1(row_1),
.leds2(row_2),
.leds3(row_3),
.leds(led_wire),
.lcol(col_wire)
);
// 10 clock cycle counter to delay
reg [4:0] clock_counter;
// Initialization
initial begin
clock_counter <= 0;
start_flash <= 0;
end
always @(posedge clk) begin
if (clock_counter < 10) begin
// Increment clock counter until it reaches 10
clock_counter <= clock_counter + 1;
end else if (clock_counter == 10) begin
// Trigger the flash read once 10 clock cycles have passed
start_flash <= 1;
clock_counter <= clock_counter + 1; // Move past the 10 clock mark
end else if (flash_done && start_flash) begin
start_flash <= 0; // Reset the flash read trigger
end
end
endmodule
ledscan.v
drives the leds:
module LedScan (
input clk,
input [7:0] leds0,
input [7:0] leds1,
input [7:0] leds2,
input [7:0] leds3,
output reg [7:0] leds,
output reg [3:0] lcol
);
/* Counter register */
reg [11:0] timer = 12'b0;
always @ (posedge clk) begin
case (timer[11:10])
2'b00: begin
leds[7:0] <= ~leds0[7:0];
lcol[3:0] <= 4'b1110;
end
2'b01: begin
leds[7:0] <= ~leds1[7:0];
lcol[3:0] <= 4'b1101;
end
2'b10: begin
leds[7:0] <= ~leds2[7:0];
lcol[3:0] <= 4'b1011;
end
2'b11: begin
leds[7:0] <= ~leds3[7:0];
lcol[3:0] <= 4'b0111;
end
endcase
end
// increment the scan timer
always @ (posedge clk) begin
timer <= timer + 1;
end
endmodule
status.v
drives the flash device:
module flash_status (
input wire clk, // System clock
input wire start, // Start signal to begin the read
output reg [7:0] data_out, // Data read from flash
output reg done, // Done signal to indicate completion
output reg CS, // Chip Select (Active low)
output reg SCK, // SPI Clock (Mode 0)
output reg SI, // SPI MOSI (Master Output Slave Input)
input wire SO // SPI MISO (Master Input Slave Output)
);
// State definitions
reg [3:0] state;
reg [7:0] bit_count_send;
reg [7:0] bit_count_read;
reg [7:0] shift_reg;
integer delay_counter;
localparam IDLE = 4'b0000;
localparam SEND_OPCODE = 4'b0001;
localparam READ_DATA = 4'b0011;
localparam DONE = 4'b0100;
reg [7:0] OPCODE = 8'h05; // Opcode for status read
// Initialization on startup
initial begin
state <= IDLE;
CS <= 1; // CS inactive (high)
SI <= 1;
done <= 0;
delay_counter <= 0;
bit_count_send <= 8;
bit_count_read <= 8;
data_out = 8'b0; // Initialize data_out to zero to avoid undefined values
end
always @ (*) begin
SCK <= clk;
end
always @(negedge clk) begin
case (state)
IDLE: begin
done <= 0;
CS <= 1; // CS inactive
if (start) begin
shift_reg <= {OPCODE}; // Load opcode into shift register
bit_count_send <= 7;
state <= SEND_OPCODE;
end
end
SEND_OPCODE: begin
CS <= 0; // Assert CS (active low)
SI <= shift_reg[bit_count_send]; // Send MSB first
bit_count_send <= bit_count_send - 1;
if (bit_count_send == 0) begin
state <= READ_DATA;
end
end
READ_DATA: begin
data_out[bit_count_read] <= SO; // Sample MISO data
bit_count_read <= bit_count_read - 1;
if (bit_count_read == 0) begin
CS <= 1;
state <= DONE;
end
end
DONE: begin
done <= 1;
if (!start) begin
state <= IDLE; // Go back to IDLE if start is deasserted
end
end
default: state <= IDLE;
endcase
end
endmodule
output_tb.v
is the testbench generator:
`timescale 1 ns / 1 ps
module output_tb();
wire sdi, sdo, cs, sck;
wire [7:0] led;
wire [3:0] col;
// Clock and flash response data simulation
reg clk = 0;
reg sdo_reg = 0; // Simulated response data from the flash device
// Duration of the test
localparam DURATION = 10000;
always begin
#41.67
clk = ~clk;
end
// Instantiate the main module
main #(
.COUNT_WIDTH(4),
.MAX_COUNT(6)
) uut_0 (
.clk(clk),
.led(led),
.col(col),
.cs(cs),
.sck(sck),
.sdi(sdi),
.sdo(sdo_reg) // Connect simulated sdo (flash output)
);
// Simulation of the flash memory's output (sdo)
initial begin
sdo_reg = 8'hFF;
#1000; // Wait for some time before changing the data
sdo_reg = 8'hFF; // Change to another dummy data (0b01010101)
#100; // Wait again
sdo_reg = 8'hFF; // Final dummy data (0b11111111)
#100;
sdo_reg = 8'hFF; // Change to another dummy data (0b01010101)
#100;
sdo_reg = 8'hFF;
#100;
sdo_reg = 8'hFF;
#100;
sdo_reg = 8'hFF;
#100;
sdo_reg = 8'hFF;
#30;
sdo_reg = 8'h00; // Final dummy data (0b00000000)
#30;
sdo_reg = 8'hFF;
#30;
sdo_reg = 8'h00;
#30;
sdo_reg = 8'hFF;
#30;
sdo_reg = 8'h00;
#30;
sdo_reg = 8'hFF;
#30;
sdo_reg = 8'h00;
#30;
sdo_reg = 8'hFF;
#30;
sdo_reg = 8'h00;
#30;
sdo_reg = 8'hFF;
#30;
sdo_reg = 8'h00;
#30;
sdo_reg = 8'hFF;
#30;
sdo_reg = 8'h00;
#30;
sdo_reg = 8'hFF;
#30;
sdo_reg = 8'h00;
#30;
sdo_reg = 8'hFF;
#30;
sdo_reg = 8'h00;
#30;
sdo_reg = 8'hFF;
#30;
sdo_reg = 8'h00;
#30;
sdo_reg = 8'hFF;
#30;
sdo_reg = 8'h00;
#30;
sdo_reg = 8'hFF;
#30;
sdo_reg = 8'h00;
#30;
sdo_reg = 8'hFF;
#30;
end
initial begin
$dumpfile("output_tb.vcd");
$dumpvars(0, output_tb);
#(DURATION); // Run the simulation for DURATION nanoseconds
$finish; // End the simulation
end
endmodule