-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtb.v
More file actions
168 lines (133 loc) · 4.02 KB
/
Copy pathtb.v
File metadata and controls
168 lines (133 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
`timescale 1ns / 1ps
module tb_spi_master();
// Signals & Parameters
reg clk;
reg reset;
reg start;
reg [7:0] data_in;
wire SCLK;
wire MOSI;
wire CS;
wire [7:0] data_out;
// MISO needs to be driven by our mock slave
reg MISO;
// Mock Slave Variables
reg [7:0] slave_tx_data;
reg [7:0] slave_rx_data;
// Unit Under Test (UUT)
spi_master #(
.clk_freq(50_000_000),
.spi_clk_freq(1_000_000),
.data_width(8)
) uut (
.clk(clk),
.reset(reset),
.start(start),
.data_in(data_in),
.MISO(MISO),
.SCLK(SCLK),
.MOSI(MOSI),
.CS(CS),
.data_out(data_out)
);
// Clock Generation (50 MHz = 20ns period)
always #10 clk = ~clk;
// Mock SPI Slave (Mode 0)
// Mode 0: Slave drives data on falling SCLK, samples on rising SCLK.
// 1. Drive the first bit as soon as CS goes active (low)
always @(negedge CS) begin
if (!reset) begin
MISO = slave_tx_data[7];
end
end
// 2. Shift and drive subsequent bits on falling edge of SCLK
always @(negedge SCLK) begin
slave_tx_data = {slave_tx_data[6:0], 1'b0};
MISO = slave_tx_data[7];
end
// 3. Sample MOSI from master on rising edge of SCLK
always @(posedge SCLK) begin
slave_rx_data = {slave_rx_data[6:0], MOSI};
end
// Main Stimulus
initial begin
// Setup waveform dumping for simulation (e.g., in Icarus/Vivado)
$dumpfile("spi_master_tb.vcd");
$dumpvars(0, tb_spi_master);
// Initialize signals
clk = 0;
reset = 1;
start = 0;
data_in = 8'h00;
MISO = 1'bz;
slave_tx_data = 8'h00;
slave_rx_data = 8'h00;
// Apply Hard Reset
#100;
reset = 0;
#100;
$display("--- Starting SPI Master Verification ---");
// TEST 1: Standard Single Byte Transfer
$display("[TEST 1] Standard Single Transfer (Master: 0xC3, Slave: 0x5A)");
slave_tx_data = 8'h5A;
data_in = 8'hC3;
@(posedge clk);
start = 1;
@(posedge clk);
start = 0; // Pulse start
// Wait for CS to drop, then wait for it to finish
wait(CS == 0);
wait(CS == 1);
#100;
if (data_out == 8'h5A && slave_rx_data == 8'hC3)
$display(" -> PASS");
else
$display(" -> FAIL: Mismatch in expected data.");
// TEST 2: Back-to-Back Transfers (Start held high)
$display("[TEST 2] Back-to-Back Transfers (Testing if CS pulses cleanly)");
slave_tx_data = 8'h81; // Queue slave byte 1
data_in = 8'h18; // Queue master byte 1
@(posedge clk);
start = 1; // Hold start HIGH indefinitely
wait(CS == 0); // Transfer 1 begins
wait(CS == 1); // Transfer 1 ends
// As soon as CS goes high, instantly queue the next byte
slave_tx_data = 8'h24;
data_in = 8'h42;
wait(CS == 0); // Transfer 2 begins
wait(CS == 1); // Transfer 2 ends
@(posedge clk);
start = 0; // Finally release start
#100;
$display(" -> COMPLETED: Inspect waveforms to ensure CS went high between bytes.");
// TEST 3: Mid-Flight Reset Simulation
$display("[TEST 3] Mid-Flight Reset Simulation");
slave_tx_data = 8'hFF;
data_in = 8'hEE;
@(posedge clk);
start = 1;
@(posedge clk);
start = 0;
// Wait ~4 microseconds (middle of the SPI transfer), then hit reset
#4000;
reset = 1;
#50;
reset = 0;
#1000;
if (CS == 1 && SCLK == 0 && MOSI == 0)
$display(" -> PASS: Bus safely aborted and returned to idle state.");
else
$display(" -> FAIL: Bus did not recover properly from mid-flight reset.");
// TEST 4: Boundary Values (All Zeros / All Ones)
$display("[TEST 4] Boundary Data (0x00 and 0xFF)");
slave_tx_data = 8'h00; data_in = 8'h00;
@(posedge clk); start = 1; @(posedge clk); start = 0;
wait(CS == 1); #100;
slave_tx_data = 8'hFF; data_in = 8'hFF;
@(posedge clk); start = 1; @(posedge clk); start = 0;
wait(CS == 1); #100;
$display(" -> COMPLETED: Boundary Data.");
$display("--- Verification Finished ---");
$finish;
end
endmodule