MCU与液晶控制模块通讯仿真
0赞做一个CPLD液晶控制模块,其中CPLD与MCU的通信协议如下:
x_cnt[1..640]:ADDR[9..0] VGA显示行坐标 //对应SRAM的ADDR[9..0]
y_cnt[1..480]:ADDR[8..0] VGA显示列坐标 //对应SRAM的ADDR[18..10]
MCU和CPLD接口:
CS: CPLD片选
RS: RS=0写命令,RS=1写数据
RD: RD=0,写选通
WR:WR=0,读选通
DB[7..0]: 数据总线(写入数据时低3bit有效)
8bit命令寄存器CMD_REG使用说明:
CMD_REG[2..0] =000:写入x坐标地址addr[7:0]
=001:写入x坐标地址addr[9:8]
=010:写入y坐标地址addr[7:0]
=011:写入y坐标地址addr[8]
=100:写入显示数据,x坐标、y坐标地址不变
=101:写入显示数据,x坐标地址增1,y坐标地址不变
(当x坐标写满,回到1地址,同时y坐标地址自动加1)
=110:写入显示数据,y坐标地址增1,x坐标地址不变
(y坐标地址写满后,需要软件送地址复位)
CMD_REG[3] =1:开显示
=0:关显示
CMD_REG[7..4] 保留
现在要做一个仿真实验,看看CPLD的设计是否符合要求,到达预定目的。Testbench的设计即仿真模块分为三个部分:
//时钟复位部分//这个部分产生时钟源,以及上电的复位模拟
//模拟激励部分//这个部分产生激励信号,模拟MCU向CPLD发送命令/地址/数据
//自动验证部分//这个部分时产生(自动)验证机制,对通信的结果进行验证
时钟复位如下代码实现:
initial begin
rst_n = 0;//复位
#100;
rst_n = 1;//复位结束
end
initial begin
clk = 0;
forever
#10 clk = ~clk; //产生20ns的时钟信号
End
模拟激励部分:
实现功能如下:
- 写入x坐标地址为1,y坐标地址为1
- 在写入地址后x,y地址不自增模式下连续写入0,1,2,3,4四个数据
- 在写入地址后x地址自增,y地址不自增模式下连续写入0,1,2,3,4四个数据
- 在写入地址后x地址不自增,y地址自增模式下连续写入0,1,2,3,4四个数据
自动验证部分:
1、观察波形(不能算做自动验证,比较常规的观察方法,在大模块的设计中时无法进行RTL设计仿真验证)
2、使用如下代码:
initial begin
$monitor($time,," sram_wr_data=%d, x_addr=%d, y_addr=%d",
sram_wr_data,sram_wr_addr[9:0],sram_wr_addr[18:10]);
end
只要sram_wr_data,sram_wr_addr[9:0],sram_wr_addr[18:10]三个数据的任意一个发生变化,modelsim的命令窗口就会更新一次数据。
在modelsim命令窗口观察到如下数据:
# 0 sram_wr_data=x, x_addr= x, y_addr= x
run -all
# 1270 sram_wr_data=x, x_addr= X, y_addr= x
# 2470 sram_wr_data=x, x_addr= 1, y_addr= x
# 3670 sram_wr_data=x, x_addr= 1, y_addr= X
# 4870 sram_wr_data=x, x_addr= 1, y_addr= 1
# 6070 sram_wr_data=0, x_addr= 1, y_addr= 1
# 6670 sram_wr_data=1, x_addr= 1, y_addr= 1
# 7270 sram_wr_data=2, x_addr= 1, y_addr= 1
# 7870 sram_wr_data=3, x_addr= 1, y_addr= 1
# 8470 sram_wr_data=4, x_addr= 1, y_addr= 1
# 9670 sram_wr_data=0, x_addr= 1, y_addr= 1
# 9710 sram_wr_data=0, x_addr= 2, y_addr= 1
# 10270 sram_wr_data=1, x_addr= 2, y_addr= 1
# 10310 sram_wr_data=1, x_addr= 3, y_addr= 1
# 10870 sram_wr_data=2, x_addr= 3, y_addr= 1
# 10910 sram_wr_data=2, x_addr= 4, y_addr= 1
# 11470 sram_wr_data=3, x_addr= 4, y_addr= 1
# 11510 sram_wr_data=3, x_addr= 5, y_addr= 1
# 12070 sram_wr_data=4, x_addr= 5, y_addr= 1
# 12110 sram_wr_data=4, x_addr= 6, y_addr= 1
# 13270 sram_wr_data=0, x_addr= 6, y_addr= 1
# 13310 sram_wr_data=0, x_addr= 6, y_addr= 2
# 13870 sram_wr_data=1, x_addr= 6, y_addr= 2
# 13910 sram_wr_data=1, x_addr= 6, y_addr= 3
# 14470 sram_wr_data=2, x_addr= 6, y_addr= 3
# 14510 sram_wr_data=2, x_addr= 6, y_addr= 4
# 15070 sram_wr_data=3, x_addr= 6, y_addr= 4
# 15110 sram_wr_data=3, x_addr= 6, y_addr= 5
# 15670 sram_wr_data=4, x_addr= 6, y_addr= 5
# 15710 sram_wr_data=4, x_addr= 6, y_addr= 6
# Break key hit
$time是时间命令,就是#后的第一列为仿真的绝对时间,单位ns,后面是仿真过程中的数据变化。
上面的两种验证方法还不是做到真正意义上的自动验证。因为这个模块比较简单,所以做到这个程度已经能够很好了验证了RTL设计的正确性。如果更大的系统模块,应该时准备好一组正确数据和经过RTL代码的输出数据比较,然后在屏幕直接送出是否出错的提示就可以了。