mirror of
https://github.com/WangXuan95/FPGA-DDR-SDRAM.git
synced 2025-01-30 02:32:53 +08:00
first commit
This commit is contained in:
commit
a528872406
454
README.md
Normal file
454
README.md
Normal file
@ -0,0 +1,454 @@
|
||||
![test](https://img.shields.io/badge/test-passing-green.svg)
|
||||
![docs](https://img.shields.io/badge/docs-passing-green.svg)
|
||||
![platform](https://img.shields.io/badge/platform-Quartus|Vivado-blue.svg)
|
||||
|
||||
FPGA DDR-SDRAM
|
||||
===========================
|
||||
在低端FPGA设计中用 DDR-SDRAM(DDR1)替换 SDR-SDRAM。
|
||||
|
||||
# 简介
|
||||
|
||||
|-------------------------| |--------------|
|
||||
| | | |
|
||||
----->| 驱动时钟和复位 | | |
|
||||
| | | |
|
||||
------------| | DDR-SDRAM接口 |--------->| |
|
||||
| AXI4 | | | |
|
||||
AXI4 master |----------->| AXI4 slave | | |
|
||||
| | | | |
|
||||
------------| |-------------------------| |--------------|
|
||||
用户逻辑 DDR1 控制器 DDR1 芯片
|
||||
|
||||
很多低端 FPGA 开发板(例如 [DE0-Nano](https://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&No=593))使用 SDR-SDRAM 作为片外存储,而 DDR-SDRAM (DDR1) 比 SDR-SDRAM 容量更大,价格更低。且与SDR-SDRAM一样,DDR1也能使用低端FPGA的普通的IO管脚直接驱动。我编写了一个软核的 AXI4 接口的 DDR1 控制器(见 [RTL/ddr_sdram_ctrl.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/RTL/ddr_sdram_ctrl.sv) )。该控制器的特点有:
|
||||
|
||||
* **平台无关** :纯 RTL 编写,可以在 Altera 和 Xilinx 等各种 FPGA 上运行。
|
||||
* **兼容性强** :支持各种位宽和容量的 DDR1 (已在MICRON所有位宽和容量的DDR1型号上仿真通过)。
|
||||
|
||||
为了展示该控制器的使用方法,我提供了两个示例程序:
|
||||
|
||||
* **自测程序**:通过DDR1控制器,将数据写入 DDR1 ,然后读出,比较读出的数据是否与写入的吻合。
|
||||
* **UART读写程序**:将 UART 命令转化成 AXI4 总线动作,通过DDR1控制器读写DDR1。
|
||||
|
||||
另外,由于各代 DDR-SDRAM(例如DDR3、DDR2、DDR1)的接口时序大同小异,本库也可以方便那些熟悉 Verilog 的人来学习 DDR-SDRAM 接口。
|
||||
|
||||
# 目录
|
||||
|
||||
* [简介](#简介)
|
||||
* [硬件设计指南](#硬件设计指南)
|
||||
* [硬件设计示例](#硬件设计示例)
|
||||
* [DDR1 控制器](#DDR1 控制器)
|
||||
* [模块参数](#模块参数)
|
||||
* [模块接口 - 驱动时钟和复位](#模块接口 - 驱动时钟和复位)
|
||||
* [时钟频率的选取](#时钟频率的选取)
|
||||
* [模块接口 - DDR1 接口](#模块接口 - DDR1 接口)
|
||||
* [模块接口 - AXI4 从接口](#模块接口 - AXI4 从接口)
|
||||
* [位宽参数的确定](#位宽参数的确定)
|
||||
* [时序参数的确定](#时序参数的确定)
|
||||
* [示例程序](#示例程序)
|
||||
* [示例程序 - 自测](#示例程序 - 自测)
|
||||
* [示例程序 - UART读写](#示例程序 - UART读写)
|
||||
* [Verilog 仿真](#Verilog 仿真)
|
||||
* [建立仿真工程](#建立仿真工程)
|
||||
* [运行仿真](#运行仿真)
|
||||
* [修改仿真参数](#修改仿真参数)
|
||||
|
||||
# 硬件设计指南
|
||||
|
||||
对于 FPGA 的选型,只需要有足够数量的普通 IO 的 FPGA 就可以驱动 DDR1。DDR1 的 IO 电平标准往往是 SSTL-2 ,与 2.5V LVTTL 或 2.5V LVCMOS 兼容,因此相应的 FPGA 的 IO bank 的电源应该是 2.5V,且应在开发软件配置为 2.5V LVTTL 或 2.5V LVCMOS 。
|
||||
|
||||
下表展示了 DDR1 颗粒 的引脚,以及其与 FPGA 连接时应该注意的点。
|
||||
|
||||
| 引脚名称 | 方向 | 位宽 | 说明 | 连接方法 | 注意事项 |
|
||||
| :---: | :---: | :---: | :--- | :--- | :--- |
|
||||
| ddr_ck_p | FPGA output | 1 | 差分时钟正,≥75MHz | 应与 FPGA 的 2.5V LVTTL管脚连接 | 布线尽量短,与 ddr_ck_n 差分布线 |
|
||||
| ddr_ck_n | FPGA output | 1 | 差分时钟负,≥75MHz | 应与 FPGA 的 2.5V LVTTL管脚连接 | 布线尽量短,与 ddr_ck_p 差分布线 |
|
||||
| ddr_cke、ddr_cs_n | FPGA output | 1 | 低速 | 应与 FPGA 的 2.5V LVTTL管脚连接 | |
|
||||
| ddr_ras_n、ddr_cas_n、ddr_we_n | FPGA output | 1 | 与 ddr_ck_p 下降沿同步 | 应与 FPGA 的 2.5V LVTTL管脚连接 | 布线尽量短,与 ddr_ck_p 大致等长(长度别太离谱即可) |
|
||||
| ddr_ba | FPGA output | 2 | 与 ddr_ck_p 下降沿同步 | 应与 FPGA 的 2.5V LVTTL管脚连接 | 布线尽量短,与 ddr_ck_p 大致等长(别太离谱即可) |
|
||||
| ddr_a | FPGA output | 取决于芯片型号 | 与 ddr_ck_p 下降沿同步 | 应与 FPGA 的 2.5V LVTTL管脚连接 | 布线尽量短,与 ddr_ck_p 大致等长(别太离谱即可) |
|
||||
| ddr_dqs | inout | 取决于芯片型号 | | 应与 FPGA 的 2.5V LVTTL管脚连接 | 布线尽量短 |
|
||||
| ddr_dm、ddr_dq | inout | 取决于芯片型号 | 与 ddr_dqs 双沿同步 | 应与 FPGA 的 2.5V LVTTL管脚连接 | 布线尽量短,与 ddr_dqs 大致等长(别太离谱即可) |
|
||||
|
||||
|
||||
# 硬件设计示例
|
||||
|
||||
我用 Altera Cyclone IV 的一个非常低端和廉价的 FPGA (型号:EP4CE6E22C8N) 和 MICRON 的 64MB DDR1 (型号 MT46V64M8TG-6T)画了一个小板子,本库的所有例子可以直接在该板子上直接运行。
|
||||
|
||||
| ![board-image](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/images/board.jpg) |
|
||||
| :---: |
|
||||
| 图:FPGA + DDR1 测试板 |
|
||||
|
||||
原理图见 [hardware/sch.pdf](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/hardware/sch.pdf),PCB制造文件见 [hardware/gerber.zip](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/hardware/gerber.zip) ,在布局布线时,使用双层板即可,不需像 DDR2 以上的设计那样刻意注意等长和阻抗匹配,因为该电路工作频率为双边沿 75MHz,不是特别高,只需注意让FPGA与DDR距离尽量近,布线尽量短即可。比如我在布局时,把DDR1芯片放在了FPGA芯片正对的背面,从而保证布线都较短。
|
||||
|
||||
该板子的设计在立创EDA中开放,见[这里](https://oshwhub.com/wangxuan/fpga-ddr-ce-shi-ban)。
|
||||
|
||||
# DDR1 控制器
|
||||
|
||||
DDR1 控制器代码见 [RTL/ddr_sdram_ctrl.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/RTL/ddr_sdram_ctrl.sv) ,是一个用 SystemVerilog 编写的模块,它能自动对 DDR1 进行初始化,并定时进行刷新(Refresh)。该模块有一个简化但完备的 AXI4 从接口,通过它可以完成对 DDR1 的读写。本节详细解释该模块的使用方法。
|
||||
|
||||
## 模块参数
|
||||
|
||||
模块参数和默认值在 Verilog 中定义如下:
|
||||
|
||||
```Verilog
|
||||
module ddr_sdram_ctrl #(
|
||||
parameter READ_BUFFER = 1,
|
||||
parameter BA_BITS = 2,
|
||||
parameter ROW_BITS = 13,
|
||||
parameter COL_BITS = 11,
|
||||
parameter DQ_LEVEL = 1,
|
||||
parameter [9:0] tREFC = 10'd256,
|
||||
parameter [7:0] tW2I = 8'd7,
|
||||
parameter [7:0] tR2I = 8'd7
|
||||
)
|
||||
```
|
||||
|
||||
对这些参数说明如下:
|
||||
|
||||
| 参数名 | 类型 | 取值范围 | 默认值 | 说明 |
|
||||
| :--: | :--: | :--: | :--: | :-- |
|
||||
| READ_BUFFER | 配置参数 | 0 或 1 | 1 | 若设为0,DDR1控制器内将没有读数据缓冲,读出的数据将不会等待AXI4主机是否能接受,即rvalid信号不会等待rready信号,直接以最高速率灌出去,此时AXI4是不完备的,但可以降低读出的时延。若设为1,则DDR1控制器内会有一个足够大的读数据缓冲,rvalid信号会与rready信号握手,确认AXI4主机准备好后再读出数据。 |
|
||||
| BA_BITS | 位宽参数 | 1~4 | 2 | 规定了 DDR BANK ADDRESS (ddr_ba) 的宽度,常规的 DDR1 的 BANK ADDRESS 都是 2bit,因此该参数通常固定为默认值不用改 |
|
||||
| ROW_BITS | 位宽参数 | 1~15 | 13 | 规定了 DDR ROW ADDRESS 的宽度,同时也决定了 DDR1 芯片的地址线引脚(ddr_a)的宽度。该参数取决于DDR1芯片的选型。例如 MT46V64M8 每个 BANK 有 8192 个 COL,考虑到2^11=8192,该参数应为13。同理,对于 MT46V128M8,该参数应为14 |
|
||||
| COL_BITS | 位宽参数 | 1~14 | 11 | 规定了 DDR COL ADDRESS 的宽度。该参数取决于DDR1芯片的选型。例如 MT46V64M8 每个 ROW 有 2048 个 COL,考虑到2^11=2048,因此该参数应该为11。同理,对于MT46V32M16,该参数应为10。 |
|
||||
| DQ_LEVEL | 位宽参数 | 0~7 | 1 | 规定了 DDR1 芯片的数据位宽,对于位宽x4的芯片(例如MT46V64M4),该参数应取0;对于位宽x8的芯片(例如MT46V64M8),该参数应取1;对于位宽x16的芯片(例如MT46V64M16),该参数应取2;对于位宽x32的情况(例如两片MT46V64M16扩展位宽),该参数应取3;以此类推。
|
||||
| tREFC | 时序参数 | 10'd1 ~ 10'd1023 | 10'd256 | 该控制器会周期性地刷新 DDR1,该参数规定了刷新的间隔。详见下文[时序参数的确定](#时序参数的确定) |
|
||||
| tW2I | 时序参数 | 8'd1~8'd255 | 8'd7 | 该参数规定了一个写动作的最后一个写命令到下一个动作的激活命令(ACT)的间隔。详见下文[时序参数的确定](#时序参数的确定) |
|
||||
| tR2I | 时序参数 | 8'd1~8'd255 | 8'd7 | 该参数规定了一个读动作的最后一个读命令到下一个动作的激活命令(ACT)的间隔。详见下文[时序参数的确定](#时序参数的确定) |
|
||||
|
||||
## 模块接口 - 驱动时钟和复位
|
||||
|
||||
该模块需要一个时钟和一个复位进行驱动,如下:
|
||||
|
||||
```Verilog
|
||||
input wire rstn,
|
||||
input wire clk,
|
||||
```
|
||||
|
||||
rstn 是低电平复位信号,正常工作时应该置高。clk 是驱动时钟,频率是用户时钟的 4 倍。
|
||||
|
||||
模块开始工作前,rstn信号应该置低,让模块复位,当 clk 的频率稳定后,可以把 rstn 置高,让模块处于工作状态。
|
||||
|
||||
如果 clk 一开始就是稳定的(例如直接来自晶振输入),那么 rstn 可以直接置为 1'b1 。
|
||||
|
||||
如果 clk 经过一段时间后才能稳定(例如来自 FPGA 的 PLL 或 MMCM),那么 rstn 应该接 PLL/MMCM 的 locked 信号,保证 PLL 锁相成功(稳定)后,模块再开始工作。
|
||||
|
||||
## 时钟频率的选取
|
||||
|
||||
模块内使用寄存器分频 4 倍产生 DDR1 驱动时钟(ddr_ck_p/ddr_ck_n)和 AXI4 总线用户时钟(aclk)。本节讲述如何决定驱动时钟 clk 的频率。
|
||||
|
||||
首先,时钟频率受限于 DDR1 芯片。考虑到所有的 DDR1 的接口频率至少为 75MHz ,则 clk 的下限是 75\*4=300MHz。而 clk 的上限就取决于 DDR1 的芯片型号,例如对于 MT46V64M8P-5B ,查芯片手册可知,-5B 后缀的 DDR1 在 CL=1 时最高时钟频率是 133MHz,则 clk 的上限是 133\*4=532MHz 。
|
||||
|
||||
另外,时钟频率的上限还受限于 FPGA 的速度,太高的时钟频率容易导致时序不收敛。该控制器充分考虑时序安全设计,大多数寄存器工作在频率较低用户时钟域;个别寄存器工作在用户时钟的 2 倍频率的时钟下,且输入端口的组合逻辑非常短;还有一个寄存器工作在高频的 clk 下,但输入端口直接来自于上一级的寄存器输出(没有组合逻辑)。因此,即使在速度级别很低的 EP4CE6E22C8N 上,在 300MHz 的驱动时钟下也能保证模块正确运行。在速度等级更高的 FPGA (例如 EP4CE22F17C6N)上,驱动时钟的频率可以更高(例如400MHz)。
|
||||
|
||||
> 注意:本控制器固定 CAS Latency (CL) = 2。
|
||||
|
||||
## 模块接口 - DDR1 接口
|
||||
|
||||
以下是该模块的 DDR1 接口。这些接口应该直接从 FPGA 引出,连接到 DDR1 芯片上。
|
||||
|
||||
```Verilog
|
||||
output wire ddr_ck_p, ddr_ck_n,
|
||||
output wire ddr_cke,
|
||||
output reg ddr_cs_n,
|
||||
output reg ddr_ras_n,
|
||||
output reg ddr_cas_n,
|
||||
output reg ddr_we_n,
|
||||
output reg [ BA_BITS-1:0] ddr_ba,
|
||||
output reg [ ROW_BITS-1:0] ddr_a,
|
||||
output wire [((1<<DQ_LEVEL)+1)/2-1:0] ddr_dm,
|
||||
inout [((1<<DQ_LEVEL)+1)/2-1:0] ddr_dqs,
|
||||
inout [ (4<<DQ_LEVEL)-1:0] ddr_dq
|
||||
```
|
||||
|
||||
可以看出 DDR1 接口的一些信号的位宽是和参数有关的,用户需要根据 DDR1 的芯片选型来确定模块参数。详见 [位宽参数的确定](#位宽参数的确定)。
|
||||
|
||||
想了解 DDR1 接口在初始化、读写、刷新时的波形,请进行 [Verilog 仿真](#Verilog 仿真)。
|
||||
|
||||
## 模块接口 - AXI4 从接口
|
||||
|
||||
DDR1 控制器对外提供 AXI4 从接口(AXI4 slave)的时钟和复位信号,如下。AXI4 主机应该用它们作为自己的时钟和复位。
|
||||
|
||||
```Verilog
|
||||
output reg aresetn,
|
||||
output reg aclk,
|
||||
```
|
||||
|
||||
以下是该模块的 AXI4 从接口,它们都与 aclk 时钟的上升沿同步,应该连接到 FPGA 内的的 AXI4 主机。
|
||||
|
||||
```Verilog
|
||||
input wire awvalid,
|
||||
output wire awready,
|
||||
input wire [BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-2:0] awaddr,
|
||||
input wire [ 7:0] awlen,
|
||||
input wire wvalid,
|
||||
output wire wready,
|
||||
input wire wlast,
|
||||
input wire [(8<<DQ_LEVEL)-1:0] wdata,
|
||||
output wire bvalid,
|
||||
input wire bready,
|
||||
input wire arvalid,
|
||||
output wire arready,
|
||||
input wire [BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-2:0] araddr,
|
||||
input wire [ 7:0] arlen,
|
||||
output wire rvalid,
|
||||
input wire rready,
|
||||
output wire rlast,
|
||||
output wire [(8<<DQ_LEVEL)-1:0] rdata,
|
||||
```
|
||||
|
||||
AXI4 总线的数据(wdata和rdata)的位宽是 DDR1 数据位宽的 2 倍。例如,对于位宽为 8bit 的 MT46V64M8,wdata 和 rdata 的位宽是 16bit 。
|
||||
|
||||
AXI4 总线的地址(awaddr和araddr)统一是字节地址,模块会根据用户指定的参数来计算 awaddr 和 araddr 的位宽 = BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-1 。例如对于 64MB 的 MT46V64M8 ,awaddr/araddr 位宽为 26,而 2^26 等于 64MB。
|
||||
|
||||
每次读写访问时,地址值(awaddr和araddr)都要和整个字对齐,例如若 wdata 和 rdata 的位宽是 16bit(2字节),那么 wdata 和 rdata 要按 2 字节对齐,即能整除 2。
|
||||
|
||||
该模块的 AXI4 接口不支持字节选通写入,没有 wstrb 信号,每次至少写入一整个数据位宽,例如若 wdata 的位宽是 16,那么一次至少写入2字节。
|
||||
|
||||
该模块的 AXI4 接口支持突发读写,突发长度可取 1~256 之间的任意值,即 awlen 和 arlen 取值范围为 0~255 。例如,在一次写入动作中,awlen=12,则突发长度为 13,若 wdata 的位宽是 16 ,那么该次突发写一共写了 13\*2=26B。
|
||||
|
||||
另外,每次突发读写不能超越 DDR1 内的一个行的边界。例如对于 MT46V64M8,每个行有 8\*2^11/8 = 2048B,那么每次突发读写就不能超越 2048B 的边界。
|
||||
|
||||
### AXI4 写操作时序
|
||||
|
||||
__ __ __ __ __ __ __ __ __ __ __ __ _
|
||||
aclk __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/
|
||||
___________
|
||||
awvalid ___/ \____________________________________________________________
|
||||
_____
|
||||
awready _________/ \____________________________________________________________
|
||||
___________
|
||||
awaddr XXXX____ADDR___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
___________
|
||||
awlen XXXX____8'd3___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
___________ ___________ _____
|
||||
wvalid _______________/ \_____/ \_____/ \__________________
|
||||
___________________________________
|
||||
wready _____________________/ \__________________
|
||||
_____
|
||||
wlast ___________________________________________________/ \__________________
|
||||
___________ _____ _____ _____
|
||||
wdata XXXXXXXXXXXXXXXX_____D0____XXXXXXX__D1_X__D2_XXXXXXX__D3_XXXXXXXXXXXXXXXXXXX
|
||||
___________
|
||||
bvalid _________________________________________________________/ \______
|
||||
_____
|
||||
bready _______________________________________________________________/ \______
|
||||
|
||||
一个典型的,突发长度为 4 (awlen=3) 的 AXI4 写操作如上图。分为 3 步:
|
||||
|
||||
* **地址通道握手**:AXI4 主机把 awvalid 信号拉高,指示想要发起写动作,图中经过一周期后,DDR1 控制器才把 awready 信号拉高,说明地址通道握手成功(在此之前,DDR1 控制器可能在处理上一次读写动作,或者在进行刷新,因此暂时没把 awready 拉高)。握手成功的同时,DDR1 控制器收到待写地址(awaddr)和突发长度(awlen),awlen=8'd3 说明突发长度为 4。
|
||||
* **数据传送**:AXI4 总线上的 wvalid 和 wready 进行 4 次握手,把突发传输的 4 个数据写入 DDR1。在握手时,若 AXI4 主机还没准备好数据,可以把 wvalid 拉低,若 DDR1 控制器还没准备好接受数据,会把 wready 拉低。注意,根据 AXI4 总线的规定,在突发传输的最后一个数据传输的同时需要把 wlast 信号置高(实际上即使不置高,DDR1 控制器也能根据突发长度自动结束数据传送,进入写响应状态)。
|
||||
* **写响应**:数据传送结束后,DDR1 控制器还需要和 AXI4 主机进行一次握手,才能彻底结束本次写动作。DDR1 控制器在数据传送结束后立即把 wvalid 信号拉高,并等待 wready 为高。完成该握手后,DDR1才能响应下一次读写操作。
|
||||
|
||||
### AXI4 读操作时序
|
||||
|
||||
__ __ __ __ __ __ __ __ __ __ __ __ _
|
||||
aclk __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/
|
||||
___________
|
||||
arvalid ___/ \____________________________________________________________
|
||||
_____
|
||||
arready _________/ \____________________________________________________________
|
||||
___________
|
||||
araddr XXXX____ADDR___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
___________
|
||||
arlen XXXX____8'd4___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
___________________________________
|
||||
rvalid _________________________________/ \______
|
||||
___________________________________________________ __________________
|
||||
rready \_____/
|
||||
_____
|
||||
rlast _______________________________________________________________/ \______
|
||||
_____ _____ _____ ___________ _____
|
||||
rdata XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX__D0_X__D1_X__D2_X_____D3____X__D4_XXXXXXX
|
||||
|
||||
一个典型的,突发长度为 5 (arlen=4) 的 AXI4 读操作如上图。分为 2 步:
|
||||
|
||||
* **地址通道握手**:AXI4 主机把 arvalid 信号拉高,指示想要发起写动作,图中经过一周期后,DDR1 控制器才把 arready 信号拉高,说明地址通道握手成功(在此之前,DDR1 控制器可能在处理上一次读写动作,或者在进行刷新,因此暂时没把 arready 拉高)。握手成功的同时,DDR1 控制器收到待读地址(araddr)和突发长度(arlen),arlen=8'd4 说明突发长度为 5。
|
||||
* **数据传送**:AXI4 总线上的 rvalid 和 rready 进行 5 次握手,把突发传输的 5 个读出。在握手时,若 AXI4 主机还没准备好接受数据,可以把 rready 拉低,则 DDR1 控制器会保持当前数据,直到 AXI4主机能接受此数据(即把rready拉高)为止。在传送最后一个数据时,DDR1 控制器会把 rlast 拉高。
|
||||
|
||||
> 注:当模块参数 READ_BUFFER = 0 时,模块将节省一个 BRAM 资源,同时还能降低地址通道握手和数据传送之间的延迟。但 DDR1 控制器会忽略 rready=0 的情况,不等待 AXI4 主机是否准备好接受数据。这样将会破坏 AXI4 协议的完备性,但在一些简单的场合或许有用。
|
||||
|
||||
|
||||
## 位宽参数的确定
|
||||
|
||||
本节讲述如何确定 **BA_BITS**、**ROW_BITS**、**COL_BITS** 和 **DQ_LEVEL** 这 4 个参数。
|
||||
|
||||
从[模块接口 - DDR1 接口](#模块接口 - DDR1 接口)一节可以看出 DDR1 接口的一些信号的位宽是和参数有关的,用户需要根据 DDR1 的芯片选型来确定模块参数。
|
||||
|
||||
以 [MICRON 公司的 DDR-SDRAM](https://www.micron.com/products/dram/ddr-sdram) 系列芯片为例,不同芯片有不同的 ROW ADDRESS BITS (行地址宽度)、COL ADDRESS BITS(列地址宽度)、DATA BITS(数据宽度),决定了他们的位宽参数也不同,如下表(注:这些参数都能从芯片datasheet中查到)。
|
||||
|
||||
| 芯片名称 | ddr_dq 位宽 | ddr_dm 和 ddr_dqs 位宽 | DQ_LEVEL 取值 | BA_BITS | ROW_BITS | COL_BITS | 每行字节数 | 容量 | awaddr/araddr 位宽 |
|
||||
| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :-- | :--: |
|
||||
| MT46V64M4 | 4 | 1 | 0 | 2 | 13 | 11 | 1024 | 4\*2^(2+13+11)=256Mb=32MB | 25 |
|
||||
| MT46V128M4 | 4 | 1 | 0 | 2 | 13 | 12 | 2048 | 4\*2^(2+13+12)=512Mb=64MB | 26 |
|
||||
| MT46V256M4 | 4 | 1 | 0 | 2 | 14 | 12 | 4096 | 4\*2^(2+14+12)=1Gb=128MB | 27 |
|
||||
| MT46V32M8 | 8 | 1 | 1 | 2 | 13 | 10 | 1024 | 8\*2^(2+13+10)=256Mb=32MB | 25 |
|
||||
| MT46V64M8 | 8 | 1 | 1 | 2 | 13 | 11 | 2048 | 8\*2^(2+13+11)=512Mb=64MB | 26 |
|
||||
| MT46V128M8 | 8 | 1 | 1 | 2 | 14 | 11 | 4096 | 8\*2^(2+14+11)=1Gb=128MB | 27 |
|
||||
| MT46V16M16 | 16 | 2 | 2 | 2 | 13 | 9 | 1024 | 16\*2^(2+13+9)=256Mb=32MB | 25 |
|
||||
| MT46V32M16 | 16 | 2 | 2 | 2 | 13 | 10 | 2048 | 16\*2^(2+13+10)=512Mb=64MB | 26 |
|
||||
| MT46V64M16 | 16 | 2 | 2 | 2 | 14 | 10 | 4096 | 16\*2^(2+14+10)=1Gb=128MB | 27 |
|
||||
|
||||
## 时序参数的确定
|
||||
|
||||
本节讲述如何确定 **tREFC**、**tW2I** 和 **tR2I** 这 3 个时序参数。
|
||||
|
||||
我们知道,DDR1 需要周期性的刷新动作,**tREFC** 就规定了刷新的时钟周期间隔(以 aclk为准)。例如,若用户时钟为 75MHz,根据 MT46V64M8 的芯片手册,需要至多 7.8125us 刷新一次,考虑到 75MHz * 7.8125us = 585.9,则该参数可以设置为一个小于 585 的值,例如 10'd512。
|
||||
|
||||
**tW2I** 规定了一个写操作的最后一个写命令到下一个操作的激活命令(ACT)的时钟周期数(以 aclk 为准)的最小值。下图展示了一个 DDR1 接口上的写操作,ddr_cas_n 的第一个上升沿代表了一个写操作的最后一个写命令结束,ddr_ras_n 的第二个下降沿代表了下一个操作(可能是读、写、刷新)的开始,它们之间有 5 个时钟周期,**tW2I** 就是用来规定该周期数的下限的。**tW2I** 的默认值 8'd7 是一个兼容绝大多数 DDR1 的保守值,对于不同的 DDR1 芯片,有不同的缩小的余地(详见 DDR1 芯片 datasheet)。
|
||||
|
||||
__ __ __ __ __ __ __ __ __ __ __ __
|
||||
ddr_ck_p __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__
|
||||
_____ _______________________________________________ ________
|
||||
ddr_ras_n \_____/ \_____/
|
||||
_________________ ____________________________________________
|
||||
ddr_cas_n \___________/
|
||||
_________________ ____________________________________________
|
||||
ddr_we_n \___________/
|
||||
_____
|
||||
ddr_a[10] XXXXXXXXXXXXXXXXXX_____/ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
_______________________
|
||||
ddr_ba XXXXXX__________BA___________XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
_______________________
|
||||
ddr_a XXXXXX__RA_XXXXXXX_CA0_X_CA1_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
**tR2I** 规定了一个读操作的最后一个读命令到下一个操作的激活命令(ACT)的时钟周期数(以 aclk 为准)的最小值。下图展示了一个 DDR1 接口上的读操作,ddr_cas_n 的第一个上升沿代表了一个读操作的最后一个读命令结束,ddr_ras_n 的第二个下降沿代表了下一个操作(可能是读、写、刷新)的开始,它们之间有 5 个时钟周期,**tR2I** 就是用来规定该周期数的下限的。**tR2I** 的默认值 8'd7 是一个兼容绝大多数 DDR1 的保守值,对于不同的 DDR1 芯片,有不同的缩小的余地(详见 DDR1 芯片 datasheet)。
|
||||
|
||||
__ __ __ __ __ __ __ __ __ __ __ __
|
||||
ddr_ck_p __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__
|
||||
_____ _______________________________________________ ________
|
||||
ddr_ras_n \_____/ \_____/
|
||||
_________________ ____________________________________________
|
||||
ddr_cas_n \___________/
|
||||
__________________________________________________________________________
|
||||
ddr_we_n
|
||||
_____
|
||||
ddr_a[10] XXXXXXXXXXXXXXXXXX_____/ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
_______________________
|
||||
ddr_ba XXXXXX__________BA___________XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
_______________________
|
||||
ddr_a XXXXXX__RA_XXXXXXX_CA0_X_CA1_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
# 示例程序
|
||||
|
||||
## 示例程序 - 自测
|
||||
|
||||
我基于我画的 [FPGA+DDR1测试板](#硬件设计示例) 做了一个 DDR1 读写自测程序,工程目录是 [example-selftest](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/example-selftest),请用 Quartus II 13.1 打开它。
|
||||
|
||||
该工程包含以下文件:
|
||||
|
||||
| 文件名称 | 用途 |
|
||||
| :---- | :--- |
|
||||
| [top.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/example-selftest/RTL/top.sv) | 顶层 |
|
||||
| [axi_self_test_master.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/example-selftest/RTL/axi_self_test_master.sv) | 是 AXI4 主机,通过 AXI4 先把有规律的数据写入 DDR1,然后读回,比较读回的数据是否符合规律,并对不匹配的情况进行计数。 |
|
||||
| [ddr_sdram_ctrl.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/RTL/ddr_sdram_ctrl.sv) | DDR1 控制器 |
|
||||
| [pll.v](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/example-selftest/IP/pll.v) | 使用板上 50MHz 晶振产生 300MHz 时钟,输出给 DDR1 控制器 |
|
||||
|
||||
**写入**:该工程开始运行后,会先通过 AXI4 把整个 DDR1 都写一遍,直接把地址字写入相应的地址。例如,如果 AXI4 的数据宽度是 16bit,那么地址 0x000002 处写 0x0001。地址 0x123456 处写 0x3456。
|
||||
|
||||
**读取&错误校验**:写完整个 DDR1 后,该工程会一轮一轮地反复读取整个 DDR1,若读出的数据不符合上述规律,就认为出现错误,在错误信号(error)上产生一个高电平脉冲,并把错误计数信号(error_cnt)+1。如果 DDR1 配置正确,是不该出现 error 信号的。你可以测量 error_cnt 对应的引脚,若为0(全低电平),说明不存在错误。
|
||||
|
||||
**SignalTap抓波形**:该工程包含一个 SignalTap 文件([stp1.stp]()),在程序运行时,可以用它查看 DDR1 接口上的波形。它以 error=1 为触发信号,因此如果读写自测没有出错,它就不会被触发。因为该工程随时都在读取 DDR1,要想看 DDR1 接口上的波形,直接按“停止”按钮即可。
|
||||
|
||||
**修改 AXI4 突发长度**:在 [top.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/example-selftest/RTL/top.sv) 的第 82,83 行可以修改 WBURST_LEN 和 RBURST_LEN,从而修改自测时的写/读突发长度,该自测程序只支持 2^n-1 这种突发长度,即 WBURST_LEN 和 RBURST_LEN 必须取形如 0,1,3,7,15,31,…… 的值(注意,这只是我编写的自测程序的限制,DDR1 控制器是支持 0~255 之间的任意突发长度的。
|
||||
|
||||
> WBURST_LEN 和 RBURST_LEN 可以设置的不一样。
|
||||
|
||||
## 示例程序 - UART读写
|
||||
|
||||
我基于我画的 [FPGA+DDR1测试板](#硬件设计示例) 做了一个 UART 读写程序,使用该程序,你可以通过 UART 命令,以不同的突发长度来读写 DDR1。工程目录是 [example-uart-read-write](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/example-uart-read-write),请用 Quartus II 13.1 打开它。
|
||||
|
||||
该工程包含以下文件:
|
||||
|
||||
| 文件名称 | 用途 |
|
||||
| :---- | :--- |
|
||||
| [top.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/example-uart-read-write/RTL/top.sv) | 顶层 |
|
||||
| [uart2axi4.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/example-uart-read-write/RTL/uart2axi4.sv) | 是 AXI4 主机,能把 UART RX 收到的命令转换成 AXI4 读写操作,并把读操作读出的数据通过 UART TX 发送出去 |
|
||||
| [uart_rx.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/example-uart-read-write/RTL/uart_rx.sv) | UART RX 接收器,被 uart2axi4.sv 调用 |
|
||||
| [axis2uarttx.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/example-uart-read-write/RTL/axis2uarttx.sv) | UART TX 发送器,被 uart2axi4.sv 调用 |
|
||||
| [ddr_sdram_ctrl.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/RTL/ddr_sdram_ctrl.sv) | DDR1 控制器 |
|
||||
| [pll.v](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/example-uart-read-write/IP/pll.v) | 使用板上 50MHz 晶振产生 300MHz 时钟,输出给 DDR1 控制器 |
|
||||
|
||||
[FPGA+DDR1测试板](#硬件设计示例)上有一个 CH340E 芯片(USB 转 UART),因此插上 USB 线后就可以在电脑上看见 UART 对应的 COM 口(需要先在[这里](http://www.wch.cn/product/CH340.html)下载安装 CH341 的驱动)。
|
||||
|
||||
工程上传 FPGA 后,双击打开我编写的一个串口小工具 [UartSession.exe](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/UartSession.exe) ,根据提示打开板子对应的 COM 口,然后打如下的命令+回车,可以把 0x0123 0x4567 0x89ab 0xcdef 这 4 个数据写入起始地址0x12345。(AXI4总线上会产生一个突发长度为 4 的写操作)。
|
||||
|
||||
w12345 0123 4567 89ab cdef
|
||||
|
||||
然后用以下命令+回车,可以以 0x12345 为起始地址,以 7 为突发长度,读取 8 个数据。
|
||||
|
||||
r12345 7
|
||||
|
||||
效果如下图,前4个数据 (0123 4567 89ab cdef) 就是我们已经写入 DDR1 的,后4个数据我们没写过,是 DDR1 初始化后自带的随机数据。
|
||||
|
||||
| ![UART读写](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/images/UartSession.png) |
|
||||
| :--: |
|
||||
| 图:使用 UartSession.exe 测试 DDR1 读写 |
|
||||
|
||||
写命令里有多少数据,写突发长度就是多少,例如以下写命令的突发长度是 9,将 10 个数据写入起始地址 0x00000
|
||||
|
||||
w0 1234 2345 3456 4567 5678 6789 789a 89ab 9abc abcd
|
||||
|
||||
读命令则直接指定突发长度,例如以下命令的突发长度为 30 (0x1e),从起始地址 0x00000 将 31 个数据读出
|
||||
|
||||
r0 1e
|
||||
|
||||
# Verilog 仿真
|
||||
|
||||
## 建立仿真工程
|
||||
|
||||
仿真所需要的文件在目录 [sim-selftest](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest) 里,你可以用以下 Verilog 文件建立仿真工程:
|
||||
|
||||
| 文件路径 | 用途 |
|
||||
| :---- | :--- |
|
||||
| [sim-selftest/SRC/tb_ddr_ctrl.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/SRC/tb_ddr_ctrl.sv) | 仿真顶层 |
|
||||
| [sim-selftest/SRC/axi_self_test_master.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/SRC/axi_self_test_master.sv) | 是 AXI4 主机,通过 AXI4 先把有规律的数据写入 DDR1,然后读回,比较读回的数据是否符合规律,并对不匹配的情况进行计数。 |
|
||||
| [RTL/ddr_sdram_ctrl.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/RTL/ddr_sdram_ctrl.sv) | DDR1 控制器 |
|
||||
| [sim-selftest/DDR_MODEL/ddr.v](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/DDR_MODEL/ddr.v) | [MICRON 公司提供的 DDR1 仿真模型](https://www.micron.com/products/dram/ddr-sdram/part-catalog/mt46v64m8p-5b) |
|
||||
| [sim-selftest/DDR_MODEL/ddr_parameters.vh](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/DDR_MODEL/ddr_parameters.vh) | DDR1 仿真模型的参数配置文件 |
|
||||
|
||||
该仿真工程的行为类似[自测程序](#示例程序 - 自测),[axi_self_test_master.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/SRC/axi_self_test_master.sv) 作为 AXI4 主机,将有规律的数据写入 DDR1 中,只不过不是全部写入,而是只写入 DDR1 的前 16KB (因为仿真模型的存储空间有限),然后一轮一轮地反复读出数据,比较是否有不匹配的数据,若有,则在 error 信号上产生一个时钟周期的高电平。
|
||||
|
||||
## 运行仿真
|
||||
|
||||
建立工程后,直接运行仿真,得到如下波形。前 294us,AXI4 主机在进行前 16KB 的写入;294us 之后,AXI4 主机在不断的读出数据。error 信号一直为低电平说明读出的数据无误。
|
||||
|
||||
| ![仿真波形](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/images/sim.png) |
|
||||
| :--: |
|
||||
| 图:仿真波形 |
|
||||
|
||||
你可以展开查看 AXI4 总线和 DDR1 接口的波形细节。这里不做赘述。
|
||||
|
||||
## 修改仿真参数
|
||||
|
||||
以上仿真默认配置的参数是使用 MT46V64M8 ,即 ROW_BITS=13,COL_BITS=11,DQ_BITS=8。如果想对其它型号的 DDR1 芯片进行仿真,需要修改的参数如下:
|
||||
|
||||
* 仿真顶层中的 **BA_BITS**:见 [sim-selftest/SRC/tb_ddr_ctrl.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/SRC/tb_ddr_ctrl.sv) 第 8 行。
|
||||
* DDR1 模型中的 **BA_BITS**:见 [sim-selftest/DDR_MODEL/ddr_parameters.vh](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/DDR_MODEL/ddr_parameters.vh) 第 35 行。
|
||||
* 仿真顶层中的 **ROW_BITS**:见 [sim-selftest/SRC/tb_ddr_ctrl.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/SRC/tb_ddr_ctrl.sv) 第 9 行。
|
||||
* DDR1 模型中的 **ROW_BITS**:见 [sim-selftest/DDR_MODEL/ddr_parameters.vh](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/DDR_MODEL/ddr_parameters.vh) 第 36 行。
|
||||
* 仿真顶层中的 **COL_BITS**:见 [sim-selftest/SRC/tb_ddr_ctrl.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/SRC/tb_ddr_ctrl.sv) 第 10 行。
|
||||
* DDR1 模型中的 **COL_BITS**:见 [sim-selftest/DDR_MODEL/ddr_parameters.vh](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/DDR_MODEL/ddr_parameters.vh) 第 37 行。
|
||||
* 仿真顶层中的 **DQ_LEVEL**:见 [sim-selftest/SRC/tb_ddr_ctrl.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/SRC/tb_ddr_ctrl.sv) 第 11 行。
|
||||
* DDR1 模型中的 **DQ_BITS**:见 [sim-selftest/DDR_MODEL/ddr_parameters.vh](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/DDR_MODEL/ddr_parameters.vh) 第 38 行。
|
||||
|
||||
对于 MICRON 公司的 DDR1 系列,这些参数应该这样修改:
|
||||
|
||||
| 芯片名称 | BA_BITS | ROW_BITS | COL_BITS | DQ_LEVEL | DQ_BITS
|
||||
| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: |
|
||||
| MT46V64M4 | 2 | 13 | 11 | 0 | 4 |
|
||||
| MT46V128M4 | 2 | 13 | 12 | 0 | 4 |
|
||||
| MT46V256M4 | 2 | 14 | 12 | 0 | 4 |
|
||||
| MT46V32M8 | 2 | 13 | 10 | 1 | 8 |
|
||||
| MT46V64M8 | 2 | 13 | 11 | 1 | 8 |
|
||||
| MT46V128M8 | 2 | 14 | 11 | 1 | 8 |
|
||||
| MT46V16M16 | 2 | 13 | 9 | 2 | 16 |
|
||||
| MT46V32M16 | 2 | 13 | 10 | 2 | 16 |
|
||||
| MT46V64M16 | 2 | 14 | 10 | 2 | 16 |
|
||||
|
||||
另外,你可以修改 [tb_ddr_ctrl.sv](https://github.com/WangXuan95/FPGA-DDR-SDRAM/blob/main/sim-selftest/SRC/tb_ddr_ctrl.sv) 的第 18 和 19 行来修改仿真时的突发读写的长度。
|
||||
|
||||
# 参考资料
|
||||
|
||||
* MICRON 公司提供的 DDR1 仿真模型: https://www.micron.com/products/dram/ddr-sdram/part-catalog/mt46v64m8p-5b
|
||||
* MT46V64M8 芯片手册: https://media-www.micron.com/-/media/client/global/documents/products/data-sheet/dram/ddr1/512mb_ddr.pdf?rev=4e1e995d6d2240e293286770f193d57d
|
593
RTL/ddr_sdram_ctrl.sv
Normal file
593
RTL/ddr_sdram_ctrl.sv
Normal file
@ -0,0 +1,593 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
module ddr_sdram_ctrl #(
|
||||
parameter READ_BUFFER = 1,
|
||||
parameter BA_BITS = 2,
|
||||
parameter ROW_BITS = 13,
|
||||
parameter COL_BITS = 11,
|
||||
parameter DQ_LEVEL = 1, // DDR DQ_BITS = 4<<DQ_LEVEL, AXI4 DATA WIDTH = 8<<DQ_LEVEL, for example:
|
||||
// DQ_LEVEL = 0: DQ_BITS = 4 (x4) , AXI DATA WIDTH = 8
|
||||
// DQ_LEVEL = 1: DQ_BITS = 8 (x8) , AXI DATA WIDTH = 16 (default)
|
||||
// DQ_LEVEL = 2: DQ_BITS = 16 (x16) , AXI DATA WIDTH = 32
|
||||
parameter [9:0] tREFC = 10'd256,
|
||||
parameter [7:0] tW2I = 8'd7,
|
||||
parameter [7:0] tR2I = 8'd7
|
||||
) (
|
||||
// driving clock and reset
|
||||
input wire rstn,
|
||||
input wire clk, // driving clock, typically 300~532MHz
|
||||
// user interface ( meta AXI4 )
|
||||
output reg aresetn,
|
||||
output reg aclk, // freq = F(clk)/4
|
||||
input wire awvalid,
|
||||
output wire awready,
|
||||
input wire [BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-2:0] awaddr, // byte address, not word address.
|
||||
input wire [ 7:0] awlen,
|
||||
input wire wvalid,
|
||||
output wire wready,
|
||||
input wire wlast,
|
||||
input wire [(8<<DQ_LEVEL)-1:0] wdata,
|
||||
output wire bvalid,
|
||||
input wire bready,
|
||||
input wire arvalid,
|
||||
output wire arready,
|
||||
input wire [BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-2:0] araddr, // byte address, not word address.
|
||||
input wire [ 7:0] arlen,
|
||||
output wire rvalid,
|
||||
input wire rready,
|
||||
output wire rlast,
|
||||
output wire [(8<<DQ_LEVEL)-1:0] rdata,
|
||||
// DDR-SDRAM interface
|
||||
output wire ddr_ck_p, ddr_ck_n, // freq = F(clk)/4
|
||||
output wire ddr_cke,
|
||||
output reg ddr_cs_n,
|
||||
output reg ddr_ras_n,
|
||||
output reg ddr_cas_n,
|
||||
output reg ddr_we_n,
|
||||
output reg [ BA_BITS-1:0] ddr_ba,
|
||||
output reg [ ROW_BITS-1:0] ddr_a,
|
||||
output wire [((1<<DQ_LEVEL)+1)/2-1:0] ddr_dm,
|
||||
inout [((1<<DQ_LEVEL)+1)/2-1:0] ddr_dqs,
|
||||
inout [ (4<<DQ_LEVEL)-1:0] ddr_dq
|
||||
);
|
||||
|
||||
localparam DQS_BITS = ((1<<DQ_LEVEL)+1)/2;
|
||||
|
||||
reg clk2;
|
||||
reg init_done;
|
||||
reg [2:0] ref_idle, ref_real;
|
||||
reg [9:0] ref_cnt;
|
||||
reg [7:0] cnt;
|
||||
enum logic [3:0] {RESET, IDLE, CLEARDLL, REFRESH, WPRE, WRITE, WRESP, WWAIT, RPRE, READ, RRESP, RWAIT} stat;
|
||||
|
||||
reg [7:0] burst_len;
|
||||
wire burst_last = cnt==burst_len;
|
||||
reg [DQ_LEVEL-1:0] trash_lsb_addr;
|
||||
reg [COL_BITS-2:0] col_addr;
|
||||
|
||||
wire [ROW_BITS-1:0] ddr_a_col;
|
||||
generate if(COL_BITS>10) begin
|
||||
assign ddr_a_col = {col_addr[COL_BITS-2:9], burst_last, col_addr[8:0], 1'b0};
|
||||
end else begin
|
||||
assign ddr_a_col = {burst_last, col_addr[8:0], 1'b0};
|
||||
end endgenerate
|
||||
|
||||
wire read_accessible, read_respdone;
|
||||
reg output_enable, output_enable_d1, output_enable_d2;
|
||||
|
||||
reg o_v_a;
|
||||
reg [(4<<DQ_LEVEL)-1:0] o_dh_a;
|
||||
reg [(4<<DQ_LEVEL)-1:0] o_dl_a;
|
||||
reg o_v_b;
|
||||
reg [(4<<DQ_LEVEL)-1:0] o_dh_b;
|
||||
reg o_dqs_c;
|
||||
reg [(4<<DQ_LEVEL)-1:0] o_d_c;
|
||||
reg [(4<<DQ_LEVEL)-1:0] o_d_d;
|
||||
|
||||
reg i_v_a;
|
||||
reg i_l_a;
|
||||
reg i_v_b;
|
||||
reg i_l_b;
|
||||
reg i_v_c;
|
||||
reg i_l_c;
|
||||
reg i_dqs_c;
|
||||
reg [(4<<DQ_LEVEL)-1:0] i_d_c;
|
||||
reg i_v_d;
|
||||
reg i_l_d;
|
||||
reg [(8<<DQ_LEVEL)-1:0] i_d_d;
|
||||
reg i_v_e;
|
||||
reg i_l_e;
|
||||
reg [(8<<DQ_LEVEL)-1:0] i_d_e;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// constants defination and assignment
|
||||
// -------------------------------------------------------------------------------------
|
||||
reg [ROW_BITS-1:0] DDR_A_DEFAULT, DDR_A_MR0, DDR_A_MR_CLEAR_DLL;
|
||||
always_comb begin
|
||||
DDR_A_DEFAULT = '0;
|
||||
DDR_A_MR0 = '0;
|
||||
DDR_A_MR_CLEAR_DLL = '0;
|
||||
DDR_A_DEFAULT[10] = 1'b1;
|
||||
DDR_A_MR0[0] = 1'b1;
|
||||
DDR_A_MR0[3] = 1'b1;
|
||||
DDR_A_MR0[5] = 1'b1;
|
||||
DDR_A_MR0[8] = 1'b1;
|
||||
DDR_A_MR_CLEAR_DLL[0] = 1'b1;
|
||||
DDR_A_MR_CLEAR_DLL[3] = 1'b1;
|
||||
DDR_A_MR_CLEAR_DLL[5] = 1'b1;
|
||||
end
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// generate clocks
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn)
|
||||
{aclk,clk2} <= 2'b00;
|
||||
else
|
||||
{aclk,clk2} <= {aclk,clk2} + 2'b01;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// generate user reset
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge aclk or negedge rstn)
|
||||
if(~rstn)
|
||||
aresetn <= 1'b0;
|
||||
else
|
||||
aresetn <= init_done;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// refresh wptr self increasement
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge aclk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
ref_cnt <= '0;
|
||||
ref_idle <= 3'd1;
|
||||
end else begin
|
||||
if(init_done) begin
|
||||
if(ref_cnt<tREFC) begin
|
||||
ref_cnt <= ref_cnt + 10'd1;
|
||||
end else begin
|
||||
ref_cnt <= '0;
|
||||
ref_idle <= ref_idle + 3'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// generate DDR clock
|
||||
// -------------------------------------------------------------------------------------
|
||||
assign ddr_ck_p = ~aclk;
|
||||
assign ddr_ck_n = aclk;
|
||||
assign ddr_cke = ~ddr_cs_n;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// generate DDR DQ output behavior
|
||||
// -------------------------------------------------------------------------------------
|
||||
assign ddr_dm = output_enable ? '0 : 'z;
|
||||
assign ddr_dqs = output_enable ? {DQS_BITS{o_dqs_c}} : 'z;
|
||||
assign ddr_dq = output_enable ? o_d_d : 'z;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// assignment for user interface (meta AXI4 interface)
|
||||
// -------------------------------------------------------------------------------------
|
||||
assign awready = stat==IDLE && init_done && ref_real==ref_idle;
|
||||
assign wready = stat==WRITE;
|
||||
assign bvalid = stat==WRESP;
|
||||
assign arready = stat==IDLE && init_done && ref_real==ref_idle && ~awvalid && read_accessible;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// main FSM for generating DDR-SDRAM behavior
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge aclk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
ddr_cs_n <= 1'b1;
|
||||
ddr_ras_n <= 1'b1;
|
||||
ddr_cas_n <= 1'b1;
|
||||
ddr_we_n <= 1'b1;
|
||||
ddr_ba <= '0;
|
||||
ddr_a <= DDR_A_DEFAULT;
|
||||
col_addr <= '0;
|
||||
burst_len <= '0;
|
||||
init_done <= 1'b0;
|
||||
ref_real <= 3'd0;
|
||||
cnt <= 8'd0;
|
||||
stat <= RESET;
|
||||
end else begin
|
||||
case(stat)
|
||||
RESET: begin
|
||||
cnt <= cnt + 8'd1;
|
||||
if(cnt<8'd13) begin
|
||||
end else if(cnt<8'd50) begin
|
||||
ddr_cs_n <= 1'b0;
|
||||
end else if(cnt<8'd51) begin
|
||||
ddr_ras_n <= 1'b0;
|
||||
ddr_we_n <= 1'b0;
|
||||
end else if(cnt<8'd53) begin
|
||||
ddr_ras_n <= 1'b1;
|
||||
ddr_we_n <= 1'b1;
|
||||
end else if(cnt<8'd54) begin
|
||||
ddr_ras_n <= 1'b0;
|
||||
ddr_cas_n <= 1'b0;
|
||||
ddr_we_n <= 1'b0;
|
||||
ddr_ba <= 'h1;
|
||||
ddr_a <= '0;
|
||||
end else begin
|
||||
ddr_ba <= '0;
|
||||
ddr_a <= DDR_A_MR0;
|
||||
stat <= IDLE;
|
||||
end
|
||||
end
|
||||
IDLE: begin
|
||||
ddr_ras_n <= 1'b1;
|
||||
ddr_cas_n <= 1'b1;
|
||||
ddr_we_n <= 1'b1;
|
||||
ddr_ba <= '0;
|
||||
ddr_a <= DDR_A_DEFAULT;
|
||||
cnt <= 8'd0;
|
||||
if(ref_real != ref_idle) begin
|
||||
ref_real <= ref_real + 3'd1;
|
||||
stat <= REFRESH;
|
||||
end else if(~init_done) begin
|
||||
stat <= CLEARDLL;
|
||||
end else if(awvalid) begin
|
||||
ddr_ras_n <= 1'b0;
|
||||
if(DQ_LEVEL>0)
|
||||
{ddr_ba, ddr_a, col_addr, trash_lsb_addr} <= awaddr;
|
||||
else
|
||||
{ddr_ba, ddr_a, col_addr} <= awaddr;
|
||||
burst_len <= awlen;
|
||||
stat <= WPRE;
|
||||
end else if(arvalid & read_accessible) begin
|
||||
ddr_ras_n <= 1'b0;
|
||||
if(DQ_LEVEL>0)
|
||||
{ddr_ba, ddr_a, col_addr, trash_lsb_addr} <= araddr;
|
||||
else
|
||||
{ddr_ba, ddr_a, col_addr} <= araddr;
|
||||
burst_len <= arlen;
|
||||
stat <= RPRE;
|
||||
end
|
||||
end
|
||||
CLEARDLL: begin
|
||||
ddr_ras_n <= cnt!=8'd0;
|
||||
ddr_cas_n <= cnt!=8'd0;
|
||||
ddr_we_n <= cnt!=8'd0;
|
||||
ddr_a <= cnt!=8'd0 ? DDR_A_DEFAULT : DDR_A_MR_CLEAR_DLL;
|
||||
cnt <= cnt + 8'd1;
|
||||
if(cnt==8'd255) begin
|
||||
init_done <= 1'b1;
|
||||
stat <= IDLE;
|
||||
end
|
||||
end
|
||||
REFRESH: begin
|
||||
cnt <= cnt + 8'd1;
|
||||
if(cnt<8'd1) begin
|
||||
ddr_ras_n <= 1'b0;
|
||||
ddr_we_n <= 1'b0;
|
||||
end else if(cnt<8'd3) begin
|
||||
ddr_ras_n <= 1'b1;
|
||||
ddr_we_n <= 1'b1;
|
||||
end else if(cnt<8'd4) begin
|
||||
ddr_ras_n <= 1'b0;
|
||||
ddr_cas_n <= 1'b0;
|
||||
end else if(cnt<8'd10) begin
|
||||
ddr_ras_n <= 1'b1;
|
||||
ddr_cas_n <= 1'b1;
|
||||
end else if(cnt<8'd11) begin
|
||||
ddr_ras_n <= 1'b0;
|
||||
ddr_cas_n <= 1'b0;
|
||||
end else if(cnt<8'd17) begin
|
||||
ddr_ras_n <= 1'b1;
|
||||
ddr_cas_n <= 1'b1;
|
||||
end else begin
|
||||
stat <= IDLE;
|
||||
end
|
||||
end
|
||||
WPRE: begin
|
||||
ddr_ras_n <= 1'b1;
|
||||
cnt <= 8'd0;
|
||||
stat <= WRITE;
|
||||
end
|
||||
WRITE: begin
|
||||
ddr_a <= ddr_a_col;
|
||||
if(wvalid) begin
|
||||
ddr_cas_n <= 1'b0;
|
||||
ddr_we_n <= 1'b0;
|
||||
col_addr <= col_addr + {{(COL_BITS-2){1'b0}}, 1'b1};
|
||||
if(burst_last | wlast) begin
|
||||
cnt <= '0;
|
||||
stat <= WRESP;
|
||||
end else begin
|
||||
cnt <= cnt + 8'd1;
|
||||
end
|
||||
end else begin
|
||||
ddr_cas_n <= 1'b1;
|
||||
ddr_we_n <= 1'b1;
|
||||
end
|
||||
end
|
||||
WRESP: begin
|
||||
ddr_cas_n <= 1'b1;
|
||||
ddr_we_n <= 1'b1;
|
||||
cnt <= cnt + 8'd1;
|
||||
if(bready)
|
||||
stat <= WWAIT;
|
||||
end
|
||||
WWAIT: begin
|
||||
cnt <= cnt + 8'd1;
|
||||
if(cnt>=tW2I)
|
||||
stat <= IDLE;
|
||||
end
|
||||
RPRE: begin
|
||||
ddr_ras_n <= 1'b1;
|
||||
cnt <= 8'd0;
|
||||
stat <= READ;
|
||||
end
|
||||
READ: begin
|
||||
ddr_cas_n <= 1'b0;
|
||||
ddr_a <= ddr_a_col;
|
||||
col_addr <= col_addr + {{(COL_BITS-2){1'b0}}, 1'b1};
|
||||
if(burst_last) begin
|
||||
cnt <= '0;
|
||||
stat <= RRESP;
|
||||
end else begin
|
||||
cnt <= cnt + 8'd1;
|
||||
end
|
||||
end
|
||||
RRESP: begin
|
||||
ddr_cas_n <= 1'b1;
|
||||
cnt <= cnt + 8'd1;
|
||||
if(read_respdone)
|
||||
stat <= RWAIT;
|
||||
end
|
||||
RWAIT: begin
|
||||
cnt <= cnt + 8'd1;
|
||||
if(cnt>=tR2I)
|
||||
stat <= IDLE;
|
||||
end
|
||||
default: stat <= IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// output enable generate
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
output_enable <= 1'b0;
|
||||
output_enable_d1 <= 1'b0;
|
||||
output_enable_d2 <= 1'b0;
|
||||
end else begin
|
||||
output_enable <= stat==WRITE || output_enable_d1 || output_enable_d2;
|
||||
output_enable_d1 <= stat==WRITE;
|
||||
output_enable_d2 <= output_enable_d1;
|
||||
end
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// output data latches --- stage A
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
o_v_a <= 1'b0;
|
||||
{o_dh_a, o_dl_a} <= '0;
|
||||
end else begin
|
||||
o_v_a <= (stat==WRITE && wvalid);
|
||||
{o_dh_a, o_dl_a} <= wdata;
|
||||
end
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// output data latches --- stage B
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
o_v_b <= 1'b0;
|
||||
o_dh_b <= '0;
|
||||
end else begin
|
||||
o_v_b <= o_v_a;
|
||||
o_dh_b <= o_dh_a;
|
||||
end
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// dq and dqs generate for output (write)
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge clk2) begin
|
||||
if(~aclk) begin
|
||||
o_dqs_c <= 1'b0;
|
||||
o_d_c <= o_v_a ? o_dl_a : '0;
|
||||
end else begin
|
||||
o_dqs_c <= o_v_b;
|
||||
o_d_c <= o_v_b ? o_dh_b : '0;
|
||||
end
|
||||
end
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// dq delay for output (write)
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge clk)
|
||||
o_d_d <= o_d_c;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// dq sampling for input (read)
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge clk2) begin
|
||||
i_dqs_c <= ddr_dqs;
|
||||
i_d_c <= ddr_dq;
|
||||
end
|
||||
|
||||
always @ (posedge clk2)
|
||||
if(i_dqs_c)
|
||||
i_d_d <= {ddr_dq, i_d_c};
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
{i_v_a, i_v_b, i_v_c, i_v_d} <= '0;
|
||||
{i_l_a, i_l_b, i_l_c, i_l_d} <= '0;
|
||||
end else begin
|
||||
i_v_a <= stat==READ ? 1'b1 : 1'b0;
|
||||
i_l_a <= burst_last;
|
||||
i_v_b <= i_v_a;
|
||||
i_l_b <= i_l_a & i_v_a;
|
||||
i_v_c <= i_v_b;
|
||||
i_l_c <= i_l_b;
|
||||
i_v_d <= i_v_c;
|
||||
i_l_d <= i_l_c;
|
||||
end
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
i_v_e <= 1'b0;
|
||||
i_l_e <= 1'b0;
|
||||
i_d_e <= '0;
|
||||
end else begin
|
||||
i_v_e <= i_v_d;
|
||||
i_l_e <= i_l_d;
|
||||
i_d_e <= i_d_d;
|
||||
end
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// data buffer for read
|
||||
// -------------------------------------------------------------------------------------
|
||||
generate if(READ_BUFFER) begin
|
||||
SyncFIFO #(
|
||||
.AWIDTH ( 10 ),
|
||||
.DWIDTH ( 1 + (8<<DQ_LEVEL) )
|
||||
) read_buffer_i (
|
||||
.rstn ( aresetn ),
|
||||
.clk ( aclk ),
|
||||
.emptyn ( ),
|
||||
.itvalid ( i_v_e ),
|
||||
.itready ( ),
|
||||
.itdata ( {i_l_e, i_d_e} ),
|
||||
.otvalid ( rvalid ),
|
||||
.otready ( rready ),
|
||||
.otdata ( {rlast, rdata} )
|
||||
);
|
||||
assign read_accessible = ~rvalid;
|
||||
assign read_respdone = rvalid;
|
||||
end else begin
|
||||
assign rvalid = i_v_e;
|
||||
assign rlast = i_l_e;
|
||||
assign rdata = i_d_e;
|
||||
assign read_accessible = 1'b1;
|
||||
assign read_respdone = i_l_e;
|
||||
end endgenerate
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Simple stream-FIFO
|
||||
// --------------------------------------------------------------------------
|
||||
module SyncFIFO #(
|
||||
parameter AWIDTH = 10,
|
||||
parameter DWIDTH = 8
|
||||
)(
|
||||
input wire rstn,
|
||||
input wire clk,
|
||||
|
||||
output wire emptyn,
|
||||
|
||||
input wire itvalid,
|
||||
output wire itready,
|
||||
input wire [DWIDTH-1:0] itdata,
|
||||
|
||||
output wire otvalid,
|
||||
input wire otready,
|
||||
output wire [DWIDTH-1:0] otdata
|
||||
);
|
||||
|
||||
localparam [AWIDTH-1:0] ONE = 1;
|
||||
reg [AWIDTH-1:0] wpt, rpt;
|
||||
reg dvalid, valid;
|
||||
reg [DWIDTH-1:0] datareg;
|
||||
|
||||
wire rreq;
|
||||
wire [DWIDTH-1:0] rdata;
|
||||
|
||||
assign emptyn = rpt != wpt;
|
||||
|
||||
assign itready = rpt != (wpt+1);
|
||||
assign otvalid = valid | dvalid;
|
||||
assign rreq = emptyn & ( otready | ~otvalid );
|
||||
assign otdata = dvalid ? rdata : datareg;
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn)
|
||||
wpt <= 0;
|
||||
else if(itvalid & itready)
|
||||
wpt <= wpt + ONE;
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn)
|
||||
rpt <= 0;
|
||||
else if(rreq & emptyn)
|
||||
rpt <= rpt + ONE;
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
dvalid <= 1'b0;
|
||||
valid <= 1'b0;
|
||||
datareg <= 0;
|
||||
end else begin
|
||||
dvalid <= rreq;
|
||||
if(dvalid)
|
||||
datareg <= rdata;
|
||||
if(otready)
|
||||
valid <= 1'b0;
|
||||
else if(dvalid)
|
||||
valid <= 1'b1;
|
||||
end
|
||||
|
||||
SyncRAM #(
|
||||
.DWIDTH ( DWIDTH ),
|
||||
.AWIDTH ( AWIDTH )
|
||||
) ram_for_fifo (
|
||||
.clk ( clk ),
|
||||
.wen ( itvalid ),
|
||||
.waddr ( wpt ),
|
||||
.wdata ( itdata ),
|
||||
.raddr ( rpt ),
|
||||
.rdata ( rdata )
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Simple Dual Port RAM
|
||||
// --------------------------------------------------------------------------
|
||||
module SyncRAM #(
|
||||
parameter AWIDTH = 10,
|
||||
parameter DWIDTH = 32
|
||||
)(
|
||||
input logic clk,
|
||||
input logic wen,
|
||||
input logic [AWIDTH-1:0] waddr,
|
||||
input logic [DWIDTH-1:0] wdata,
|
||||
input logic [AWIDTH-1:0] raddr,
|
||||
output logic [DWIDTH-1:0] rdata
|
||||
);
|
||||
|
||||
reg [DWIDTH-1:0] mem [(1<<AWIDTH)];
|
||||
|
||||
always @ (posedge clk)
|
||||
if(wen)
|
||||
mem[waddr] <= wdata;
|
||||
|
||||
always @ (posedge clk)
|
||||
rdata <= mem[raddr];
|
||||
|
||||
endmodule
|
BIN
UartSession.exe
Normal file
BIN
UartSession.exe
Normal file
Binary file not shown.
115
example-selftest/IP/pll.v
Normal file
115
example-selftest/IP/pll.v
Normal file
@ -0,0 +1,115 @@
|
||||
`timescale 1 ns / 1 ns
|
||||
|
||||
// synopsys translate_on
|
||||
module pll (
|
||||
input wire inclk0,
|
||||
output wire c0,
|
||||
output wire locked
|
||||
);
|
||||
|
||||
wire [4:0] sub_wire0;
|
||||
wire sub_wire2;
|
||||
wire [0:0] sub_wire5 = 1'h0;
|
||||
wire [0:0] sub_wire1 = sub_wire0[0:0];
|
||||
assign c0 = sub_wire1;
|
||||
assign locked = sub_wire2;
|
||||
wire sub_wire3 = inclk0;
|
||||
wire [1:0] sub_wire4 = {sub_wire5, sub_wire3};
|
||||
|
||||
altpll altpll_component (
|
||||
.inclk (sub_wire4),
|
||||
.clk (sub_wire0),
|
||||
.locked (sub_wire2),
|
||||
.activeclock (),
|
||||
.areset (1'b0),
|
||||
.clkbad (),
|
||||
.clkena ({6{1'b1}}),
|
||||
.clkloss (),
|
||||
.clkswitch (1'b0),
|
||||
.configupdate (1'b0),
|
||||
.enable0 (),
|
||||
.enable1 (),
|
||||
.extclk (),
|
||||
.extclkena ({4{1'b1}}),
|
||||
.fbin (1'b1),
|
||||
.fbmimicbidir (),
|
||||
.fbout (),
|
||||
.fref (),
|
||||
.icdrclk (),
|
||||
.pfdena (1'b1),
|
||||
.phasecounterselect ({4{1'b1}}),
|
||||
.phasedone (),
|
||||
.phasestep (1'b1),
|
||||
.phaseupdown (1'b1),
|
||||
.pllena (1'b1),
|
||||
.scanaclr (1'b0),
|
||||
.scanclk (1'b0),
|
||||
.scanclkena (1'b1),
|
||||
.scandata (1'b0),
|
||||
.scandataout (),
|
||||
.scandone (),
|
||||
.scanread (1'b0),
|
||||
.scanwrite (1'b0),
|
||||
.sclkout0 (),
|
||||
.sclkout1 (),
|
||||
.vcooverrange (),
|
||||
.vcounderrange ());
|
||||
defparam
|
||||
altpll_component.bandwidth_type = "AUTO",
|
||||
altpll_component.clk0_divide_by = 1,
|
||||
altpll_component.clk0_duty_cycle = 50,
|
||||
altpll_component.clk0_multiply_by = 6,
|
||||
altpll_component.clk0_phase_shift = "0",
|
||||
altpll_component.compensate_clock = "CLK0",
|
||||
altpll_component.inclk0_input_frequency = 20000,
|
||||
altpll_component.intended_device_family = "Cyclone IV E",
|
||||
altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll",
|
||||
altpll_component.lpm_type = "altpll",
|
||||
altpll_component.operation_mode = "NORMAL",
|
||||
altpll_component.pll_type = "AUTO",
|
||||
altpll_component.port_activeclock = "PORT_UNUSED",
|
||||
altpll_component.port_areset = "PORT_UNUSED",
|
||||
altpll_component.port_clkbad0 = "PORT_UNUSED",
|
||||
altpll_component.port_clkbad1 = "PORT_UNUSED",
|
||||
altpll_component.port_clkloss = "PORT_UNUSED",
|
||||
altpll_component.port_clkswitch = "PORT_UNUSED",
|
||||
altpll_component.port_configupdate = "PORT_UNUSED",
|
||||
altpll_component.port_fbin = "PORT_UNUSED",
|
||||
altpll_component.port_inclk0 = "PORT_USED",
|
||||
altpll_component.port_inclk1 = "PORT_UNUSED",
|
||||
altpll_component.port_locked = "PORT_USED",
|
||||
altpll_component.port_pfdena = "PORT_UNUSED",
|
||||
altpll_component.port_phasecounterselect = "PORT_UNUSED",
|
||||
altpll_component.port_phasedone = "PORT_UNUSED",
|
||||
altpll_component.port_phasestep = "PORT_UNUSED",
|
||||
altpll_component.port_phaseupdown = "PORT_UNUSED",
|
||||
altpll_component.port_pllena = "PORT_UNUSED",
|
||||
altpll_component.port_scanaclr = "PORT_UNUSED",
|
||||
altpll_component.port_scanclk = "PORT_UNUSED",
|
||||
altpll_component.port_scanclkena = "PORT_UNUSED",
|
||||
altpll_component.port_scandata = "PORT_UNUSED",
|
||||
altpll_component.port_scandataout = "PORT_UNUSED",
|
||||
altpll_component.port_scandone = "PORT_UNUSED",
|
||||
altpll_component.port_scanread = "PORT_UNUSED",
|
||||
altpll_component.port_scanwrite = "PORT_UNUSED",
|
||||
altpll_component.port_clk0 = "PORT_USED",
|
||||
altpll_component.port_clk1 = "PORT_UNUSED",
|
||||
altpll_component.port_clk2 = "PORT_UNUSED",
|
||||
altpll_component.port_clk3 = "PORT_UNUSED",
|
||||
altpll_component.port_clk4 = "PORT_UNUSED",
|
||||
altpll_component.port_clk5 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena0 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena1 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena2 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena3 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena4 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena5 = "PORT_UNUSED",
|
||||
altpll_component.port_extclk0 = "PORT_UNUSED",
|
||||
altpll_component.port_extclk1 = "PORT_UNUSED",
|
||||
altpll_component.port_extclk2 = "PORT_UNUSED",
|
||||
altpll_component.port_extclk3 = "PORT_UNUSED",
|
||||
altpll_component.self_reset_on_loss_lock = "OFF",
|
||||
altpll_component.width_clock = 5;
|
||||
|
||||
|
||||
endmodule
|
113
example-selftest/RTL/axi_self_test_master.sv
Normal file
113
example-selftest/RTL/axi_self_test_master.sv
Normal file
@ -0,0 +1,113 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
module axi_self_test_master #(
|
||||
parameter A_WIDTH_TEST = 26,
|
||||
parameter A_WIDTH = 26,
|
||||
parameter D_WIDTH = 16,
|
||||
parameter D_LEVEL = 1,
|
||||
parameter [7:0] WBURST_LEN = 8'd7,
|
||||
parameter [7:0] RBURST_LEN = 8'd7
|
||||
)(
|
||||
input wire aresetn,
|
||||
input wire aclk,
|
||||
output wire awvalid,
|
||||
input wire awready,
|
||||
output reg [A_WIDTH-1:0] awaddr,
|
||||
output wire [ 7:0] awlen,
|
||||
output wire wvalid,
|
||||
input wire wready,
|
||||
output wire wlast,
|
||||
output wire [D_WIDTH-1:0] wdata,
|
||||
input wire bvalid,
|
||||
output wire bready,
|
||||
output wire arvalid,
|
||||
input wire arready,
|
||||
output reg [A_WIDTH-1:0] araddr,
|
||||
output wire [ 7:0] arlen,
|
||||
input wire rvalid,
|
||||
output wire rready,
|
||||
input wire rlast,
|
||||
input wire [D_WIDTH-1:0] rdata,
|
||||
output reg error,
|
||||
output reg [ 15:0] error_cnt
|
||||
);
|
||||
|
||||
wire aw_end;
|
||||
reg awaddr_carry;
|
||||
reg [7:0] w_cnt;
|
||||
enum logic [2:0] {INIT, AW, W, B, AR, R} stat;
|
||||
|
||||
generate if(A_WIDTH_TEST<A_WIDTH)
|
||||
assign aw_end = awaddr[A_WIDTH_TEST];
|
||||
else
|
||||
assign aw_end = awaddr_carry;
|
||||
endgenerate
|
||||
|
||||
assign awvalid = stat==AW;
|
||||
assign awlen = WBURST_LEN;
|
||||
assign wvalid = stat==W;
|
||||
assign wlast = w_cnt==WBURST_LEN;
|
||||
assign wdata = awaddr;
|
||||
assign bready = 1'b1;
|
||||
assign arvalid = stat==AR;
|
||||
assign arlen = RBURST_LEN;
|
||||
assign rready = 1'b1;
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
{awaddr_carry, awaddr} <= '0;
|
||||
w_cnt <= 8'd0;
|
||||
araddr <= '0;
|
||||
stat <= INIT;
|
||||
end else begin
|
||||
case(stat)
|
||||
INIT: begin
|
||||
{awaddr_carry, awaddr} <= '0;
|
||||
w_cnt <= 8'd0;
|
||||
araddr <= '0;
|
||||
stat <= AW;
|
||||
end
|
||||
AW: if(awready) begin
|
||||
w_cnt <= 8'd0;
|
||||
stat <= W;
|
||||
end
|
||||
W: if(wready) begin
|
||||
{awaddr_carry, awaddr} <= {awaddr_carry, awaddr} + (1<<D_LEVEL);
|
||||
w_cnt <= w_cnt + 8'd1;
|
||||
if(wlast)
|
||||
stat <= B;
|
||||
end
|
||||
B: if(bvalid) begin
|
||||
stat <= aw_end ? AR : AW;
|
||||
end
|
||||
AR: if(arready) begin
|
||||
stat <= R;
|
||||
end
|
||||
R: if(rvalid) begin
|
||||
automatic logic [A_WIDTH:0] araddr_next;
|
||||
araddr_next = araddr + (1<<D_LEVEL);
|
||||
araddr <= araddr_next[A_WIDTH-1:0];
|
||||
if(rlast) begin
|
||||
stat <= AR;
|
||||
if(araddr_next[A_WIDTH_TEST])
|
||||
araddr <= '0;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// read and write mismatch detect
|
||||
// ------------------------------------------------------------
|
||||
wire [D_WIDTH-1:0] rdata_idle = araddr;
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
error <= 1'b0;
|
||||
error_cnt <= 16'd0;
|
||||
end else begin
|
||||
error <= rvalid && rready && rdata!=rdata_idle;
|
||||
if(error)
|
||||
error_cnt <= error_cnt + 16'd1;
|
||||
end
|
||||
|
||||
endmodule
|
158
example-selftest/RTL/top.sv
Normal file
158
example-selftest/RTL/top.sv
Normal file
@ -0,0 +1,158 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
module top(
|
||||
input wire clk50m,
|
||||
|
||||
output wire ddr_ck_p, ddr_ck_n,
|
||||
output wire ddr_cke,
|
||||
output wire ddr_cs_n, ddr_ras_n, ddr_cas_n, ddr_we_n,
|
||||
output wire [ 1:0] ddr_ba,
|
||||
output wire [12:0] ddr_a,
|
||||
inout [ 7:0] ddr_dq,
|
||||
inout [ 0:0] ddr_dqs,
|
||||
output wire [ 0:0] ddr_dm,
|
||||
|
||||
output wire error,
|
||||
output wire [15:0] error_cnt
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// DDR-SDRAM parameters
|
||||
// -------------------------------------------------------------------------------------
|
||||
localparam BA_BITS = 2;
|
||||
localparam ROW_BITS = 13;
|
||||
localparam COL_BITS = 11;
|
||||
localparam DQ_LEVEL = 1;
|
||||
localparam DQ_BITS = (4<<DQ_LEVEL);
|
||||
localparam DQS_BITS = ((1<<DQ_LEVEL)+1)/2;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// meta AXI4 parameters
|
||||
// -------------------------------------------------------------------------------------
|
||||
localparam A_WIDTH = BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-1;
|
||||
localparam D_WIDTH = (8<<DQ_LEVEL);
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// driving clock and reset
|
||||
// -------------------------------------------------------------------------------------
|
||||
wire clk300m;
|
||||
wire rstn;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// meta AXI4 interface
|
||||
// -------------------------------------------------------------------------------------
|
||||
wire aresetn;
|
||||
wire aclk;
|
||||
wire awvalid;
|
||||
wire awready;
|
||||
wire [A_WIDTH-1:0] awaddr;
|
||||
wire [ 7:0] awlen;
|
||||
wire wvalid;
|
||||
wire wready;
|
||||
wire wlast;
|
||||
wire [D_WIDTH-1:0] wdata;
|
||||
wire bvalid;
|
||||
wire bready;
|
||||
wire arvalid;
|
||||
wire arready;
|
||||
wire [A_WIDTH-1:0] araddr;
|
||||
wire [ 7:0] arlen;
|
||||
wire rvalid;
|
||||
wire rready;
|
||||
wire rlast;
|
||||
wire [D_WIDTH-1:0] rdata;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// PLL for generating 300MHz clock
|
||||
// -------------------------------------------------------------------------------------
|
||||
pll pll_i(
|
||||
.inclk0 ( clk50m ),
|
||||
.c0 ( clk300m ),
|
||||
.locked ( rstn )
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// meta AXI4 master for testing
|
||||
// -------------------------------------------------------------------------------------
|
||||
axi_self_test_master #(
|
||||
.A_WIDTH ( A_WIDTH ),
|
||||
.A_WIDTH_TEST( A_WIDTH ),
|
||||
.D_WIDTH ( D_WIDTH ),
|
||||
.D_LEVEL ( DQ_LEVEL ),
|
||||
.WBURST_LEN ( 8'd15 ),
|
||||
.RBURST_LEN ( 8'd15 )
|
||||
) axi_m_i (
|
||||
.aresetn ( aresetn ),
|
||||
.aclk ( aclk ),
|
||||
.awvalid ( awvalid ),
|
||||
.awready ( awready ),
|
||||
.awaddr ( awaddr ),
|
||||
.awlen ( awlen ),
|
||||
.wvalid ( wvalid ),
|
||||
.wready ( wready ),
|
||||
.wlast ( wlast ),
|
||||
.wdata ( wdata ),
|
||||
.bvalid ( bvalid ),
|
||||
.bready ( bready ),
|
||||
.arvalid ( arvalid ),
|
||||
.arready ( arready ),
|
||||
.araddr ( araddr ),
|
||||
.arlen ( arlen ),
|
||||
.rvalid ( rvalid ),
|
||||
.rready ( rready ),
|
||||
.rlast ( rlast ),
|
||||
.rdata ( rdata ),
|
||||
.error ( error ),
|
||||
.error_cnt ( error_cnt )
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// DDR-SDRAM controller
|
||||
// -------------------------------------------------------------------------------------
|
||||
ddr_sdram_ctrl #(
|
||||
.READ_BUFFER ( 1 ),
|
||||
.BA_BITS ( BA_BITS ),
|
||||
.ROW_BITS ( ROW_BITS ),
|
||||
.COL_BITS ( COL_BITS ),
|
||||
.DQ_LEVEL ( DQ_LEVEL ), // x8
|
||||
.tREFC ( 10'd512 ),
|
||||
.tW2I ( 8'd7 ),
|
||||
.tR2I ( 8'd7 )
|
||||
) ddr_ctrl_i(
|
||||
.rstn ( rstn ),
|
||||
.clk ( clk300m ),
|
||||
.aresetn ( aresetn ),
|
||||
.aclk ( aclk ),
|
||||
.awvalid ( awvalid ),
|
||||
.awready ( awready ),
|
||||
.awaddr ( awaddr ),
|
||||
.awlen ( awlen ),
|
||||
.wvalid ( wvalid ),
|
||||
.wready ( wready ),
|
||||
.wlast ( wlast ),
|
||||
.wdata ( wdata ),
|
||||
.bvalid ( bvalid ),
|
||||
.bready ( bready ),
|
||||
.arvalid ( arvalid ),
|
||||
.arready ( arready ),
|
||||
.araddr ( araddr ),
|
||||
.arlen ( arlen ),
|
||||
.rvalid ( rvalid ),
|
||||
.rready ( rready ),
|
||||
.rlast ( rlast ),
|
||||
.rdata ( rdata ),
|
||||
.ddr_ck_p ( ddr_ck_p ),
|
||||
.ddr_ck_n ( ddr_ck_n ),
|
||||
.ddr_cke ( ddr_cke ),
|
||||
.ddr_cs_n ( ddr_cs_n ),
|
||||
.ddr_ras_n ( ddr_ras_n ),
|
||||
.ddr_cas_n ( ddr_cas_n ),
|
||||
.ddr_we_n ( ddr_we_n ),
|
||||
.ddr_ba ( ddr_ba ),
|
||||
.ddr_a ( ddr_a ),
|
||||
.ddr_dq ( ddr_dq ),
|
||||
.ddr_dqs ( ddr_dqs ),
|
||||
.ddr_dm ( ddr_dm )
|
||||
);
|
||||
|
||||
endmodule
|
327
example-selftest/SignalTap/stp1.stp
Normal file
327
example-selftest/SignalTap/stp1.stp
Normal file
File diff suppressed because one or more lines are too long
30
example-selftest/ddr_test.qpf
Normal file
30
example-selftest/ddr_test.qpf
Normal file
@ -0,0 +1,30 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Copyright (C) 1991-2013 Altera Corporation
|
||||
# Your use of Altera Corporation's design tools, logic functions
|
||||
# and other software and tools, and its AMPP partner logic
|
||||
# functions, and any output files from any of the foregoing
|
||||
# (including device programming or simulation files), and any
|
||||
# associated documentation or information are expressly subject
|
||||
# to the terms and conditions of the Altera Program License
|
||||
# Subscription Agreement, Altera MegaCore Function License
|
||||
# Agreement, or other applicable license agreement, including,
|
||||
# without limitation, that your use is for the sole purpose of
|
||||
# programming logic devices manufactured by Altera and sold by
|
||||
# Altera or its authorized distributors. Please refer to the
|
||||
# applicable agreement for further details.
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Quartus II 64-Bit
|
||||
# Version 13.1.0 Build 162 10/23/2013 SJ Full Version
|
||||
# Date created = 21:02:52 January 17, 2021
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
|
||||
QUARTUS_VERSION = "13.1"
|
||||
DATE = "21:02:52 January 17, 2021"
|
||||
|
||||
# Revisions
|
||||
|
||||
PROJECT_REVISION = "ddr_test"
|
179
example-selftest/ddr_test.qsf
Normal file
179
example-selftest/ddr_test.qsf
Normal file
@ -0,0 +1,179 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Copyright (C) 1991-2013 Altera Corporation
|
||||
# Your use of Altera Corporation's design tools, logic functions
|
||||
# and other software and tools, and its AMPP partner logic
|
||||
# functions, and any output files from any of the foregoing
|
||||
# (including device programming or simulation files), and any
|
||||
# associated documentation or information are expressly subject
|
||||
# to the terms and conditions of the Altera Program License
|
||||
# Subscription Agreement, Altera MegaCore Function License
|
||||
# Agreement, or other applicable license agreement, including,
|
||||
# without limitation, that your use is for the sole purpose of
|
||||
# programming logic devices manufactured by Altera and sold by
|
||||
# Altera or its authorized distributors. Please refer to the
|
||||
# applicable agreement for further details.
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Quartus II 64-Bit
|
||||
# Version 13.1.0 Build 162 10/23/2013 SJ Full Version
|
||||
# Date created = 21:02:52 January 17, 2021
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Notes:
|
||||
#
|
||||
# 1) The default values for assignments are stored in the file:
|
||||
# ddr_test_assignment_defaults.qdf
|
||||
# If this file doesn't exist, see file:
|
||||
# assignment_defaults.qdf
|
||||
#
|
||||
# 2) Altera recommends that you do not modify this file. This
|
||||
# file is updated automatically by the Quartus II software
|
||||
# and any changes you make may be lost or overwritten.
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
|
||||
|
||||
set_global_assignment -name FAMILY "Cyclone IV E"
|
||||
set_global_assignment -name DEVICE EP4CE6E22C8
|
||||
set_global_assignment -name TOP_LEVEL_ENTITY top
|
||||
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1
|
||||
set_global_assignment -name PROJECT_CREATION_TIME_DATE "21:02:52 JANUARY 17, 2021"
|
||||
set_global_assignment -name LAST_QUARTUS_VERSION 13.1
|
||||
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
|
||||
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
|
||||
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
|
||||
set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
|
||||
set_global_assignment -name NOMINAL_CORE_SUPPLY_VOLTAGE 1.2V
|
||||
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
|
||||
|
||||
set_location_assignment PIN_23 -to clk50m
|
||||
|
||||
set_location_assignment PIN_10 -to ddr_cs_n
|
||||
set_location_assignment PIN_30 -to ddr_ras_n
|
||||
set_location_assignment PIN_31 -to ddr_cas_n
|
||||
set_location_assignment PIN_32 -to ddr_we_n
|
||||
set_location_assignment PIN_86 -to ddr_cke
|
||||
set_location_assignment PIN_85 -to ddr_ck_p
|
||||
set_location_assignment PIN_84 -to ddr_ck_n
|
||||
set_location_assignment PIN_7 -to ddr_ba[0]
|
||||
set_location_assignment PIN_3 -to ddr_ba[1]
|
||||
set_location_assignment PIN_1 -to ddr_a[0]
|
||||
set_location_assignment PIN_144 -to ddr_a[1]
|
||||
set_location_assignment PIN_143 -to ddr_a[2]
|
||||
set_location_assignment PIN_142 -to ddr_a[3]
|
||||
set_location_assignment PIN_106 -to ddr_a[4]
|
||||
set_location_assignment PIN_105 -to ddr_a[5]
|
||||
set_location_assignment PIN_104 -to ddr_a[6]
|
||||
set_location_assignment PIN_103 -to ddr_a[7]
|
||||
set_location_assignment PIN_100 -to ddr_a[8]
|
||||
set_location_assignment PIN_99 -to ddr_a[9]
|
||||
set_location_assignment PIN_2 -to ddr_a[10]
|
||||
set_location_assignment PIN_98 -to ddr_a[11]
|
||||
set_location_assignment PIN_87 -to ddr_a[12]
|
||||
set_location_assignment PIN_83 -to ddr_dm[0]
|
||||
set_location_assignment PIN_80 -to ddr_dqs[0]
|
||||
set_location_assignment PIN_38 -to ddr_dq[0]
|
||||
set_location_assignment PIN_39 -to ddr_dq[1]
|
||||
set_location_assignment PIN_34 -to ddr_dq[2]
|
||||
set_location_assignment PIN_33 -to ddr_dq[3]
|
||||
set_location_assignment PIN_76 -to ddr_dq[4]
|
||||
set_location_assignment PIN_75 -to ddr_dq[5]
|
||||
set_location_assignment PIN_74 -to ddr_dq[6]
|
||||
set_location_assignment PIN_73 -to ddr_dq[7]
|
||||
|
||||
set_location_assignment PIN_42 -to error
|
||||
set_location_assignment PIN_141 -to error_cnt[0]
|
||||
set_location_assignment PIN_138 -to error_cnt[1]
|
||||
set_location_assignment PIN_137 -to error_cnt[2]
|
||||
set_location_assignment PIN_136 -to error_cnt[3]
|
||||
set_location_assignment PIN_135 -to error_cnt[4]
|
||||
set_location_assignment PIN_133 -to error_cnt[5]
|
||||
set_location_assignment PIN_132 -to error_cnt[6]
|
||||
set_location_assignment PIN_129 -to error_cnt[7]
|
||||
set_location_assignment PIN_128 -to error_cnt[8]
|
||||
set_location_assignment PIN_127 -to error_cnt[9]
|
||||
set_location_assignment PIN_126 -to error_cnt[10]
|
||||
set_location_assignment PIN_125 -to error_cnt[11]
|
||||
set_location_assignment PIN_124 -to error_cnt[12]
|
||||
set_location_assignment PIN_121 -to error_cnt[13]
|
||||
set_location_assignment PIN_120 -to error_cnt[14]
|
||||
set_location_assignment PIN_119 -to error_cnt[15]
|
||||
|
||||
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
|
||||
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
|
||||
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
|
||||
set_global_assignment -name ENABLE_SIGNALTAP ON
|
||||
set_global_assignment -name USE_SIGNALTAP_FILE SignalTap/stp1.stp
|
||||
set_global_assignment -name SLD_NODE_CREATOR_ID 110 -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_ENTITY_NAME sld_signaltap -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_RAM_BLOCK_TYPE=AUTO" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_BITS=1" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_INFO=805334528" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_POWER_UP_TRIGGER=0" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_INVERSION_MASK=00000000000000000000000000" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_INVERSION_MASK_LENGTH=26" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_STORAGE_QUALIFIER_INVERSION_MASK_LENGTH=0" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_SEGMENT_SIZE=512" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_ATTRIBUTE_MEM_MODE=OFF" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_STATE_FLOW_USE_GENERATED=0" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_STATE_BITS=11" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_BUFFER_FULL_STOP=1" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_CURRENT_RESOURCE_WIDTH=1" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_LEVEL=1" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_SAMPLE_DEPTH=512" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_IN_ENABLED=0" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_ADVANCED_TRIGGER_ENTITY=basic,1," -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_LEVEL_PIPELINE=1" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_ENABLE_ADVANCED_TRIGGER=0" -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_clk -to "ddr_ctrl:ddr_ctrl_i|clk2" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE RTL/top.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE RTL/axi_self_test_master.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE ../RTL/ddr_sdram_ctrl.sv
|
||||
set_global_assignment -name VERILOG_FILE IP/pll.v
|
||||
set_global_assignment -name SIGNALTAP_FILE SignalTap/stp1.stp
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[0] -to error -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[0] -to ddr_a[0] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[1] -to ddr_a[10] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[2] -to ddr_a[11] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[3] -to ddr_a[12] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[4] -to ddr_a[1] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[5] -to ddr_a[2] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[6] -to ddr_a[3] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[7] -to ddr_a[4] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[8] -to ddr_a[5] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[9] -to ddr_a[6] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[10] -to ddr_a[7] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[11] -to ddr_a[8] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[12] -to ddr_a[9] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[13] -to ddr_ba[0] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[14] -to ddr_ba[1] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[15] -to ddr_cas_n -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[16] -to ddr_ck_p -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[17] -to ddr_cs_n -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[18] -to ddr_ras_n -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[19] -to ddr_we_n -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[20] -to error -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[21] -to error_cnt[0] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[22] -to error_cnt[10] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[23] -to error_cnt[11] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[24] -to error_cnt[12] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[25] -to error_cnt[13] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[26] -to error_cnt[14] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[27] -to error_cnt[15] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[28] -to error_cnt[1] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[29] -to error_cnt[2] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[30] -to error_cnt[3] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[31] -to error_cnt[4] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[32] -to error_cnt[5] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[33] -to error_cnt[6] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[34] -to error_cnt[7] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[35] -to error_cnt[8] -section_id auto_signaltap_0
|
||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[36] -to error_cnt[9] -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_DATA_BITS=37" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_CRC_LOWORD=45013" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_CRC_HIWORD=22477" -section_id auto_signaltap_0
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
||||
set_global_assignment -name SLD_FILE db/stp1_auto_stripped.stp
|
115
example-uart-read-write/IP/pll.v
Normal file
115
example-uart-read-write/IP/pll.v
Normal file
@ -0,0 +1,115 @@
|
||||
`timescale 1 ns / 1 ns
|
||||
|
||||
// synopsys translate_on
|
||||
module pll (
|
||||
input wire inclk0,
|
||||
output wire c0,
|
||||
output wire locked
|
||||
);
|
||||
|
||||
wire [4:0] sub_wire0;
|
||||
wire sub_wire2;
|
||||
wire [0:0] sub_wire5 = 1'h0;
|
||||
wire [0:0] sub_wire1 = sub_wire0[0:0];
|
||||
assign c0 = sub_wire1;
|
||||
assign locked = sub_wire2;
|
||||
wire sub_wire3 = inclk0;
|
||||
wire [1:0] sub_wire4 = {sub_wire5, sub_wire3};
|
||||
|
||||
altpll altpll_component (
|
||||
.inclk (sub_wire4),
|
||||
.clk (sub_wire0),
|
||||
.locked (sub_wire2),
|
||||
.activeclock (),
|
||||
.areset (1'b0),
|
||||
.clkbad (),
|
||||
.clkena ({6{1'b1}}),
|
||||
.clkloss (),
|
||||
.clkswitch (1'b0),
|
||||
.configupdate (1'b0),
|
||||
.enable0 (),
|
||||
.enable1 (),
|
||||
.extclk (),
|
||||
.extclkena ({4{1'b1}}),
|
||||
.fbin (1'b1),
|
||||
.fbmimicbidir (),
|
||||
.fbout (),
|
||||
.fref (),
|
||||
.icdrclk (),
|
||||
.pfdena (1'b1),
|
||||
.phasecounterselect ({4{1'b1}}),
|
||||
.phasedone (),
|
||||
.phasestep (1'b1),
|
||||
.phaseupdown (1'b1),
|
||||
.pllena (1'b1),
|
||||
.scanaclr (1'b0),
|
||||
.scanclk (1'b0),
|
||||
.scanclkena (1'b1),
|
||||
.scandata (1'b0),
|
||||
.scandataout (),
|
||||
.scandone (),
|
||||
.scanread (1'b0),
|
||||
.scanwrite (1'b0),
|
||||
.sclkout0 (),
|
||||
.sclkout1 (),
|
||||
.vcooverrange (),
|
||||
.vcounderrange ());
|
||||
defparam
|
||||
altpll_component.bandwidth_type = "AUTO",
|
||||
altpll_component.clk0_divide_by = 1,
|
||||
altpll_component.clk0_duty_cycle = 50,
|
||||
altpll_component.clk0_multiply_by = 6,
|
||||
altpll_component.clk0_phase_shift = "0",
|
||||
altpll_component.compensate_clock = "CLK0",
|
||||
altpll_component.inclk0_input_frequency = 20000,
|
||||
altpll_component.intended_device_family = "Cyclone IV E",
|
||||
altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll",
|
||||
altpll_component.lpm_type = "altpll",
|
||||
altpll_component.operation_mode = "NORMAL",
|
||||
altpll_component.pll_type = "AUTO",
|
||||
altpll_component.port_activeclock = "PORT_UNUSED",
|
||||
altpll_component.port_areset = "PORT_UNUSED",
|
||||
altpll_component.port_clkbad0 = "PORT_UNUSED",
|
||||
altpll_component.port_clkbad1 = "PORT_UNUSED",
|
||||
altpll_component.port_clkloss = "PORT_UNUSED",
|
||||
altpll_component.port_clkswitch = "PORT_UNUSED",
|
||||
altpll_component.port_configupdate = "PORT_UNUSED",
|
||||
altpll_component.port_fbin = "PORT_UNUSED",
|
||||
altpll_component.port_inclk0 = "PORT_USED",
|
||||
altpll_component.port_inclk1 = "PORT_UNUSED",
|
||||
altpll_component.port_locked = "PORT_USED",
|
||||
altpll_component.port_pfdena = "PORT_UNUSED",
|
||||
altpll_component.port_phasecounterselect = "PORT_UNUSED",
|
||||
altpll_component.port_phasedone = "PORT_UNUSED",
|
||||
altpll_component.port_phasestep = "PORT_UNUSED",
|
||||
altpll_component.port_phaseupdown = "PORT_UNUSED",
|
||||
altpll_component.port_pllena = "PORT_UNUSED",
|
||||
altpll_component.port_scanaclr = "PORT_UNUSED",
|
||||
altpll_component.port_scanclk = "PORT_UNUSED",
|
||||
altpll_component.port_scanclkena = "PORT_UNUSED",
|
||||
altpll_component.port_scandata = "PORT_UNUSED",
|
||||
altpll_component.port_scandataout = "PORT_UNUSED",
|
||||
altpll_component.port_scandone = "PORT_UNUSED",
|
||||
altpll_component.port_scanread = "PORT_UNUSED",
|
||||
altpll_component.port_scanwrite = "PORT_UNUSED",
|
||||
altpll_component.port_clk0 = "PORT_USED",
|
||||
altpll_component.port_clk1 = "PORT_UNUSED",
|
||||
altpll_component.port_clk2 = "PORT_UNUSED",
|
||||
altpll_component.port_clk3 = "PORT_UNUSED",
|
||||
altpll_component.port_clk4 = "PORT_UNUSED",
|
||||
altpll_component.port_clk5 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena0 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena1 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena2 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena3 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena4 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena5 = "PORT_UNUSED",
|
||||
altpll_component.port_extclk0 = "PORT_UNUSED",
|
||||
altpll_component.port_extclk1 = "PORT_UNUSED",
|
||||
altpll_component.port_extclk2 = "PORT_UNUSED",
|
||||
altpll_component.port_extclk3 = "PORT_UNUSED",
|
||||
altpll_component.self_reset_on_loss_lock = "OFF",
|
||||
altpll_component.width_clock = 5;
|
||||
|
||||
|
||||
endmodule
|
138
example-uart-read-write/RTL/axis2uarttx.sv
Normal file
138
example-uart-read-write/RTL/axis2uarttx.sv
Normal file
@ -0,0 +1,138 @@
|
||||
|
||||
module axis2uarttx #(
|
||||
parameter CLK_DIV = 434,
|
||||
parameter DATA_WIDTH = 32,
|
||||
parameter FIFO_ASIZE = 8
|
||||
) (
|
||||
// AXI-stream (slave) side
|
||||
input logic aclk, aresetn,
|
||||
input logic tvalid, tlast,
|
||||
output logic tready,
|
||||
input logic [DATA_WIDTH-1:0] tdata,
|
||||
// UART TX signal
|
||||
output logic uart_tx
|
||||
);
|
||||
localparam TX_WIDTH = (DATA_WIDTH+3) / 4;
|
||||
|
||||
function automatic logic [7:0] hex2ascii(input [3:0] hex);
|
||||
return (hex<4'hA) ? (hex+"0") : (hex+("A"-8'hA)) ;
|
||||
endfunction
|
||||
|
||||
logic uart_txb;
|
||||
logic [FIFO_ASIZE-1:0] fifo_rpt='0, fifo_wpt='0;
|
||||
wire [FIFO_ASIZE-1:0] fifo_wpt_next = fifo_wpt + {{(FIFO_ASIZE-1){1'b0}}, 1'b1};
|
||||
wire [FIFO_ASIZE-1:0] fifo_rpt_next = fifo_rpt + {{(FIFO_ASIZE-1){1'b0}}, 1'b1};
|
||||
logic [31:0] cyccnt=0, hexcnt=0, txcnt=0;
|
||||
logic [ 7:0] txshift = '1;
|
||||
logic fifo_tlast;
|
||||
logic [DATA_WIDTH-1:0] fifo_data;
|
||||
logic endofline = 1'b0;
|
||||
logic [TX_WIDTH*4-1:0] data='0;
|
||||
wire emptyn = (fifo_rpt != fifo_wpt);
|
||||
assign tready = (fifo_rpt != fifo_wpt_next) & aresetn;
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn)
|
||||
uart_tx <= 1'b1;
|
||||
else begin
|
||||
uart_tx <= uart_txb;
|
||||
end
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn)
|
||||
fifo_wpt <= '0;
|
||||
else begin
|
||||
if(tvalid & tready) fifo_wpt <= fifo_wpt_next;
|
||||
end
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn)
|
||||
cyccnt <= 0;
|
||||
else
|
||||
cyccnt <= (cyccnt<CLK_DIV-1) ? cyccnt+1 : 0;
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
fifo_rpt <= '0;
|
||||
endofline <= 1'b0;
|
||||
data <= '0;
|
||||
uart_txb <= 1'b1;
|
||||
txshift <= '1;
|
||||
txcnt <= 0;
|
||||
hexcnt <= 0;
|
||||
end else begin
|
||||
if( hexcnt>(1+TX_WIDTH) ) begin
|
||||
uart_txb <= 1'b1;
|
||||
endofline <= fifo_tlast;
|
||||
data <= '0;
|
||||
data[DATA_WIDTH-1:0] <= fifo_data;
|
||||
hexcnt <= hexcnt-1;
|
||||
end else if(hexcnt>0 || txcnt>0) begin
|
||||
if(cyccnt==CLK_DIV-1) begin
|
||||
if(txcnt>0) begin
|
||||
{txshift, uart_txb} <= {1'b1, txshift};
|
||||
txcnt <= txcnt-1;
|
||||
end else begin
|
||||
uart_txb <= 1'b0;
|
||||
hexcnt <= hexcnt-1;
|
||||
if(hexcnt>1)
|
||||
txshift <= hex2ascii(data[(hexcnt-2)*4+:4]);
|
||||
else if(endofline)
|
||||
txshift <= "\n";
|
||||
else
|
||||
txshift <= " ";
|
||||
txcnt <= 11;
|
||||
end
|
||||
end
|
||||
end else if(emptyn) begin
|
||||
uart_txb <= 1'b1;
|
||||
hexcnt <= 2 + TX_WIDTH;
|
||||
txcnt <= 0;
|
||||
fifo_rpt <= fifo_rpt_next;
|
||||
end
|
||||
end
|
||||
|
||||
ram_for_axi_stream_to_uart_tx_fifo #(
|
||||
.ADDR_LEN ( FIFO_ASIZE ),
|
||||
.DATA_LEN ( DATA_WIDTH + 1 )
|
||||
) ram_for_uart_tx_fifo_inst (
|
||||
.clk ( aclk ),
|
||||
.wr_req ( tvalid & tready ),
|
||||
.wr_addr ( fifo_wpt ),
|
||||
.wr_data ( {tlast, tdata} ),
|
||||
.rd_addr ( fifo_rpt ),
|
||||
.rd_data ( {fifo_tlast,fifo_data} )
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
module ram_for_axi_stream_to_uart_tx_fifo #(
|
||||
parameter ADDR_LEN = 12,
|
||||
parameter DATA_LEN = 8
|
||||
) (
|
||||
input logic clk,
|
||||
input logic wr_req,
|
||||
input logic [ADDR_LEN-1:0] rd_addr, wr_addr,
|
||||
output logic [DATA_LEN-1:0] rd_data,
|
||||
input logic [DATA_LEN-1:0] wr_data
|
||||
);
|
||||
|
||||
localparam RAM_SIZE = (1<<ADDR_LEN);
|
||||
|
||||
logic [DATA_LEN-1:0] mem [RAM_SIZE];
|
||||
|
||||
initial rd_data = 0;
|
||||
|
||||
always @ (posedge clk)
|
||||
rd_data <= mem[rd_addr];
|
||||
|
||||
always @ (posedge clk)
|
||||
if(wr_req)
|
||||
mem[wr_addr] <= wr_data;
|
||||
|
||||
endmodule
|
153
example-uart-read-write/RTL/top.sv
Normal file
153
example-uart-read-write/RTL/top.sv
Normal file
@ -0,0 +1,153 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
module top(
|
||||
input wire clk50m,
|
||||
|
||||
output wire uart_tx,
|
||||
input wire uart_rx,
|
||||
|
||||
output wire ddr_ck_p, ddr_ck_n,
|
||||
output wire ddr_cke,
|
||||
output wire ddr_cs_n, ddr_ras_n, ddr_cas_n, ddr_we_n,
|
||||
output wire [ 1:0] ddr_ba,
|
||||
output wire [12:0] ddr_a,
|
||||
output wire [ 0:0] ddr_dm,
|
||||
inout [ 0:0] ddr_dqs,
|
||||
inout [ 7:0] ddr_dq
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// DDR-SDRAM parameters
|
||||
// -------------------------------------------------------------------------------------
|
||||
localparam BA_BITS = 2;
|
||||
localparam ROW_BITS = 13;
|
||||
localparam COL_BITS = 11;
|
||||
localparam DQ_LEVEL = 1;
|
||||
localparam DQ_BITS = (4<<DQ_LEVEL);
|
||||
localparam DQS_BITS = ((1<<DQ_LEVEL)+1)/2;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// meta AXI4 parameters
|
||||
// -------------------------------------------------------------------------------------
|
||||
localparam A_WIDTH = BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-1;
|
||||
localparam D_WIDTH = (8<<DQ_LEVEL);
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// driving clock and reset
|
||||
// -------------------------------------------------------------------------------------
|
||||
wire clk300m;
|
||||
wire rstn;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// meta AXI4 interface
|
||||
// -------------------------------------------------------------------------------------
|
||||
wire aresetn;
|
||||
wire aclk;
|
||||
wire awvalid;
|
||||
wire awready;
|
||||
wire [A_WIDTH-1:0] awaddr;
|
||||
wire [ 7:0] awlen;
|
||||
wire wvalid;
|
||||
wire wready;
|
||||
wire wlast;
|
||||
wire [D_WIDTH-1:0] wdata;
|
||||
wire bvalid;
|
||||
wire bready;
|
||||
wire arvalid;
|
||||
wire arready;
|
||||
wire [A_WIDTH-1:0] araddr;
|
||||
wire [ 7:0] arlen;
|
||||
wire rvalid;
|
||||
wire rready;
|
||||
wire rlast;
|
||||
wire [D_WIDTH-1:0] rdata;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// PLL for generating 300MHz clock
|
||||
// -------------------------------------------------------------------------------------
|
||||
pll pll_i(
|
||||
.inclk0 ( clk50m ),
|
||||
.c0 ( clk300m ),
|
||||
.locked ( rstn )
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// meta AXI4 master for testing
|
||||
// -------------------------------------------------------------------------------------
|
||||
uart2axi4 #(
|
||||
.A_WIDTH ( A_WIDTH )
|
||||
) uart_axi_i (
|
||||
.aresetn ( aresetn ),
|
||||
.aclk ( aclk ),
|
||||
.awvalid ( awvalid ),
|
||||
.awready ( awready ),
|
||||
.awaddr ( awaddr ),
|
||||
.awlen ( awlen ),
|
||||
.wvalid ( wvalid ),
|
||||
.wready ( wready ),
|
||||
.wlast ( wlast ),
|
||||
.wdata ( wdata ),
|
||||
.bvalid ( bvalid ),
|
||||
.bready ( bready ),
|
||||
.arvalid ( arvalid ),
|
||||
.arready ( arready ),
|
||||
.araddr ( araddr ),
|
||||
.arlen ( arlen ),
|
||||
.rvalid ( rvalid ),
|
||||
.rready ( rready ),
|
||||
.rlast ( rlast ),
|
||||
.rdata ( rdata ),
|
||||
.uart_tx ( uart_tx ),
|
||||
.uart_rx ( uart_rx )
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// DDR-SDRAM controller
|
||||
// -------------------------------------------------------------------------------------
|
||||
ddr_sdram_ctrl #(
|
||||
.READ_BUFFER ( 1 ),
|
||||
.BA_BITS ( BA_BITS ),
|
||||
.ROW_BITS ( ROW_BITS ),
|
||||
.COL_BITS ( COL_BITS ),
|
||||
.DQ_LEVEL ( DQ_LEVEL ), // x8
|
||||
.tREFC ( 10'd512 ),
|
||||
.tW2I ( 8'd7 ),
|
||||
.tR2I ( 8'd7 )
|
||||
) ddr_ctrl_i(
|
||||
.rstn ( rstn ),
|
||||
.clk ( clk300m ),
|
||||
.aresetn ( aresetn ),
|
||||
.aclk ( aclk ),
|
||||
.awvalid ( awvalid ),
|
||||
.awready ( awready ),
|
||||
.awaddr ( awaddr ),
|
||||
.awlen ( awlen ),
|
||||
.wvalid ( wvalid ),
|
||||
.wready ( wready ),
|
||||
.wlast ( wlast ),
|
||||
.wdata ( wdata ),
|
||||
.bvalid ( bvalid ),
|
||||
.bready ( bready ),
|
||||
.arvalid ( arvalid ),
|
||||
.arready ( arready ),
|
||||
.araddr ( araddr ),
|
||||
.arlen ( arlen ),
|
||||
.rvalid ( rvalid ),
|
||||
.rready ( rready ),
|
||||
.rlast ( rlast ),
|
||||
.rdata ( rdata ),
|
||||
.ddr_ck_p ( ddr_ck_p ),
|
||||
.ddr_ck_n ( ddr_ck_n ),
|
||||
.ddr_cke ( ddr_cke ),
|
||||
.ddr_cs_n ( ddr_cs_n ),
|
||||
.ddr_ras_n ( ddr_ras_n ),
|
||||
.ddr_cas_n ( ddr_cas_n ),
|
||||
.ddr_we_n ( ddr_we_n ),
|
||||
.ddr_ba ( ddr_ba ),
|
||||
.ddr_a ( ddr_a ),
|
||||
.ddr_dq ( ddr_dq ),
|
||||
.ddr_dqs ( ddr_dqs ),
|
||||
.ddr_dm ( ddr_dm )
|
||||
);
|
||||
|
||||
endmodule
|
265
example-uart-read-write/RTL/uart2axi4.sv
Normal file
265
example-uart-read-write/RTL/uart2axi4.sv
Normal file
@ -0,0 +1,265 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
module uart2axi4 #(
|
||||
parameter A_WIDTH = 26,
|
||||
parameter D_WIDTH = 16
|
||||
) (
|
||||
input wire aresetn,
|
||||
input wire aclk,
|
||||
|
||||
output wire awvalid,
|
||||
input wire awready,
|
||||
output reg [A_WIDTH-1:0] awaddr,
|
||||
output reg [ 7:0] awlen,
|
||||
output wire wvalid,
|
||||
input wire wready,
|
||||
output wire wlast,
|
||||
output wire [D_WIDTH-1:0] wdata,
|
||||
input wire bvalid,
|
||||
output wire bready,
|
||||
output wire arvalid,
|
||||
input wire arready,
|
||||
output reg [A_WIDTH-1:0] araddr,
|
||||
output reg [ 7:0] arlen,
|
||||
input wire rvalid,
|
||||
output wire rready,
|
||||
input wire rlast,
|
||||
input wire [D_WIDTH-1:0] rdata,
|
||||
|
||||
input wire uart_rx,
|
||||
output wire uart_tx
|
||||
);
|
||||
|
||||
function automatic logic isW(input [7:0] c);
|
||||
return c==8'h57 || c==8'h77;
|
||||
endfunction
|
||||
|
||||
function automatic logic isR(input [7:0] c);
|
||||
return c==8'h52 || c==8'h72;
|
||||
endfunction
|
||||
|
||||
function automatic logic isSpace(input [7:0] c);
|
||||
return c==8'h20 || c==8'h09;
|
||||
endfunction
|
||||
|
||||
function automatic logic isNewline(input [7:0] c);
|
||||
return c==8'h0D || c==8'h0A;
|
||||
endfunction
|
||||
|
||||
function automatic logic [3:0] isHex(input [7:0] c);
|
||||
if(c>=8'h30 && c<= 8'h39)
|
||||
return 1'b1;
|
||||
else if(c>=8'h41 && c<=8'h46 || c>=8'h61 && c<=8'h66)
|
||||
return 1'b1;
|
||||
else
|
||||
return 1'b0;
|
||||
endfunction
|
||||
|
||||
function automatic logic [3:0] getHex(input [7:0] c);
|
||||
if(c>=8'h30 && c<= 8'h39)
|
||||
return c[3:0];
|
||||
else if(c>=8'h41 && c<=8'h46 || c>=8'h61 && c<=8'h66)
|
||||
return c[3:0] + 8'h9;
|
||||
else
|
||||
return 4'd0;
|
||||
endfunction
|
||||
|
||||
localparam V_WIDTH = A_WIDTH>D_WIDTH ? (A_WIDTH>8?A_WIDTH:8) : (D_WIDTH>8?D_WIDTH:8);
|
||||
|
||||
wire rx_valid;
|
||||
wire [7:0] rx_data;
|
||||
|
||||
reg rw; // 0:write 1:read
|
||||
reg [V_WIDTH-1:0] value;
|
||||
reg [ 7:0] value_cnt;
|
||||
reg wbuf_wen;
|
||||
reg [ 7:0] wbuf_waddr;
|
||||
reg [D_WIDTH-1:0] wbuf_wdata;
|
||||
reg [ 7:0] wbuf_raddr;
|
||||
wire[ 7:0] wbuf_raddr_n = stat == AXI_W && wready ? wbuf_raddr + 8'd1 : wbuf_raddr;
|
||||
wire[D_WIDTH-1:0] wbuf_rdata;
|
||||
enum logic [3:0] {IDLE, INVALID, GADDR, GRLEN, GWDATA, AXI_AR, AXI_R, AXI_AW, AXI_W, AXI_B} stat;
|
||||
|
||||
assign awvalid = stat == AXI_AW;
|
||||
assign wvalid = stat == AXI_W;
|
||||
assign wlast = wbuf_raddr == wbuf_waddr;
|
||||
assign wdata = wbuf_rdata;
|
||||
assign bready = stat == AXI_B;
|
||||
assign arvalid = stat == AXI_AR;
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
awaddr <= '0;
|
||||
awlen <= '0;
|
||||
araddr <= '0;
|
||||
arlen <= '0;
|
||||
rw <= 1'b0;
|
||||
value <= '0;
|
||||
value_cnt <= '0;
|
||||
wbuf_wen <= 1'b0;
|
||||
wbuf_waddr <= '0;
|
||||
wbuf_wdata <= '0;
|
||||
wbuf_raddr <= '0;
|
||||
stat <= IDLE;
|
||||
end else begin
|
||||
wbuf_wen <= 1'b0;
|
||||
case(stat)
|
||||
IDLE: if(rx_valid) begin
|
||||
value <= '0;
|
||||
value_cnt <= '0;
|
||||
wbuf_raddr <= '0;
|
||||
if( isW(rx_data) ) begin
|
||||
rw <= 1'b0;
|
||||
stat <= GADDR;
|
||||
end else if( isR(rx_data) ) begin
|
||||
rw <= 1'b1;
|
||||
stat <= GADDR;
|
||||
end else if( ~isNewline(rx_data) ) begin
|
||||
stat <= INVALID;
|
||||
end
|
||||
end
|
||||
GADDR: if(rx_valid) begin
|
||||
if( isNewline(rx_data) ) begin
|
||||
value <= '0;
|
||||
stat <= IDLE;
|
||||
end else if( isSpace(rx_data) ) begin
|
||||
value <= '0;
|
||||
if(rw) begin
|
||||
araddr <= value[A_WIDTH-1:0];
|
||||
stat <= GRLEN;
|
||||
end else begin
|
||||
awaddr <= value[A_WIDTH-1:0];
|
||||
stat <= GWDATA;
|
||||
end
|
||||
end else if( isHex(rx_data) ) begin
|
||||
value <= { value[V_WIDTH-5:0], getHex(rx_data) };
|
||||
end else begin
|
||||
stat <= INVALID;
|
||||
end
|
||||
end
|
||||
GRLEN: if(rx_valid) begin
|
||||
if( isNewline(rx_data) ) begin
|
||||
value <= '0;
|
||||
arlen <= value[7:0];
|
||||
stat <= AXI_AR;
|
||||
end else if( isHex(rx_data) ) begin
|
||||
value <= { value[V_WIDTH-5:0], getHex(rx_data) };
|
||||
end else begin
|
||||
stat <= INVALID;
|
||||
end
|
||||
end
|
||||
GWDATA: if(rx_valid) begin
|
||||
if( isNewline(rx_data) ) begin
|
||||
wbuf_wen <= 1'b1;
|
||||
wbuf_waddr <= value_cnt;
|
||||
wbuf_wdata <= value[D_WIDTH-1:0];
|
||||
awlen <= value_cnt;
|
||||
stat <= AXI_AW;
|
||||
end else if( isSpace(rx_data) ) begin
|
||||
value <= '0;
|
||||
value_cnt <= value_cnt + 8'd1;
|
||||
wbuf_wen <= 1'b1;
|
||||
wbuf_waddr <= value_cnt;
|
||||
wbuf_wdata <= value[D_WIDTH-1:0];
|
||||
end else if( isHex(rx_data) ) begin
|
||||
value <= { value[V_WIDTH-5:0], getHex(rx_data) };
|
||||
end else begin
|
||||
stat <= INVALID;
|
||||
end
|
||||
end
|
||||
INVALID: if( rx_valid ) begin
|
||||
if ( isNewline(rx_data) )
|
||||
stat <= IDLE;
|
||||
end
|
||||
AXI_AR: if(arready) begin
|
||||
stat <= AXI_R;
|
||||
end
|
||||
AXI_R: if(rvalid & rready & rlast) begin
|
||||
stat <= IDLE;
|
||||
end
|
||||
AXI_AW: if(awready) begin
|
||||
stat <= AXI_W;
|
||||
end
|
||||
AXI_W: if(wready) begin
|
||||
wbuf_raddr <= wbuf_raddr + 8'd1;
|
||||
if(wbuf_raddr==awlen)
|
||||
stat <= AXI_B;
|
||||
end
|
||||
AXI_B: if(bvalid) begin
|
||||
stat <= IDLE;
|
||||
end
|
||||
default: stat<=IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
ram_for_axi4write #(
|
||||
.ADDR_LEN ( 8 ),
|
||||
.DATA_LEN ( D_WIDTH )
|
||||
) ram_for_axi4write_i (
|
||||
.clk ( aclk ),
|
||||
.wr_req ( wbuf_wen ),
|
||||
.wr_addr ( wbuf_waddr ),
|
||||
.wr_data ( wbuf_wdata ),
|
||||
.rd_addr ( wbuf_raddr_n ),
|
||||
.rd_data ( wbuf_rdata )
|
||||
);
|
||||
|
||||
uart_rx#(
|
||||
.CLK_DIV ( 162 ),
|
||||
.CLK_PART ( 6 )
|
||||
) uart_rx_i (
|
||||
.rstn ( aresetn ),
|
||||
.clk ( aclk ),
|
||||
.rx ( uart_rx ),
|
||||
.rvalid ( rx_valid ),
|
||||
.rdata ( rx_data )
|
||||
);
|
||||
|
||||
axis2uarttx #(
|
||||
.CLK_DIV ( 651 ),
|
||||
.DATA_WIDTH ( D_WIDTH ),
|
||||
.FIFO_ASIZE ( 10 )
|
||||
) uart_tx_i (
|
||||
.aresetn ( aresetn ),
|
||||
.aclk ( aclk ),
|
||||
.tvalid ( rvalid ),
|
||||
.tready ( rready ),
|
||||
.tlast ( rlast ),
|
||||
.tdata ( rdata ),
|
||||
.uart_tx ( uart_tx )
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
module ram_for_axi4write #(
|
||||
parameter ADDR_LEN = 12,
|
||||
parameter DATA_LEN = 8
|
||||
) (
|
||||
input logic clk,
|
||||
input logic wr_req,
|
||||
input logic [ADDR_LEN-1:0] rd_addr, wr_addr,
|
||||
output logic [DATA_LEN-1:0] rd_data,
|
||||
input logic [DATA_LEN-1:0] wr_data
|
||||
);
|
||||
|
||||
localparam RAM_SIZE = (1<<ADDR_LEN);
|
||||
|
||||
logic [DATA_LEN-1:0] mem [RAM_SIZE];
|
||||
|
||||
initial rd_data = 0;
|
||||
|
||||
always @ (posedge clk)
|
||||
rd_data <= mem[rd_addr];
|
||||
|
||||
always @ (posedge clk)
|
||||
if(wr_req)
|
||||
mem[wr_addr] <= wr_data;
|
||||
|
||||
endmodule
|
71
example-uart-read-write/RTL/uart_rx.sv
Normal file
71
example-uart-read-write/RTL/uart_rx.sv
Normal file
@ -0,0 +1,71 @@
|
||||
module uart_rx #(
|
||||
parameter CLK_DIV = 108, // UART baud rate = clk freq/(4*CLK_DIV)
|
||||
// modify CLK_DIV to change the UART baud
|
||||
// for example, when clk=50MHz, CLK_DIV=108, then baud=100MHz/(4*108)=115200
|
||||
// 115200 is a typical baud rate for UART
|
||||
parameter CLK_PART = 4 // from 0 to 7
|
||||
) (
|
||||
input wire clk, rstn,
|
||||
// uart rx input
|
||||
input wire rx,
|
||||
// user interface
|
||||
output wire rvalid,
|
||||
output wire [7:0] rdata
|
||||
);
|
||||
|
||||
reg done = 1'b0;
|
||||
reg [ 7:0] data = 8'h0;
|
||||
reg [ 2:0] supercnt=3'h0;
|
||||
reg [31:0] cnt = 0;
|
||||
reg [ 7:0] databuf = 8'h0;
|
||||
reg [ 5:0] status=6'h0, shift=6'h0;
|
||||
reg rxr=1'b1;
|
||||
wire recvbit = (shift[1]&shift[0]) | (shift[0]&rxr) | (rxr&shift[1]) ;
|
||||
wire [2:0] supercntreverse = {supercnt[0], supercnt[1], supercnt[2]};
|
||||
|
||||
assign rvalid = done;
|
||||
assign rdata = data;
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn)
|
||||
rxr <= 1'b1;
|
||||
else
|
||||
rxr <= rx;
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
done <= 1'b0;
|
||||
data <= 8'h0;
|
||||
status <= 6'h0;
|
||||
shift <= 6'h0;
|
||||
databuf <= 8'h0;
|
||||
cnt <= 0;
|
||||
end else begin
|
||||
done <= 1'b0;
|
||||
if( (supercntreverse<CLK_PART) ? (cnt>=CLK_DIV) : (cnt>=CLK_DIV-1) ) begin
|
||||
if(status==0) begin
|
||||
if(shift == 6'b111_000)
|
||||
status <= 1;
|
||||
end else begin
|
||||
if(status[5] == 1'b0) begin
|
||||
if(status[1:0] == 2'b11)
|
||||
databuf <= {recvbit, databuf[7:1]};
|
||||
status <= status + 5'b1;
|
||||
end else begin
|
||||
if(status<62) begin
|
||||
status <= 62;
|
||||
data <= databuf;
|
||||
done <= 1'b1;
|
||||
end else begin
|
||||
status <= status + 6'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
shift <= {shift[4:0], rxr};
|
||||
supercnt <= supercnt + 3'h1;
|
||||
cnt <= 0;
|
||||
end else
|
||||
cnt <= cnt + 1;
|
||||
end
|
||||
|
||||
endmodule
|
30
example-uart-read-write/ddr_test.qpf
Normal file
30
example-uart-read-write/ddr_test.qpf
Normal file
@ -0,0 +1,30 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Copyright (C) 1991-2013 Altera Corporation
|
||||
# Your use of Altera Corporation's design tools, logic functions
|
||||
# and other software and tools, and its AMPP partner logic
|
||||
# functions, and any output files from any of the foregoing
|
||||
# (including device programming or simulation files), and any
|
||||
# associated documentation or information are expressly subject
|
||||
# to the terms and conditions of the Altera Program License
|
||||
# Subscription Agreement, Altera MegaCore Function License
|
||||
# Agreement, or other applicable license agreement, including,
|
||||
# without limitation, that your use is for the sole purpose of
|
||||
# programming logic devices manufactured by Altera and sold by
|
||||
# Altera or its authorized distributors. Please refer to the
|
||||
# applicable agreement for further details.
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Quartus II 64-Bit
|
||||
# Version 13.1.0 Build 162 10/23/2013 SJ Full Version
|
||||
# Date created = 17:45:24 January 23, 2021
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
|
||||
QUARTUS_VERSION = "13.1"
|
||||
DATE = "17:45:24 January 23, 2021"
|
||||
|
||||
# Revisions
|
||||
|
||||
PROJECT_REVISION = "ddr_test"
|
100
example-uart-read-write/ddr_test.qsf
Normal file
100
example-uart-read-write/ddr_test.qsf
Normal file
@ -0,0 +1,100 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Copyright (C) 1991-2013 Altera Corporation
|
||||
# Your use of Altera Corporation's design tools, logic functions
|
||||
# and other software and tools, and its AMPP partner logic
|
||||
# functions, and any output files from any of the foregoing
|
||||
# (including device programming or simulation files), and any
|
||||
# associated documentation or information are expressly subject
|
||||
# to the terms and conditions of the Altera Program License
|
||||
# Subscription Agreement, Altera MegaCore Function License
|
||||
# Agreement, or other applicable license agreement, including,
|
||||
# without limitation, that your use is for the sole purpose of
|
||||
# programming logic devices manufactured by Altera and sold by
|
||||
# Altera or its authorized distributors. Please refer to the
|
||||
# applicable agreement for further details.
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Quartus II 64-Bit
|
||||
# Version 13.1.0 Build 162 10/23/2013 SJ Full Version
|
||||
# Date created = 17:45:24 January 23, 2021
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Notes:
|
||||
#
|
||||
# 1) The default values for assignments are stored in the file:
|
||||
# ddr_test_assignment_defaults.qdf
|
||||
# If this file doesn't exist, see file:
|
||||
# assignment_defaults.qdf
|
||||
#
|
||||
# 2) Altera recommends that you do not modify this file. This
|
||||
# file is updated automatically by the Quartus II software
|
||||
# and any changes you make may be lost or overwritten.
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
|
||||
|
||||
set_global_assignment -name FAMILY "Cyclone IV E"
|
||||
set_global_assignment -name DEVICE EP4CE6E22C8
|
||||
set_global_assignment -name TOP_LEVEL_ENTITY top
|
||||
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1
|
||||
set_global_assignment -name PROJECT_CREATION_TIME_DATE "17:45:24 JANUARY 23, 2021"
|
||||
set_global_assignment -name LAST_QUARTUS_VERSION 13.1
|
||||
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
|
||||
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
|
||||
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
|
||||
set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
|
||||
set_global_assignment -name NOMINAL_CORE_SUPPLY_VOLTAGE 1.2V
|
||||
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE RTL/top.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE ../RTL/ddr_sdram_ctrl.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE RTL/uart2axi4.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE RTL/axis2uarttx.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE RTL/uart_rx.sv
|
||||
set_global_assignment -name VERILOG_FILE IP/pll.v
|
||||
|
||||
set_location_assignment PIN_23 -to clk50m
|
||||
|
||||
set_location_assignment PIN_28 -to uart_tx
|
||||
set_location_assignment PIN_25 -to uart_rx
|
||||
|
||||
set_location_assignment PIN_10 -to ddr_cs_n
|
||||
set_location_assignment PIN_30 -to ddr_ras_n
|
||||
set_location_assignment PIN_31 -to ddr_cas_n
|
||||
set_location_assignment PIN_32 -to ddr_we_n
|
||||
set_location_assignment PIN_86 -to ddr_cke
|
||||
set_location_assignment PIN_85 -to ddr_ck_p
|
||||
set_location_assignment PIN_84 -to ddr_ck_n
|
||||
set_location_assignment PIN_7 -to ddr_ba[0]
|
||||
set_location_assignment PIN_3 -to ddr_ba[1]
|
||||
set_location_assignment PIN_1 -to ddr_a[0]
|
||||
set_location_assignment PIN_144 -to ddr_a[1]
|
||||
set_location_assignment PIN_143 -to ddr_a[2]
|
||||
set_location_assignment PIN_142 -to ddr_a[3]
|
||||
set_location_assignment PIN_106 -to ddr_a[4]
|
||||
set_location_assignment PIN_105 -to ddr_a[5]
|
||||
set_location_assignment PIN_104 -to ddr_a[6]
|
||||
set_location_assignment PIN_103 -to ddr_a[7]
|
||||
set_location_assignment PIN_100 -to ddr_a[8]
|
||||
set_location_assignment PIN_99 -to ddr_a[9]
|
||||
set_location_assignment PIN_2 -to ddr_a[10]
|
||||
set_location_assignment PIN_98 -to ddr_a[11]
|
||||
set_location_assignment PIN_87 -to ddr_a[12]
|
||||
set_location_assignment PIN_83 -to ddr_dm[0]
|
||||
set_location_assignment PIN_80 -to ddr_dqs[0]
|
||||
set_location_assignment PIN_38 -to ddr_dq[0]
|
||||
set_location_assignment PIN_39 -to ddr_dq[1]
|
||||
set_location_assignment PIN_34 -to ddr_dq[2]
|
||||
set_location_assignment PIN_33 -to ddr_dq[3]
|
||||
set_location_assignment PIN_76 -to ddr_dq[4]
|
||||
set_location_assignment PIN_75 -to ddr_dq[5]
|
||||
set_location_assignment PIN_74 -to ddr_dq[6]
|
||||
set_location_assignment PIN_73 -to ddr_dq[7]
|
||||
|
||||
|
||||
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
|
||||
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
|
||||
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
BIN
hardware/gerber.zip
Normal file
BIN
hardware/gerber.zip
Normal file
Binary file not shown.
19146
hardware/sch.pdf
Normal file
19146
hardware/sch.pdf
Normal file
File diff suppressed because it is too large
Load Diff
BIN
images/UartSession.png
Normal file
BIN
images/UartSession.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
images/board.jpg
Normal file
BIN
images/board.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
BIN
images/sim.png
Normal file
BIN
images/sim.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
1436
sim-selftest/DDR_MODEL/ddr.v
Normal file
1436
sim-selftest/DDR_MODEL/ddr.v
Normal file
File diff suppressed because it is too large
Load Diff
124
sim-selftest/DDR_MODEL/ddr_parameters.vh
Normal file
124
sim-selftest/DDR_MODEL/ddr_parameters.vh
Normal file
@ -0,0 +1,124 @@
|
||||
/****************************************************************************************
|
||||
*
|
||||
* Disclaimer This software code and all associated documentation, comments or other
|
||||
* of Warranty: information (collectively "Software") is provided "AS IS" without
|
||||
* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY
|
||||
* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT
|
||||
* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE
|
||||
* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE.
|
||||
* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR
|
||||
* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS,
|
||||
* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE
|
||||
* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI,
|
||||
* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING,
|
||||
* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION,
|
||||
* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE
|
||||
* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGES. Because some jurisdictions prohibit the exclusion or
|
||||
* limitation of liability for consequential or incidental damages, the
|
||||
* above limitation may not apply to you.
|
||||
*
|
||||
* Copyright 2003 Micron Technology, Inc. All rights reserved.
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
`define sg5B
|
||||
|
||||
|
||||
parameter no_halt = 1; // If set to 1, the model won't halt on command sequence/major errors
|
||||
parameter DEBUG = 1; // Turn on DEBUG message
|
||||
|
||||
|
||||
parameter BA_BITS = 2; // Set this parmaeter to control how many Bank Address bits are used
|
||||
parameter ROW_BITS = 13; // Set this parameter to control how many Address bits are used
|
||||
parameter COL_BITS = 11; // Set this parameter to control how many Column bits are used
|
||||
parameter DQ_BITS = 8; // Set this parameter to control how many Data bits are used
|
||||
|
||||
|
||||
parameter ADDR_BITS = ROW_BITS;
|
||||
|
||||
parameter part_mem_bits = 15; // Set this parameter to control how many unique addresses are used
|
||||
|
||||
parameter full_mem_bits = BA_BITS+ROW_BITS+COL_BITS; // Set this parameter to control how many unique addresses are used
|
||||
|
||||
parameter DQS_BITS = (DQ_BITS + 4) / 8;
|
||||
parameter DM_BITS = DQS_BITS;
|
||||
|
||||
|
||||
|
||||
`ifdef sg5B // Timing Parameters for -5B (CL = 3)
|
||||
parameter tCK = 5.0; // tCK ns Nominal Clock Cycle Time
|
||||
parameter tDQSQ = 0.4; // tDQSQ ns DQS-DQ skew, DQS to last DQ valid, per group, per access
|
||||
parameter tMRD = 10.0; // tMRD ns Load Mode Register command cycle time
|
||||
parameter tRAP = 15.0; // tRAP ns ACTIVE to READ with Auto precharge command
|
||||
parameter tRAS = 40.0; // tRAS ns Active to Precharge command time
|
||||
parameter tRC = 55.0; // tRC ns Active to Active/Auto Refresh command time
|
||||
parameter tRFC = 70.0; // tRFC ns Refresh to Refresh Command interval time
|
||||
parameter tRCD = 15.0; // tRCD ns Active to Read/Write command time
|
||||
parameter tRP = 15.0; // tRP ns Precharge command period
|
||||
parameter tRRD = 10.0; // tRRD ns Active bank a to Active bank b command time
|
||||
parameter tWR = 15.0; // tWR ns Write recovery time
|
||||
`else `ifdef sg6T // Timing Parameters for -6T (CL = 2.5)
|
||||
parameter tCK = 6.0; // tCK ns Nominal Clock Cycle Time
|
||||
parameter tDQSQ = 0.45; // tDQSQ ns DQS-DQ skew, DQS to last DQ valid, per group, per access
|
||||
parameter tMRD = 12.0; // tMRD ns Load Mode Register command cycle time
|
||||
parameter tRAP = 15.0; // tRAP ns ACTIVE to READ with Auto precharge command
|
||||
parameter tRAS = 42.0; // tRAS ns Active to Precharge command time
|
||||
parameter tRC = 60.0; // tRC ns Active to Active/Auto Refresh command time
|
||||
parameter tRFC = 72.0; // tRFC ns Refresh to Refresh Command interval time
|
||||
parameter tRCD = 15.0; // tRCD ns Active to Read/Write command time
|
||||
parameter tRP = 15.0; // tRP ns Precharge command period
|
||||
parameter tRRD = 12.0; // tRRD ns Active bank a to Active bank b command time
|
||||
parameter tWR = 15.0; // tWR ns Write recovery time
|
||||
`else `ifdef sg6 // Timing Parameters for -6 (CL = 2.5)
|
||||
parameter tCK = 6.0; // tCK ns Nominal Clock Cycle Time
|
||||
parameter tDQSQ = 0.4; // tDQSQ ns DQS-DQ skew, DQS to last DQ valid, per group, per access
|
||||
parameter tMRD = 12.0; // tMRD ns Load Mode Register command cycle time
|
||||
parameter tRAP = 15.0; // tRAP ns ACTIVE to READ with Auto precharge command
|
||||
parameter tRAS = 42.0; // tRAS ns Active to Precharge command time
|
||||
parameter tRC = 60.0; // tRC ns Active to Active/Auto Refresh command time
|
||||
parameter tRFC = 72.0; // tRFC ns Refresh to Refresh Command interval time
|
||||
parameter tRCD = 15.0; // tRCD ns Active to Read/Write command time
|
||||
parameter tRP = 15.0; // tRP ns Precharge command period
|
||||
parameter tRRD = 12.0; // tRRD ns Active bank a to Active bank b command time
|
||||
parameter tWR = 15.0; // tWR ns Write recovery time
|
||||
`else `ifdef sg75E // Timing Parameters for -75E (CL = 2)
|
||||
parameter tCK = 7.5; // tCK ns Nominal Clock Cycle Time
|
||||
parameter tDQSQ = 0.5; // tDQSQ ns DQS-DQ skew, DQS to last DQ valid, per group, per access
|
||||
parameter tMRD = 15.0; // tMRD ns Load Mode Register command cycle time
|
||||
parameter tRAP = 15.0; // tRAP ns ACTIVE to READ with Auto precharge command
|
||||
parameter tRAS = 40.0; // tRAS ns Active to Precharge command time
|
||||
parameter tRC = 60.0; // tRC ns Active to Active/Auto Refresh command time
|
||||
parameter tRFC = 75.0; // tRFC ns Refresh to Refresh Command interval time
|
||||
parameter tRCD = 15.0; // tRCD ns Active to Read/Write command time
|
||||
parameter tRP = 15.0; // tRP ns Precharge command period
|
||||
parameter tRRD = 15.0; // tRRD ns Active bank a to Active bank b command time
|
||||
parameter tWR = 15.0; // tWR ns Write recovery time
|
||||
`else `ifdef sg75Z // Timing Parameters for -75Z (CL = 2)
|
||||
parameter tCK = 7.5; // tCK ns Nominal Clock Cycle Time
|
||||
parameter tDQSQ = 0.5; // tDQSQ ns DQS-DQ skew, DQS to last DQ valid, per group, per access
|
||||
parameter tMRD = 15.0; // tMRD ns Load Mode Register command cycle time
|
||||
parameter tRAP = 20.0; // tRAP ns ACTIVE to READ with Auto precharge command
|
||||
parameter tRAS = 40.0; // tRAS ns Active to Precharge command time
|
||||
parameter tRC = 65.0; // tRC ns Active to Active/Auto Refresh command time
|
||||
parameter tRFC = 75.0; // tRFC ns Refresh to Refresh Command interval time
|
||||
parameter tRCD = 20.0; // tRCD ns Active to Read/Write command time
|
||||
parameter tRP = 20.0; // tRP ns Precharge command period
|
||||
parameter tRRD = 15.0; // tRRD ns Active bank a to Active bank b command time
|
||||
parameter tWR = 15.0; // tWR ns Write recovery time
|
||||
`else `define sg75 // Timing Parameters for -75 (CL = 2.5)
|
||||
parameter tCK = 7.5; // tCK ns Nominal Clock Cycle Time
|
||||
parameter tDQSQ = 0.5; // tDQSQ ns DQS-DQ skew, DQS to last DQ valid, per group, per access
|
||||
parameter tMRD = 15.0; // tMRD ns Load Mode Register command cycle time
|
||||
parameter tRAP = 20.0; // tRAP ns ACTIVE to READ with Auto precharge command
|
||||
parameter tRAS = 40.0; // tRAS ns Active to Precharge command time
|
||||
parameter tRC = 65.0; // tRC ns Active to Active/Auto Refresh command time
|
||||
parameter tRFC = 75.0; // tRFC ns Refresh to Refresh Command interval time
|
||||
parameter tRCD = 20.0; // tRCD ns Active to Read/Write command time
|
||||
parameter tRP = 20.0; // tRP ns Precharge command period
|
||||
parameter tRRD = 15.0; // tRRD ns Active bank a to Active bank b command time
|
||||
parameter tWR = 15.0; // tWR ns Write recovery time
|
||||
`endif `endif `endif `endif `endif
|
113
sim-selftest/SRC/axi_self_test_master.sv
Normal file
113
sim-selftest/SRC/axi_self_test_master.sv
Normal file
@ -0,0 +1,113 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
module axi_self_test_master #(
|
||||
parameter A_WIDTH_TEST = 26,
|
||||
parameter A_WIDTH = 26,
|
||||
parameter D_WIDTH = 16,
|
||||
parameter D_LEVEL = 1,
|
||||
parameter [7:0] WBURST_LEN = 8'd7,
|
||||
parameter [7:0] RBURST_LEN = 8'd7
|
||||
)(
|
||||
input wire aresetn,
|
||||
input wire aclk,
|
||||
output wire awvalid,
|
||||
input wire awready,
|
||||
output reg [A_WIDTH-1:0] awaddr,
|
||||
output wire [ 7:0] awlen,
|
||||
output wire wvalid,
|
||||
input wire wready,
|
||||
output wire wlast,
|
||||
output wire [D_WIDTH-1:0] wdata,
|
||||
input wire bvalid,
|
||||
output wire bready,
|
||||
output wire arvalid,
|
||||
input wire arready,
|
||||
output reg [A_WIDTH-1:0] araddr,
|
||||
output wire [ 7:0] arlen,
|
||||
input wire rvalid,
|
||||
output wire rready,
|
||||
input wire rlast,
|
||||
input wire [D_WIDTH-1:0] rdata,
|
||||
output reg error,
|
||||
output reg [ 15:0] error_cnt
|
||||
);
|
||||
|
||||
wire aw_end;
|
||||
reg awaddr_carry;
|
||||
reg [7:0] w_cnt;
|
||||
enum logic [2:0] {INIT, AW, W, B, AR, R} stat;
|
||||
|
||||
generate if(A_WIDTH_TEST<A_WIDTH)
|
||||
assign aw_end = awaddr[A_WIDTH_TEST];
|
||||
else
|
||||
assign aw_end = awaddr_carry;
|
||||
endgenerate
|
||||
|
||||
assign awvalid = stat==AW;
|
||||
assign awlen = WBURST_LEN;
|
||||
assign wvalid = stat==W;
|
||||
assign wlast = w_cnt==WBURST_LEN;
|
||||
assign wdata = awaddr;
|
||||
assign bready = 1'b1;
|
||||
assign arvalid = stat==AR;
|
||||
assign arlen = RBURST_LEN;
|
||||
assign rready = 1'b1;
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
{awaddr_carry, awaddr} <= '0;
|
||||
w_cnt <= 8'd0;
|
||||
araddr <= '0;
|
||||
stat <= INIT;
|
||||
end else begin
|
||||
case(stat)
|
||||
INIT: begin
|
||||
{awaddr_carry, awaddr} <= '0;
|
||||
w_cnt <= 8'd0;
|
||||
araddr <= '0;
|
||||
stat <= AW;
|
||||
end
|
||||
AW: if(awready) begin
|
||||
w_cnt <= 8'd0;
|
||||
stat <= W;
|
||||
end
|
||||
W: if(wready) begin
|
||||
{awaddr_carry, awaddr} <= {awaddr_carry, awaddr} + (1<<D_LEVEL);
|
||||
w_cnt <= w_cnt + 8'd1;
|
||||
if(wlast)
|
||||
stat <= B;
|
||||
end
|
||||
B: if(bvalid) begin
|
||||
stat <= aw_end ? AR : AW;
|
||||
end
|
||||
AR: if(arready) begin
|
||||
stat <= R;
|
||||
end
|
||||
R: if(rvalid) begin
|
||||
automatic logic [A_WIDTH:0] araddr_next;
|
||||
araddr_next = araddr + (1<<D_LEVEL);
|
||||
araddr <= araddr_next[A_WIDTH-1:0];
|
||||
if(rlast) begin
|
||||
stat <= AR;
|
||||
if(araddr_next[A_WIDTH_TEST])
|
||||
araddr <= '0;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// read and write mismatch detect
|
||||
// ------------------------------------------------------------
|
||||
wire [D_WIDTH-1:0] rdata_idle = araddr;
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
error <= 1'b0;
|
||||
error_cnt <= 16'd0;
|
||||
end else begin
|
||||
error <= rvalid && rready && rdata!=rdata_idle;
|
||||
if(error)
|
||||
error_cnt <= error_cnt + 16'd1;
|
||||
end
|
||||
|
||||
endmodule
|
177
sim-selftest/SRC/tb_ddr_ctrl.sv
Normal file
177
sim-selftest/SRC/tb_ddr_ctrl.sv
Normal file
@ -0,0 +1,177 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
module tb_ddr_ctrl();
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// DDR-SDRAM parameters
|
||||
// -------------------------------------------------------------------------------------
|
||||
localparam BA_BITS = 2;
|
||||
localparam ROW_BITS = 13;
|
||||
localparam COL_BITS = 11;
|
||||
localparam DQ_LEVEL = 1;
|
||||
localparam DQ_BITS = (4<<DQ_LEVEL);
|
||||
localparam DQS_BITS = ((1<<DQ_LEVEL)+1)/2;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// meta AXI4 burst length parameters
|
||||
// -------------------------------------------------------------------------------------
|
||||
localparam [7:0] WBURST_LEN = 8'd7;
|
||||
localparam [7:0] RBURST_LEN = 8'd7;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// meta AXI4 parameters
|
||||
// -------------------------------------------------------------------------------------
|
||||
localparam A_WIDTH = BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-1;
|
||||
localparam D_WIDTH = (8<<DQ_LEVEL);
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// driving clock and reset generate
|
||||
// -------------------------------------------------------------------------------------
|
||||
reg rstn=1'b0, clk300m=1'b1;
|
||||
always #1.6667 clk300m = ~clk300m;
|
||||
initial begin repeat(4) @(posedge clk300m); rstn<=1'b1; end
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// DDR-SDRAM signal
|
||||
// -------------------------------------------------------------------------------------
|
||||
wire ddr_ck_p, ddr_ck_n;
|
||||
wire ddr_cke;
|
||||
wire ddr_cs_n, ddr_ras_n, ddr_cas_n, ddr_we_n;
|
||||
wire [ 1:0] ddr_ba;
|
||||
wire [ROW_BITS-1:0] ddr_a;
|
||||
wire [DQS_BITS-1:0] ddr_dm;
|
||||
tri [DQS_BITS-1:0] ddr_dqs;
|
||||
tri [ DQ_BITS-1:0] ddr_dq;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// meta AXI4 interface
|
||||
// -------------------------------------------------------------------------------------
|
||||
wire aresetn;
|
||||
wire aclk;
|
||||
wire awvalid;
|
||||
wire awready;
|
||||
wire [A_WIDTH-1:0] awaddr;
|
||||
wire [ 7:0] awlen;
|
||||
wire wvalid;
|
||||
wire wready;
|
||||
wire wlast;
|
||||
wire [D_WIDTH-1:0] wdata;
|
||||
wire bvalid;
|
||||
wire bready;
|
||||
wire arvalid;
|
||||
wire arready;
|
||||
wire [A_WIDTH-1:0] araddr;
|
||||
wire [ 7:0] arlen;
|
||||
wire rvalid;
|
||||
wire rready;
|
||||
wire rlast;
|
||||
wire [D_WIDTH-1:0] rdata;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// self test error signal, 1'b1 indicates error
|
||||
// -------------------------------------------------------------------------------------
|
||||
wire error;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// meta AXI4 master for testing
|
||||
// -------------------------------------------------------------------------------------
|
||||
axi_self_test_master #(
|
||||
.A_WIDTH ( A_WIDTH ),
|
||||
.A_WIDTH_TEST( 14 ),
|
||||
.D_WIDTH ( D_WIDTH ),
|
||||
.D_LEVEL ( DQ_LEVEL ),
|
||||
.WBURST_LEN ( WBURST_LEN ),
|
||||
.RBURST_LEN ( RBURST_LEN )
|
||||
) axi_m_i (
|
||||
.aresetn ( aresetn ),
|
||||
.aclk ( aclk ),
|
||||
.awvalid ( awvalid ),
|
||||
.awready ( awready ),
|
||||
.awaddr ( awaddr ),
|
||||
.awlen ( awlen ),
|
||||
.wvalid ( wvalid ),
|
||||
.wready ( wready ),
|
||||
.wlast ( wlast ),
|
||||
.wdata ( wdata ),
|
||||
.bvalid ( bvalid ),
|
||||
.bready ( bready ),
|
||||
.arvalid ( arvalid ),
|
||||
.arready ( arready ),
|
||||
.araddr ( araddr ),
|
||||
.arlen ( arlen ),
|
||||
.rvalid ( rvalid ),
|
||||
.rready ( rready ),
|
||||
.rlast ( rlast ),
|
||||
.rdata ( rdata ),
|
||||
.error ( error ),
|
||||
.error_cnt ( )
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// DDR-SDRAM controller
|
||||
// -------------------------------------------------------------------------------------
|
||||
ddr_sdram_ctrl #(
|
||||
.READ_BUFFER ( 0 ),
|
||||
.BA_BITS ( BA_BITS ),
|
||||
.ROW_BITS ( ROW_BITS ),
|
||||
.COL_BITS ( COL_BITS ),
|
||||
.DQ_LEVEL ( DQ_LEVEL ), // x8
|
||||
.tREFC ( 10'd512 ),
|
||||
.tW2I ( 8'd6 ),
|
||||
.tR2I ( 8'd6 )
|
||||
) ddr_sdram_ctrl_i (
|
||||
.rstn ( rstn ),
|
||||
.clk ( clk300m ),
|
||||
.aresetn ( aresetn ),
|
||||
.aclk ( aclk ),
|
||||
.awvalid ( awvalid ),
|
||||
.awready ( awready ),
|
||||
.awaddr ( awaddr ),
|
||||
.awlen ( awlen ),
|
||||
.wvalid ( wvalid ),
|
||||
.wready ( wready ),
|
||||
.wlast ( wlast ),
|
||||
.wdata ( wdata ),
|
||||
.bvalid ( bvalid ),
|
||||
.bready ( bready ),
|
||||
.arvalid ( arvalid ),
|
||||
.arready ( arready ),
|
||||
.araddr ( araddr ),
|
||||
.arlen ( arlen ),
|
||||
.rvalid ( rvalid ),
|
||||
.rready ( rready ),
|
||||
.rlast ( rlast ),
|
||||
.rdata ( rdata ),
|
||||
.ddr_ck_p ( ddr_ck_p ),
|
||||
.ddr_ck_n ( ddr_ck_n ),
|
||||
.ddr_cke ( ddr_cke ),
|
||||
.ddr_cs_n ( ddr_cs_n ),
|
||||
.ddr_ras_n ( ddr_ras_n ),
|
||||
.ddr_cas_n ( ddr_cas_n ),
|
||||
.ddr_we_n ( ddr_we_n ),
|
||||
.ddr_ba ( ddr_ba ),
|
||||
.ddr_a ( ddr_a ),
|
||||
.ddr_dm ( ddr_dm ),
|
||||
.ddr_dqs ( ddr_dqs ),
|
||||
.ddr_dq ( ddr_dq )
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// DDR-SDRAM simulation model
|
||||
// -------------------------------------------------------------------------------------
|
||||
ddr ddr_i (
|
||||
.Clk ( ddr_ck_p ),
|
||||
.Clk_n ( ddr_ck_n ),
|
||||
.Cke ( ddr_cke ),
|
||||
.Cs_n ( ddr_cs_n ),
|
||||
.Ras_n ( ddr_ras_n ),
|
||||
.Cas_n ( ddr_cas_n ),
|
||||
.We_n ( ddr_we_n ),
|
||||
.Ba ( ddr_ba ),
|
||||
.Addr ( ddr_a ),
|
||||
.Dm ( ddr_dm ),
|
||||
.Dqs ( ddr_dqs ),
|
||||
.Dq ( ddr_dq )
|
||||
);
|
||||
|
||||
endmodule
|
Loading…
x
Reference in New Issue
Block a user