Adolph-ChipDebug
商品列表
7年前

【Modelsim常见问题】TestBench中端口reg和wire定义解惑

TestBench中端口reg和wire定义解惑

很多学员在学习TestBench的编写的时候,容易死记概念,最典型的就是,被测试模块的输入端口在测试文件中要定义成reg,输出端口要定义为wire。
例如,最典型的这种写法,大家都能看得懂。


reg clk;
initial clk = 0;
always #10 clk = ~clk;

led_run led_run
(
    .clk50(clk),
    .led(led)
);

那我现在换一种写法,我定义一个中间信号,名叫clkin,然后按照下述方法写:


reg clk;
initial clk = 0;
always #10 clk = ~clk;

wire clkin;

assign clkin = clk;

led_run led_run
(
    .clk50(clkin),
    .led(led)
);

这个时候,被测试模块的输入端口就链接到了clkin这个被定义为wire型的信号上,是不是就与我们所说的基本规律相违背了呢?

这个实际就是看你有没有真正理解激励信号的意义,使用reg定义激励信号,然后我们可以通过对reg信号在不同的时候赋予不同的值来产生激励。如果使用reg信号定义的信号名称和你的被测试模块的端口在测试文件中的命名一样,就可以默认连接上,第一种写法就是这种形式。在第二种写法中,增加了一个中间信号,这个信号是个wire型的,一端连接到了reg型的clk这个信号上,另一端连接到了被测试模块的clk50输入端口。实质上等同于直接将reg型的clk信号直接连接到被测试模块的clk50上,所以并没有冲突。

为什么我在最开始讲测试文件的编写时候要重点使用示波器和信号发生器来类比,就是希望大家真正理解这些信号的实质。

【Modelsim常见问题】Port ‘xxxx’ not found in the connected module

[图片]

这个报错很明显,是说你在例化的时候,被例化的模块中有个信号并不存在于真正的模块设计中,例如,用户编写一个二选一多路器模块,模块端口如下表左侧所示,但是在testbench或上层模块例化使用该模块时,例化内容如下表右侧所示:

[图片]

可以看到,例化时候,用了一个叫sel的端口,但是实际被例化的模块中并没有sel这个端口,因此就会报上述错误。根据此思路对应检查设计模块的代码即可。

8年前

也贴一个我当年的做的FPGA+SDRAM设计吧。当年这个设计还有一点经济价值,现在应该没有了,代码写得太烂,有需要的可以私信我。


先看看两张效果图吧,手机拍摄效果差于实际效果

[图片]
[图片]

看看NES游戏的《坦克世界》,^_^

[图片]
[图片]
[图片]

项目背景及开发目的

目前市面上各种TFT显示专用控制器价格相对较为高昂,且存在以下缺点:

  • 通常TFT控制芯片成本在 22~33 RMB区间。
  • 支持的显示分辨率通常在800*480以内,而在分辨率为800*480时能刷新率却不能满足要求(<24fps/s),有闪烁感。
  • 支持的显存容量有限,如通常为一页或两页显存,不利于进行较为高级的UI混合渲染。
  • 支持的外部存储容量有限,在显示界面较多时存储不了所需的UI图片资源。
  • 通常只支持HV模式、DE模式,而不支持高分辨率TFT屏所带的LVDS、MIPI接口。
  • 各TFT控制芯片的接口和寄存器互异,配置寄存器繁多,操作繁复。
  • 部分TFT控制芯片开发资料少,规格书内容不详细,开发需要厂商FAE支持,而厂商FAE支持力度不太到位。
  • 部分TFT控制芯片标称的技术性能指标与实际值不一致,导致项目临时换方案。

由于以上这些原因,为了满足我司TFT相关产品的不同需求,工程师选取了多种TFT控制器方案,这不利于技术复用和维护,直接增加了开发工程师和测试工程师的工作量,同时还在一定程度上增加了项目的开发风险。
本设计的目的就在于实现成本控制和技术指标设计两方面的灵活性,增强技术的复用,降低开发难度,简化设计和维护成本,降低开发工程师和测试工程师的工作量,同时减少项目风险。

项目需求及设计指标

  • 样品成本在20 RMB左右,批量成本 15RMB 以下。
  • 分辨率支持 1024*768及以下。
  • 支持16bit、24bit真彩色。
  • 支持多页缓存(对于800*480分辨率支持8页),显示页和读写页互相独立。
  • 用户读写最大带宽50M*16bit(或50M*24bit)
  • 16bit\24bit位宽的8080或6800并行接口。
  • 支持HV、DE模式,同时可扩展支持VGA、LVDS、MIPI DSI接口。
  • 支持0~16(或更高)级分辨率的背光控制。
  • 支持画面水平和垂直显示镜像
  • 支持指定区域突发读写,即只需要指定一次操作矩形区,X、Y坐标即可自动增长,无需重复发送坐标位置。

项目方案选型(参考了ZLG的相关文档)

1. 基于CPLD + SRAM的方案。

该方案采用性价比较高的CPLD(如EMP240、A3P030 nano)和SRAM来实现,不仅成本低,而且灵活性非常大,实现的功能丰富,由于采用性价比较低的SRAM,容量有限,适合于低分辨率的TFT屏显示。

[图片]

功能特点:

  1. 采用altera的EPM240或Microsemi小容量的A3P030以及SRAM来实现,具有成本低的特点。
  2. 开发方案简单,工程量小,技术难度低。
  3. 接口非常灵活,根据不同的需要可以定制8080并行总线接口、6800并行总线接口等。
  4. 并行总线接口的速度最高可达25MHz左右,相当于480×272分辨率的TFT在1秒钟内可以更新191副图片。
  5. 支持双缓存的操作,两个缓存都可进行读写的操作。
  6. 支持定点和区域更新内容。
  7. 支持16位色480×272以及以下分辨率的TFT显示屏,刷新率在60Hz以上。
  8. 显示数据来源于MCU,数据可以存放于外部的串行或并行的Flash,可以存放图片、汉字库等,容量大小由用户自行控制。

缺点:由于SRAM成本较高,在高分辨率时整体硬件成本会明显增加

2. 基于FPGA + SDRAM的方案

该方案采用Lattice LCMXO2-1200(或Microsemi的A3P060)和SDRAM的方式实现,同样成本低,由于Microsemi资源较为丰富,并且内部带有PLL,所以可以实现高分率的TFT显示,最高可达1024×768。

[图片]

功能特点:

  1. 采用Lattice的Lattice LCMXO2-1200(或Microsemi的A3P060)以及SDRAM来实现,具有成本低的特点。
  2. 接口非常灵活,根据不同的需要可以定制8080并行总线接口、6800并行总线接口等。
  3. 并行总线接口的速度最高可达50MHz左右,相当于800×600分辨率的TFT在1秒钟内可以更新100副图片
  4. 支持8页缓存(可采用更大容量的SDRAM来实现更多的缓存页)的操作,8个缓存都可进行读写的操作。
  5. 支持定点和区域更新内容
  6. 支持16位色1024×768以及以下分辨率的TFT显示屏,刷新率在60Hz以上
  7. 显示数据来源于MCU,数据可以存放于外部的串行或并行的Flash,可以存放图片、汉字库等,容量大小由用户自行控制。

缺点:SDRAM存储器由于其自身特性时序相对较为复制,开发技术难度大

控制器总体设计

TFT控制器接口设计及PIN定义说明

[图片]

TFT控制器的电气符号如上图,该接口各个PIN定义如下:
clk —— 输入,控制器时钟,频率10M

nRst —— 输入,控制器外部复位,低电平有效

dataUsr[15..0] —— 三态双向IO,8080总线数据线

cs —— 输入,8080总线片选,低电平有效

rs —— 输入,8080总线寄存器地址与寄存器数据选择,rs为低表示数据线上呈现的是寄存器地址,rs为高表示数据线上呈现的是寄存器数据

wr —— 输入,8080总线写使能,低电平有效

rd —— 输入, 8080总线读使能,低电平有效

clkTft —— 输出,TFT模组的时钟

vs —— 输出,TFT模组的场信号

hs —— 输出,TFT模组的行信号

de —— 输出,TFT模组的时钟信号

rDataTft[4..0] —— 输出,TFT模组的R通道信号,5位

gDataTft[5..0] —— 输出, TFT模组的G通信信号,6位

bDataTft[4..0] —— 输出, TFT模组的B通信信号,5位

lrTft —— 输出,TFT模组水平扫描方向信号

udTft —— 输出,TFT模组垂直扫描方向信号

modeTft —— 输出,TFT模组行场模式、DE模式选择信号

ledTft —— 输出,TFT模组背光PWM控制信号

clkSdr —— 输出,SDRAM时钟信号

ckeSdr —— 输出, SDRAM时钟使能信号

nCsSdr —— 输出,SDRAM片选信号

nCasSdr —— 输出,SDRAM列地址有效信号

nRasSdr —— 输出, SDRAM行地址有效信号

dqmSdr[1..0] —— 输出,SDRAM掩码信号

baSdr[1..0] —— 输出,SDRAM的BANK地址信号

addrSdr[12..00] —— 输出,SDRAM的地址线

dataSdr[15..0] —— 三态双向IO,SDRAM的数据线

###控制器总体设计框图

整体设计框图如下,图中各模块功能分别如为:

  • MCU_FPGA总线接口模块——实现用户数据的同步和用户命令的解析。
  • SDRAM控制器——实现SDRAM的初始化、自动刷新,自动预充电,数据读写操作相关时序。
  • TFT_CTRL控制核心模块——实现用户读写SDRAM、TFT时序控制器读取SDRAM的协同,对SDRAM的总带宽进行分配。
  • TFT时序控制器——实现TFT显示模组的行场或DE同步刷新时序,并将显示数据呈现到TFT显示模组上。
  • TFT背光PWM控制模块——实现TFT模组LED背光亮度的控制。
  • 时钟生成与系统复位控制模块——实现各个模块所需时钟的生成,以及产生稳定可靠的复位信号

[图片]

控制器模块详细设计说明

MCU_FPGA总线接口模块

[图片]

SDRAM控制器(参考了ALTERA《SDR SDRAM Controller》白皮书)

SDRAM架构框图及原理

[图片]

关于SDRAM原理详情,请参见《高手进阶,终极内存技术指南》一文。

SDRAM时序

  • SDRAM初始化时序

[图片]

在SDRAM初始化阶段,主要用于配置SDRAM的突发模式,突发顺序,潜伏期等参数。

  • SDRAM掉电模式时序

[图片]

在掉电模式下SDRAM将进入低功耗状态,但处在该模式下的时长不能超过64ms的刷新周期,否则数据将丢失。

  • SDRAM时钟挂起模式时序

[图片]

在时钟挂起模式下,将会关闭SDRAM内部的时步逻辑,SDRAM不再响应任何组合命令,SDRAM数据线上的数据也将被屏蔽。

  • SDRAM自动刷新时序

[图片]

因为SDRAM内部的BANK是电容式的,最大只能保持64ms,因此每行存储单元必须在64ms内执行一次自动刷新。

  • SDRAM自刷新模式时序

[图片]

Self Refresh。这种mode的功耗在1mA以下。在这种状态下,SDRAM芯片自己完成refresh的操作,不需要SDRAM controller的干涉(Auto refresh需要)。既然有刷新,SDRAM中的数据是自然可以保持住的。SDRAM进入self refresh后,SDRAM controller也会disable输出到SDRAM的clock,从而整体的功耗都降低下来。

  • SDRAM无自动预充电突发读时序

[图片]

上图是需要由外部控制器发送预充电命令的突发读操作。

  • SDRAM自动预充电突发读时序

[图片]

上图的读操作,不需要外部的SDRAM控制器发送预充电命令,在每个读操作结束后SDRAM内部会自动产生一个预充电操作。

  • SDRAM无自动预充电单操作读时序

[图片]

上图是需要由外部控制器发送预充电命令的Single读操作。

  • SDRAM自动预充电单操作读时序

[图片]

上图的Single读操作,不需要外部的SDRAM控制器发送预充电命令,在每个读操作结束后SDRAM内部会自动产生一个预充电操作。

  • SDRAM变换BANK读访问时序

[图片]

上图是改变BANK的读操作时序

  • SDRAM读时DQM操作时序

上图是SDRAM在进行读操作时的DQM信号的时序图

[图片]

  • SDRAM页突发读时序

[图片]

上图是SDRAM进行页突发读的操作时序,突发长度为一页。

  • SDRAM无自动预充电突发写时序

上图是需要由外部控制器发送预充电命令的突发写操作。

[图片]

  • SDRAM自动预充电突发写时序

上图的写操作,不需要外部的SDRAM控制器发送预充电命令,在每个写操作结束后SDRAM内部会自动产生一个预充电操作。

[图片]

  • SDRAM无自动预充电单操作写时序

上图是需要由外部控制器发送预充电命令的Single写操作。

[图片]

  • SDRAM自动预充电单操作写时序

上图的Single写操作,不需要外部的SDRAM控制器发送预充电命令,在每个读操作结束后SDRAM内部会自动产生一个预充电操作。

[图片]

  • SDRAM变换BANK写访问时序

[图片]

上图是改变BANK的写操作时序

  • SDRAM读时DQM操作时序

[图片]

上图是SDRAM在进行写操作时的DQM信号的时序图

  • SDRAM页突发写时序

[图片]

上图是SDRAM进行页突发写的操作时序,突发长度为一页。

SDRAM控制器接口定义

SDRAM控制器提供如下接口

[图片]

其接口PIN定义如下

[图片]

SDRAM控制器设计

[图片]

SDRAM控制器框图如上图,主要由以下三个模块构成:

  • Control Interface Module(控制接口模块)

控制接口模块对主机发出的命令解码并寄存,传送已经解码的NOP, WRITEA, READA,
REFRESH, PRECHARGE 和 LOAD_MODE 命令和 ADDR给命令模块, LOAD_REG1 和
LOAD_REG2 命令解码后, 同ADDR一起装入内部的REG1和REG2寄存器。下图给出了控制接口
模块的框图。

[图片]

控制接口模块也含有一个16位的减法计数器, 和用于给命令模块产生周期刷新命令的电路,
16位的减法计数器装入REG2中的数值, 并递减到0, 但计数器为0时, 执行REFRESH_REQ输出
给命令模块,该命令一致输出直到命令模块响应该刷新请求。收到命令模块的刷新请求后,减
法计数器重新装入REG2中的数值,重复以上过程。 REG2是一个表示SDR SDRAM控制其发出
的REFRESH(刷新)命令之间的时间间隔周期,数值等于refresh_period/clock_period 的整数。

  • Command Module(命令模块)

“命令模块” 接收“控制接口模块” 输出的已经解码的命令,和周期性输出的刷新请求,
并产生合适的命令给SDRAM器件, 模块含有一个简易的仲裁电路用于仲裁主机的命令和刷新控
制逻辑所产生的刷新请求。从刷新控制逻辑电路发出的刷新请求比主机接口的命令的优先级别
高。如果主机命令和隐含的刷新操作同时出现,仲裁电路在刷新操作完成之前就不发出
CMDACK应答。 如果主机操作在进行中, 收到了刷新命令, 刷新操作将延时到主机操作完成后
执行,下图给出了命令模块的框图。

[图片]

在仲裁电路已经接受主机命令后, 命令被送到模块的命令发生器部分, 命令模块使用3个移
位寄存器来产生命令之间的时序,一个移位寄存器用于控制ACTIVATE命令;第二个用于控制
READA or WRITEA命令发出的时间;第三个用于对命令的持续时间定时,这样仲裁其就可以
判断最近请求的操作是否已经完成。
命令模块也实现SDRAM的地址复用,地址的行部分在ACTIVATE(RAS) 命令时复用到
SDRAM输出的A[11:0], 地址的列部分在READA(CAS) 或 WRITEA命令时复用到SDRAM地址
线上,
控制模块所产生的输出信号OE用于控制数据通路模块的DATAIN 通路的三态缓冲。

  • Data Path Module(数据通路模块)

数据通路模块提供了SDRAM和主机之间的数据接口, 主机在 WRITEA 时从 DATAIN 上输入
数据,在 READA 命令时 从 DATAOUT 上取出数据。图10给出了数据通路模块的方块图,
DATAIN通路由 2段通路组成,以和对应的 CMDACK和送往SDRAM的命令的时序对齐,
DATAOUT也由2段通路构成,用于在READA 命令期间寄存SDRAM的输出数据, DATAOUT
的通路延时能够减少到1次或者不寄存,唯一的影响的是DATAIUT和CMKACK的关系会改变。

[图片]

注:在本项目设计中由于时序上的原因,该模块已被裁剪掉,但为了更好地完整说明SDRAM控制器的设计,所以仍在文档中保留了该模块的描述

TFT_CTRL控制核心模块

[图片]

核心控制器模块的主要组成部分及功能设计说明:
用户显存坐标=》SDRAM地址转换 ——完成用户像素逻辑坐标到SDRAM地址的映射,省去了用户在上位机由坐标计算SDRAM地址的麻烦。同时该功能块还用于用户写显存时X、Y坐标在指定矩形操作区内的的自动增长维护。

SDRAM带宽仲裁 ——由于SDRAM的接口并不是并行,在TFT模块从SDRAM读取数据刷新屏模式,用户的不能SDRAM进行读写操作,因此需要一个SDRAM带宽仲裁模块来对SDRAM的操作带宽进行合理分配。本设计中包含有三个FIFO模块,其中FIFO_RD_TFT是用于缓存TFT从SDRAM读取的数据,FIFO_WR_USR用于缓存用户写写和数据,FIFO_RD_USR用于缓存用户从SDRAM读取的数据。在TFT读取SDRAM数据时,若有用户往控制器写入数据,将会被缓存在FIFO_WR_USR中,在本设计中由于仲裁器留给用户的SDRAM平均写入带宽远大于用户通过8080接口写入的带宽,因此FIFO不会溢出,用户也不会感觉到数据被缓存;当用户往控制器发送读数据命令时,若此时SDRAM处于TFT读操作中,该命令将会暂缓执行,直至TFT读取SDRAM数据操作结束,在本设中于TFT读取SDRAM操作的周期很短,仲裁器留给SDRAM的用户平均读取操作远大于用户通过8080接口读取的带宽,因此用户不会感觉到数据的平连续。

TFT_CTRL控制状态机 —— 这是TFT控制核心模块的核心,该状态机用于控制TFT_CTRL模块内部的状态切换,实现一种类似CPU的流程化控制。

TFT像素坐标=》SDRAM地址转换 —— 实现TFT像素坐标到SDRAM地址的转换,同时控制TFT刷新时X、Y坐标的自动增长控制。

TFT_CTRL控制核心状态机

[图片]

状态机各状态含义:
WAITE_SDR_INIT ——等待SDRAM初始化完成

AUTO_REF_SDR —— 执行SDRAM自动刷新

RD_SDR_TFT —— 执行从SDRAM读取TFT刷屏数据

RD_SDR_USR —— 执行用户读显存操作

WR_SDR_USR —— 执行用户写显存操作

NONE_OP_TFT —— TFT无数据请求

NONE_OP_USR —— 无外部用户请求

在控制器上电后,首先控制器内部的多路时钟生成与系统复位控制模块会延时一段时间,以等待FPGA稳定,之后内部PLL产生一个CLK_LOCK信号,这个CLK_LOCK信号表明PLL已能稳定输出时钟,此时产生一个复位信号用于作为整个控制器的内部复位信号。内部复位完成之后,开始进行SDRAM的初始化工作,经过一系统的SDRAM控制命令之后,SDRAM的内部MODE寄存器成功加载数据,此时即完成了SDRAM的初始化,在这之前状态机始终处理WAITE_SDR_INIT,TFT时序发生器一直处于复位状态。WAITE_SDR_INIT结束后,进入到AUTO_REF_SDR状态,进行SDRAM非初始化阶段的首次自动刷新操作。AUTO_REF_SDR状态同时会结束TFT时序发生器的复位。直至SDRAM自动刷新命令成功完成,状态机始终处理AUTO_REF_SDR。自动刷新命令完成后,若此时TFT模块请求读取SDRAM那么将会进入RD_SDR_TFT状态,反之则进入NONE_OP_TFT状态。在进入RD_SDR_TFT状态后,状态机将始终处于RD_SDR_TFT状态直至数据读取完成。在RD_SDR_TFT或NONE_OP_TFT状态结束之后,若有用户操作请求则进入WR_SDR_USR或RD_SDR_USR状态或NONE_OP_USR状态。若FINISH_OP_SDR状态之后wrUsrFlag标志置位则进入RD_SDR_USR状态,若rdUsrFlag标志置位则进入WR_SDR_USR状态,若二者都未置位则进入NONE_OP_USR状态。进入WR_SDR_USR状态后,直至完成用户数据向SDRAM写入状态机都将始终处于WR_SDR_USR状态。结束WR_SDR_USR状态后,若autoRefFlag置位则进入到AUTO_REF_SDR状态。RD_SDR_USR、NONE_OP_USR状态的跳转逻辑与WR_SDR_USR相同。至此,整个状态机周而复始重复以上过程。

TFT时序控制器

TFT行场模式时序

[图片]

在TFT行场模式下,HS行信号在VS场信号的t_W时段有效,DCLK像素时钟信号在HS行信号的t_HV段内有效,在t_HV时段内,每个DCLK下降沿TFT采样一个数据。在t_HV时段内,TFT完成一行图像的刷新,在t_W时段内TFT完成一幅图像的刷新。

TFT DE模式时序

[图片]

在DE模式下,在DE有效的情况下,每个DCLK下降沿TFT采样一个数据,直至完成一幅图像的刷新。

TFT时序控制器设计

[图片]

行同步计数器 —— 计数DCLK,用于产生行同步信号

场同步计数器 —— 计数行同步计数器的翻转次数,用于产生场同步信号

行信号生成逻辑 —— 产生行同步脉冲时序

场信号生成逻辑 —— 产生场同步脉冲时序

DE信号生成逻辑 —— 产生DE同步脉冲时序

数据请求生成逻辑 —— 产生数据请求信号,请求TFT_CTRL模块从SDRAM读取显存数据

###TFT背光PWM控制模块

[图片]

背光寄存器 —— 用于寄存用户写入的背光值,该值由TFT_CTRL输出

PWM计数比较器 —— 计数背光模块时钟,并与背光寄存器中的值进行比较,输出PWM波

###多路时钟生成,与系统复位控制模块

[图片]

PLL/DLL锁相环 —— 器件内置的PLL或DLL硬核IP,用于倍频和分频产生系统内部所需的25M,100M,与源时钟有一定相移的100M时钟。

内部系统延时复位模块 —— 用于等待上电后外部时钟,同步控制器外部的复位信号,同时等待内部PLL时钟锁定,综合以上信号生成用于系统内部的最终复位信号。