框架详解_UART项目详解 08仿真框架

点 击 关 注 上 方"两猿社

设 为"置 顶 或 星 标",干 货 第 一 时 间 送 达。

c71f2739d7f27cfa61c6e39b23d2ce1c.png

IC 猿 | 两 猿 社

简介

前面的文章已经说完了设计部分,从本篇文章开始分析仿真部分代码。本文主要对UART整体的仿真方法和testbench结构进行讲解。

仿真框架

仿真部分结构和设计类似,同样有波特率、接收数据和发送数据模型。仿真的实现比较灵活,不用考虑可综合性。主要实现master功能,配置部分对DUT配置,发送模型发送数据到DUT,接收模型接收到数据后与发送数据进行对比,验证基本功能的正确性。

de2542382520d5408f682142cbd67116.png
仿真框架

伤真顶层产生时钟、复位,信号的初始化,测试用例的选择以及全局变量或参数的定义(如寄存器地址和某些多模块需要用到的变量)。

`timescale 1ns/1ps
//`define tc01_00
//`define tc02_00
`define tc03_00

module top();


reg clk; // ARM clk
reg clk26m; // 26M function clk
reg rst_; // ARM clk's rst_
reg rst26m_; // function clk's rst_
reg tx_data; // send data line
wire rx_data; // receive data line
wire uart_int; // uart interrupt


// APB signals
reg [3:0] paddr;
reg [31:0] pwdata;
reg psel;
reg penable;
reg pwrite;
wire [31:0] prdata;

reg baud_tclk; // send data baud clk
reg baud_rclk; // receive data baud clk
reg start; // receive data baud enable signal
reg rx_done; // receive one data done
reg w_state; // write reg using signal
reg r_state; // read reg using signal
reg [7:0] tx_data_mem[0:999]; // send data memory
reg [7:0] rx_data_mem[0:999]; // receive data memory

reg [31:0] uart_tx;
reg [31:0] uart_rx;
reg [31:0] uart_baud;
reg [31:0] uart_conf;
reg [31:0] uart_rxtrig;
reg [31:0] uart_txtrig;
reg [31:0] uart_delay;
reg [31:0] uart_status;
reg [31:0] uart_rxfifo_stat;
reg [31:0] uart_txfifo_stat;

// when tx_model is runing a second time ,we don't want tx_cnt clean,
// so defind tx_cnt in top
integer tx_cnt;

parameter clk_period = 10;
parameter clk26m_period = 38;
parameter uart_tx_addr = 4'h0;
parameter uart_rx_addr = 4'h1;
parameter uart_baud_addr = 4'h2;
parameter uart_conf_addr = 4'h3;
parameter uart_rxtrig_addr = 4'h4;
parameter uart_txtrig_addr = 4'h5;
parameter uart_delay_addr = 4'h6;
parameter uart_status_addr = 4'h7;
parameter uart_rxfifo_stat_addr = 4'h8;
parameter uart_txfifo_stat_addr = 4'h9;

`include "UART_baud.v"
`include "reg_op.v"
`include "check_int.v"
`include "uart_tx_model.v"
`include "uart_rx_model.v"
`include "tc01_00.v"
`include "tc02_00.v"
`include "tc03_00.v"

// cases of uart
UART_TOP DUT(
.clk(clk),
.clk26m(clk26m),
.rst_(rst_),
.rst26m_(rst26m_),
.paddr_i(paddr),
.pwdata_i(pwdata),
.psel_i(psel),
.penable_i(penable),
.pwrite_i(pwrite),
.urxd_i(tx_data),
.utxd_o(rx_data),
.uart_int_o(uart_int),
.prdata_o(prdata)
);

// always produce clk
always #(clk_period/2) clk = ~clk;
always #(clk26m_period/2) clk26m = ~clk26m;


// signals initialize
initial begin
clk = 1'b0;
clk26m = 1'b0;
rst_ = 1'b1;
rst26m_ = 1'b1;
baud_tclk = 1'b0;
baud_rclk = 1'b0;
tx_data = 1'b1;
start = 1'b0;
rx_done = 1'b0;
w_state = 1'b0;
r_state = 1'b0;
uart_tx = 32'h0;
uart_baud = 32'hf152;
uart_conf = 32'h34;
uart_rxtrig = 32'h1;
uart_txtrig = 32'h0;
uart_delay = 32'h2;
uart_status = 32'h0;
tx_cnt = 0;
#50;
rst_ = 1'b0;
rst26m_ = 1'b0;
#100;
rst_ = 1'b1;
rst26m_ = 1'b1;

end


initial begin
@(posedge rst_) begin end
fork
UART_baud();
check_int();
uart_rx_model();
join
end


initial begin
@(posedge rst_) begin end
`ifdef tc01_00 tc01_00(10); `endif
`ifdef tc02_00 tc02_00(); `endif
`ifdef tc03_00 tc03_00(); `endif
end

endmodule

注意:每一个寄存器复位时都应该具有复位值,每一个输入在仿真时都应该具有初始值,确保功能的正确性以及仿真能顺利进行。

对于初学者或者常使用gui仿真的同学需要了解,在include task或者function等模型时,可以直接使用

`include "userfile.v"
或者
`include "D:/userdir/userfile.v"

两者不同之处在于前者需要指定一个include directory,这个目录包含需要inclue的文件;而后者使用绝对路径更加直接,但是在你的仿真环境需要移植或者include的文件比较多且分散时,使用第一种方式更为方便。

仿真顶层主要是将各个模型与DUT串接,形成串口的配置、收发数据通路。另外通过控制不同的仿真用例测试不同配置下的功能正确性。

testcase说明

所有的测试用例使用伪随机的方式进行,即数据和配置信息使用系统随机函数产生。

tc01_00:  对DUT接收部分的功能验证。随机配置波特率和串口功能设置,收发FIFO触发值为32'ha。控制发送数据模型发送数据到DUT,发送次数通过task input可控(10的倍数)。设计中达到RX FIFO触发值时,会触发中断,check int模块会一直工作检查处理中断,进行数据对比。

task  tc01_00;
input integer run_num;

reg [9:0] baud;
reg [2:0] conf;
reg [15:0] rdata;
integer i;
integer run_time;
integer seed;

run_time = 0;
seed = 0;
// memory initialize
for(i=0;i<1000;i++) begin
top.tx_data_mem[i] = {$random} % 255; //$dist_uniform(seed,5,255);
end
repeat(run_num) begin
baud = $dist_uniform(seed,13,676);
conf = {$random} % 7; //$dist_uniform(seed,0,7);
@(posedge top.clk) begin end
write_reg(top.uart_baud_addr,{20'hf,2'b0,baud});
@(posedge top.clk) begin end
write_reg(top.uart_txtrig_addr,32'ha);
@(posedge top.clk) begin end
write_reg(top.uart_rxtrig_addr,32'ha);
@(posedge top.clk) begin end
write_reg(top.uart_conf_addr,{26'h0,3'b111,conf});

uart_tx_model(10);

$display("------run -------%d ",run_time);
run_time++;
seed++;
end
$stop;
endtask

tc02_00:  对DUT发送部分的功能验证。随机配置波特率、功能、delay和收发FIFO触发值。寄存器配完后,配置串口发送寄存器,使DUT发送数据(重复1000次),将接收模型收到的数据与发送的数据对比,验证功能正确性。

task  tc02_00;

reg [9:0] baud;
reg [2:0] conf;
reg [3:0] delay;
reg [3:0] rxtrig;
reg [3:0] txtrig;

integer i;
integer j;
integer seed;

seed = 0;
j = 0;
// memory initialize
for(i=0;i<1000;i++) begin
top.tx_data_mem[i] = $dist_uniform(seed,5,255);
end

begin
baud = $dist_uniform(seed,13,676);
conf = $dist_uniform(seed,0,7);
delay = $dist_uniform(seed,0,15);
rxtrig = $dist_uniform(seed,4,14);
txtrig = $dist_uniform(seed,4,14);
write_reg(top.uart_baud_addr,{20'hf,2'b0,baud});
@(posedge top.clk) begin end
write_reg(top.uart_txtrig_addr,{28'h0,txtrig});
@(posedge top.clk) begin end
write_reg(top.uart_rxtrig_addr,{28'h0,rxtrig});
@(posedge top.clk) begin end
write_reg(top.uart_conf_addr,{26'h0,3'b111,conf});
@(posedge top.clk) begin end
write_reg(top.uart_delay_addr,{28'h0,delay});
repeat(16) begin
@(posedge top.clk) begin end
write_reg(top.uart_tx_addr,top.tx_data_mem[j]);
j++;
if(j > 999) begin
j = 0;
end
$display("write %d data",j);
end
seed++;
end
endtask

tc03_00:  DUT收发测试。随机配置波特率、功能、delay和收发FIFO触发值。寄存器完后,配置串口发送寄存器,使DUT发送数据(重复1000次);再使用发送数据模型发送数据1000次。

task  tc03_00;

reg [9:0] baud;
reg [2:0] conf;
reg [3:0] delay;
reg [3:0] rxtrig;
reg [3:0] txtrig;

integer i;
integer j;
integer seed;


seed = 0;
j = 0;
// memory initialize
for(i=0;i<1000;i++) begin
top.tx_data_mem[i] = $dist_uniform(seed,1,255);
end

begin
baud = $dist_uniform(seed,13,676);
conf = $dist_uniform(seed,0,7);
delay = $dist_uniform(seed,0,15);
rxtrig = $dist_uniform(seed,4,14);
txtrig = $dist_uniform(seed,4,14);
write_reg(top.uart_baud_addr,{20'hf,2'b0,baud});
@(posedge top.clk) begin end
write_reg(top.uart_txtrig_addr,{28'h0,txtrig});
@(posedge top.clk) begin end
write_reg(top.uart_rxtrig_addr,{28'h0,rxtrig});
@(posedge top.clk) begin end
write_reg(top.uart_conf_addr,{26'h0,3'b111,conf});
@(posedge top.clk) begin end
write_reg(top.uart_delay_addr,{28'h0,delay});
fork
repeat(16) begin
@(posedge top.clk) begin end
write_reg(top.uart_tx_addr,top.tx_data_mem[j]);
j++;
if(j > 999) begin
j = 0;
end
$display("write %d data",j);
end
uart_tx_model(1000);
join
seed++;
end
endtask

本设计只使用了三个测试用例,对模块的仿真验证并不完备,读者可以根据自己的使用情况增加不同功能的用例。

92cc305aa73542609229bf639c94404b.png

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值