内容
例化和复位与时钟信号的产生都是老生常谈,主要看task的产生和调用,与结果的检验。
task
//==========================================
//driver task
task spi_cmd ;
input [15:0] data_send ;
begin
wait(ready) ;
@(posedge clk_200mhz) ;
# 0.7 ;
tx_data = data_send ;
tx_data_en = 1'b1 ;
@(posedge clk_200mhz) ;
# 0.7 ;
tx_data_en = 1'b0 ;
tx_data = 'b0 ;
wait(ready) ;
end
endtask // spi_rw
定义了他上课,名字为spi_cmd
带输入参数,写在begin前
wait表示等待ready为高电平
@(posedge clk_200mhz) ;
等待时钟的上升沿
#0.7 ; 模拟时钟延迟
发送开始信号和相应数据
等待下一个时钟沿后发送结束信号
最后的等待ready高电平没有看懂,可能是为了健壮性
最后endtask结束
中间的begin和end大胆猜测,不要也罢
//driver
initial begin
tx_data = 16'b0 ;
tx_data_en = 1'b0 ;
//(1) wr address: 100-102
#133.7 ; spi_cmd({1'b1, 7'd100, 8'hAA}) ;
#501.3 ; spi_cmd({1'b1, 7'd101, 8'h55}) ;
#501.3 ; spi_cmd({1'b1, 7'd102, 8'hA5}) ;
//(2) rd address: 102-100
#2001.3 ; spi_cmd({1'b0, 7'd102, 8'h0}) ;
#501.3 ; spi_cmd({1'b0, 7'd101, 8'h0}) ;
#501.3 ; spi_cmd({1'b0, 7'd100, 8'h0}) ;
end
调用task
tx两行是为了赋初值
task的调用格式类似与c语言中的带参函数
#时间后面的分号可加可不加
结果校验
//==========================================
//finish
reg err_flag ;
initial begin
err_flag = 0 ;
#100;
//1st read
@(posedge rdata_valid) ;
@(negedge clk_200mhz) ;
if (rdata != 8'ha5) err_flag |= 1;
//2nd read
@(posedge rdata_valid) ;
@(negedge clk_200mhz) ;
if (rdata != 8'h55) err_flag |= 1;
//3rd 3read
@(posedge rdata_valid) ;
@(negedge clk_200mhz) ;
if (rdata != 8'haa) err_flag |= 1;
#13.7 ;
$display("-------------------------");
if (err_flag !== 0) begin
$display("Simulation Failed!");
end
else begin
$display("Simulation Succeed!");
end
$display();
$display();
#1000 ;
$finish ;
end
定义错误标志并赋初值
等待有效信号标志
等待时钟边沿==(不知道为啥用下降沿)==
判断数据是否与输入数据一致
重复操作
下半部分为输出
源码
`timescale 1ns/1ps
module test ;
reg clk_200mhz ;
reg rstn ;
reg [15:0] tx_data ;
reg tx_data_en ;
wire sclk, csn, mosi, miso ;
wire [7:0] rdata ;
wire rdata_valid ;
wire ready ;
//==========================================
// clk and reset
initial begin
clk_200mhz = 0 ;
rstn = 0 ;
#11.3 rstn = 1 ;
end
always #(2.5) clk_200mhz = ~clk_200mhz ;
//==========================================
//driver task
task spi_cmd ;
input [15:0] data_send ;
begin
wait(ready) ;
@(posedge clk_200mhz) ;
# 0.7 ;
tx_data = data_send ;
tx_data_en = 1'b1 ;
@(posedge clk_200mhz) ;
# 0.7 ;
tx_data_en = 1'b0 ;
tx_data = 'b0 ;
wait(ready) ;
end
endtask // spi_rw
//==========================================
//driver
initial begin
tx_data = 16'b0 ;
tx_data_en = 1'b0 ;
//(1) wr address: 100-102
#133.7 ; spi_cmd({1'b1, 7'd100, 8'hAA}) ;
#501.3 ; spi_cmd({1'b1, 7'd101, 8'h55}) ;
#501.3 ; spi_cmd({1'b1, 7'd102, 8'hA5}) ;
//(2) rd address: 102-100
#2001.3 ; spi_cmd({1'b0, 7'd102, 8'h0}) ;
#501.3 ; spi_cmd({1'b0, 7'd101, 8'h0}) ;
#501.3 ; spi_cmd({1'b0, 7'd100, 8'h0}) ;
end
//finish
reg err_flag ;
initial begin
err_flag = 0 ;
#100;
//1st read
@(posedge rdata_valid) ;
@(negedge clk_200mhz) ;
if (rdata != 8'ha5) err_flag |= 1;
//2nd read
@(posedge rdata_valid) ;
@(negedge clk_200mhz) ;
if (rdata != 8'h55) err_flag |= 1;
//3rd 3read
@(posedge rdata_valid) ;
@(negedge clk_200mhz) ;
if (rdata != 8'haa) err_flag |= 1;
#13.7 ;
$display("-------------------------");
if (err_flag !== 0) begin
$display("Simulation Failed!");
end
else begin
$display("Simulation Succeed!");
end
$display();
$display();
#1000 ;
$finish ;
end
spi_master u_spi_master (
.rstn (rstn),
.clk (clk_200mhz),
//parallel
.tx_data (tx_data),
.tx_data_en (tx_data_en),
.ready (ready),
//spi intf
.sclk (sclk),
.csn (csn),
.mosi (mosi),
.miso (miso),
.rdata (rdata),
.rdata_valid (rdata_valid)
);
spi_slave u_spi_slave (
.sclk (sclk),
.csn (csn),
.mosi (mosi),
.miso (miso));
endmodule