`timescale 1ns / 1ps
module master_spi_tb;
localparam BYTES = 8; localparam TCNT = BYTES*8*2-1;
localparam CPOL = 1; localparam CPHA = 1;
reg I_clk; //系统时钟 reg [7:0] i;//计数器,用于产生SPI时钟数量 reg I_rstn; //系统复位 reg I_spi_clk;//SPI时钟 reg I_spi_ss; //SPI的Slave选通信号 reg [3:0]bit_cnt; //bit计数器 reg [7:0]spi_tx_buf; //发送缓存(移位寄存器) reg [7:0]spi_tx_buf_r; //发送化缓存,用于产生测试数据 reg first_data_flag; //是否一个时钟改变数据
wire O_spi_rvalid; //SPI 数据接收有效,当该信号有效代表接收到一个有效数据 wire [7:0]O_spi_rdata; //SPI读数据 wire I_spi_rx;//SPI数据总线
//tb模拟的SPI测试数据接到I_spi_rx assign I_spi_rx = spi_tx_buf[7]; //例化SPI 接收模块 uispi_rx# ( .BITS_LEN(8), .CPOL(CPOL), .CPHA(CPHA) ) I_spi_rxnst( .I_clk(I_clk), .I_rstn(I_rstn), .I_spi_clk(I_spi_clk), .I_spi_rx(I_spi_rx), .I_spi_ss(I_spi_ss), .O_spi_rvalid(O_spi_rvalid), .O_spi_rdata(O_spi_rdata) ); initial begin I_clk = 1'b0; I_rstn = 1'b0; #100; I_rstn = 1'b1; end
always #10 I_clk = ~I_clk; //时钟信号翻转,产生系统时钟
initial begin #100; i = 0;
forever begin I_spi_clk = CPOL; //设置时钟极性 I_spi_ss = 1; // 设置SPI的SS控制信号 #2000; I_spi_ss = 0; for(i=0;i<TCNT;i=i+1) #1000 I_spi_clk = ~ I_spi_clk; //产生SPI时钟 #2000; I_spi_ss = 1;
end end
initial begin #100; bit_cnt = 0; first_data_flag =0; spi_tx_buf[7:0] = 8'ha0; spi_tx_buf_r[7:0] = 8'ha0; forever begin
//spi ss 控件用于启用传输 wait(I_spi_ss);//spi ss bit_cnt = 0; spi_tx_buf[7:0] = 8'ha0; spi_tx_buf_r[7:0] = 8'ha0;
if((CPHA == 1 && CPOL ==0)||(CPHA == 1 && CPOL ==1))//第一个时钟沿改变数据的情况 first_data_flag = 1; //设置first_data_flag=1 下面的发送时序对应情况跳过第一个沿
//ss低时开始数据传输 wait(!I_spi_ss);
while(!I_spi_ss)begin
//COPL=0 CPHA=0默认SCLK为低电平,对于发送方,在对于第1个bit数据提前放到总线 if(CPHA == 0 && CPOL ==0)begin @(negedge I_spi_clk) begin //每个时钟的下降沿更新需要发送的BIT if(bit_cnt == 7)begin//连续发送过程中,8bits 发送完毕后更新数据 bit_cnt = 0; spi_tx_buf_r = spi_tx_buf_r + 1'b1;//产生新的测试数据 spi_tx_buf = spi_tx_buf_r;//重新跟新发送寄存器 end else begin spi_tx_buf = {spi_tx_buf[6:0],1'b0};//数据移位,更新数据 bit_cnt = bit_cnt + 1'b1;//SPI发送位数计数器 end end end
//CPHA=0 COPL=1 默认SCLK为高电平,对于发送方,在对于第1个bit数据提前放到总线 if(CPHA == 0 && CPOL ==1)begin @(posedge I_spi_clk) begin //每个时钟的上升沿更新需要发送的BIT if(bit_cnt == 7)begin //连续发送过程中,8bits 发送完毕后更新数据 bit_cnt = 0; spi_tx_buf_r = spi_tx_buf_r + 1'b1;//产生新的测试数据 spi_tx_buf = spi_tx_buf_r; //重新跟新发送寄存器 end else begin spi_tx_buf = {spi_tx_buf[6:0],1'b0};//数据移位,更新数据 bit_cnt = bit_cnt + 1'b1;//SPI发送位数计数器 end end end
//CPHA=1 COPL=0 默认SCLK为低电平,对于发送方,在第1个SCLK的跳变沿更新 if(CPHA == 1 && CPOL ==0)begin @(posedge I_spi_clk) begin if(first_data_flag == 1'b1)begin //第一个时钟沿,由于前面已经提前初始化第一个需要发送的数据,因此,这里跳过第一个跳变沿沿 first_data_flag = 0; //spi_tx_buf[7:0] = 8'ha0;//也可以在第一个跳变沿初始化第一个发送的数据 end else begin if(bit_cnt == 7)begin bit_cnt = 0; spi_tx_buf_r = spi_tx_buf_r + 1'b1;//产生新的测试数据 spi_tx_buf = spi_tx_buf_r;//重新跟新发送寄存器 end else begin spi_tx_buf = {spi_tx_buf[6:0],1'b0}; //数据移位,更新数据 bit_cnt = bit_cnt + 1'b1;//SPI发送位数计数器 end end end end //CPHA=1 COPL=1 默认SCLK为高电平,对于发送方,在第1个SCLK的跳变沿更新 if(CPHA == 1 && CPOL ==1)begin @(negedge I_spi_clk) begin if(first_data_flag == 1'b1)begin //第一个时钟沿,由于前面已经提前初始化第一个需要发送的数据,因此,这里跳过第一个跳变沿沿 first_data_flag = 0; //spi_tx_buf[7:0] = 8'ha0;//也可以在第一个跳变沿初始化第一个发送的数据 end else begin if(bit_cnt == 7)begin bit_cnt = 0; spi_tx_buf_r = spi_tx_buf_r + 1'b1;//产生新的测试数据 spi_tx_buf = spi_tx_buf_r;//重新跟新发送寄存器 end else begin spi_tx_buf = {spi_tx_buf[6:0],1'b0};//数据移位,更新数据 bit_cnt = bit_cnt + 1'b1;//SPI发送位数计数器 end end end end
end end end
endmodule
|