本篇作为学习verilog过程中一个动手编码的尝试,主要从网上找的基础代码再加上自己的一些修改。一来可以加深对verilog语法的了解,二来也有助于有硬件有更深入的了解
module spi_slave(miso, clk, ss, mosi);
reg [7:0] tx;
reg [7:0] rx;
reg [3:0] cnt;
reg rwflag; //0 read , 1 write
output miso;
input clk, ss, mosi;
initial
begin
//tx = 8'b0100_1111;
rx = 0;
cnt = 0;
rwflag = 0;
end
assign miso = rx[0];
always @(posedge clk)
begin
$display("spi_slave cnt=%d, ss=%b mosi=%b miso=%b", cnt, ss, mosi, miso);
if (!ss) begin
if (cnt < 8 && !rwflag) begin
rx[cnt] <= mosi;
cnt <= cnt + 1;
end else begin
$display("xxxxxxxxx");
rwflag <= 1;
if (cnt >= 0) begin
rx <= rx >> 1;
cnt <= cnt - 1;
end
end
end else begin
$display("higt ss");
rwflag = 0;
cnt = 0;
rx = 8'b0000_0000;
end
end
endmodule
module stimulus;
wire miso;
reg clk, ss;
reg [7:0] mosi;
reg cin;
integer cnt;
spi_slave spi0(miso, clk, ss, cin);
initial
begin
clk = 0;
ss =1;
mosi = 8'b0110_1010;
cnt = 8;
cin = 0;
end
initial
begin
ss = 0;
#600 ss = 1;
end
initial
begin
$monitor($time, "stimulus cin=%b, miso=%b mosi=%b, cnt=%d",cin, miso, mosi, cnt);
end
always #20
begin
clk = ~clk;
if (cnt > 0 && clk)
begin
cin <= mosi[0];
mosi <= mosi >> 1;
cnt <= cnt - 1;
end
end
endmodule
上述代码比较简单,主要有两个module。一个spi回环模拟模块,一个激励模块。
- spi_slave模块模拟spi协议。当ss被拉低时,代表主机选择与本从机通信。clk由主机提供,在clk上升延的时候,进行数据的读取和发送
- stimulus作为激励模块,来验证slave模块是否达到目地
- 下图是用modelsim进行仿真验证输出的结果


上述cin是输入,miso是输出。可以看到输入与输出的数据波形是一样的数据都是0100110