mirror of
https://github.com/WangXuan95/FPGA-DDR-SDRAM.git
synced 2025-01-17 20:02:52 +08:00
update
This commit is contained in:
parent
4d296af72f
commit
3a71549cb8
117
README.md
117
README.md
@ -1,6 +1,4 @@
|
||||
![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)
|
||||
![语言](https://img.shields.io/badge/语言-systemverilog_(IEEE1800_2005)-CAD09D.svg) ![仿真](https://img.shields.io/badge/仿真-iverilog-green.svg) ![部署](https://img.shields.io/badge/部署-quartus-blue.svg) ![部署](https://img.shields.io/badge/部署-vivado-FF1010.svg)
|
||||
|
||||
FPGA DDR-SDRAM
|
||||
===========================
|
||||
@ -19,7 +17,7 @@ FPGA DDR-SDRAM
|
||||
------------| |-------------------------| |--------------|
|
||||
用户逻辑 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](./RTL/ddr_sdram_ctrl.sv) )。该控制器的特点有:
|
||||
很多低端 FPGA 开发板使用 SDR-SDRAM 作为片外存储,而 DDR-SDRAM (DDR1) 比 SDR-SDRAM 容量更大,价格更低。且与SDR-SDRAM一样,DDR1也能使用低端FPGA的普通的IO管脚直接驱动。我编写了一个软核的 AXI4 接口的 DDR1 控制器。该控制器的特点有:
|
||||
|
||||
* **平台无关** :纯 RTL 编写,可以在 Altera 和 Xilinx 等各种 FPGA 上运行。
|
||||
* **兼容性强** :支持各种位宽和容量的 DDR1 (已在MICRON所有位宽和容量的DDR1型号上仿真通过)。
|
||||
@ -31,6 +29,8 @@ FPGA DDR-SDRAM
|
||||
|
||||
另外,由于各代 DDR-SDRAM(例如DDR3、DDR2、DDR1)的接口时序大同小异,本库也可以方便那些熟悉 Verilog 的人来学习 DDR-SDRAM 接口。
|
||||
|
||||
|
||||
|
||||
# 目录
|
||||
|
||||
* [简介](#简介)
|
||||
@ -47,11 +47,13 @@ FPGA DDR-SDRAM
|
||||
* [示例程序](#示例程序)
|
||||
* [示例程序:自测](#示例程序:自测)
|
||||
* [示例程序: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 。
|
||||
@ -74,17 +76,19 @@ FPGA DDR-SDRAM
|
||||
|
||||
为了进行展示,我用 Altera Cyclone IV 的最低廉的 FPGA (型号:EP4CE6E22C8N) 和 MICRON 的 64MB DDR1 (型号 MT46V64M8TG-6T)画了一个小板子,本库的所有例子可以直接在该板子上直接运行。(如果你要在自己的PCB设计中使用 DDR1 ,只要抄我这个板子就行)
|
||||
|
||||
| ![board-image](./images/board.jpg) |
|
||||
| ![board-image](./figures/board.jpg) |
|
||||
| :---: |
|
||||
| 图:FPGA + DDR1 测试板 |
|
||||
|
||||
原理图见 [hardware/sch.pdf](./hardware/sch.pdf),PCB制造文件见 [hardware/gerber.zip](./hardware/gerber.zip) ,在布局布线时,使用双层板即可,不需像 DDR2 以上的设计那样刻意注意等长和阻抗匹配,因为该电路工作频率为双边沿 75MHz,不是特别高,只需注意让FPGA与DDR距离尽量近,布线尽量短即可。比如我在布局时,把DDR1芯片放在了FPGA芯片正对的背面,从而保证布线都较短。
|
||||
原理图见 PCB/sch.pdf ,PCB制造文件见 PCB/gerber.zip ,在布局布线时,使用双层板即可,不需像 DDR2 以上的设计那样刻意注意等长和阻抗匹配,因为该电路工作频率为双边沿 75MHz,不是特别高,只需注意让FPGA与DDR距离尽量近,布线尽量短即可。比如我在布局时,把DDR1芯片放在了FPGA芯片正对的背面,从而保证布线都较短。
|
||||
|
||||
该板子的设计在立创EDA中开放,见[这里](https://oshwhub.com/wangxuan/fpga-ddr-ce-shi-ban)。
|
||||
该板子的设计在立创EDA中开放,见 [oshwhub.com/wangxuan/fpga-ddr-ce-shi-ban](https://oshwhub.com/wangxuan/fpga-ddr-ce-shi-ban)。
|
||||
|
||||
# DDR1控制器
|
||||
|
||||
DDR1 控制器代码见 [RTL/ddr_sdram_ctrl.sv](./RTL/ddr_sdram_ctrl.sv) ,是一个用 SystemVerilog 编写的模块,它能自动对 DDR1 进行初始化,并定时进行刷新(Refresh)。该模块有一个简化但完备的 AXI4 从接口,通过它可以完成对 DDR1 的读写。本节详细解释该模块的使用方法。
|
||||
|
||||
# DDR1控制器模块
|
||||
|
||||
DDR1 控制器代码见 RTL/ddr_sdram_ctrl.sv ,它能自动对 DDR1 进行初始化,并定时进行刷新(Refresh)。该模块有一个简化但完备的 AXI4 从接口,通过它可以完成对 DDR1 的读写。本节详细解释该模块的使用方法。
|
||||
|
||||
## 模块参数
|
||||
|
||||
@ -121,27 +125,25 @@ module ddr_sdram_ctrl #(
|
||||
该模块需要一个时钟和一个复位进行驱动,如下:
|
||||
|
||||
```Verilog
|
||||
input wire rstn,
|
||||
input wire rstn_async,
|
||||
input wire clk,
|
||||
```
|
||||
|
||||
rstn 是低电平复位信号,正常工作时应该置高。clk 是驱动时钟,频率是用户时钟的 4 倍。
|
||||
rstn_async 是低电平复位信号,正常工作时应该置高。clk 是驱动时钟,频率是用户时钟的 4 倍。
|
||||
|
||||
模块开始工作前,rstn信号应该置低,让模块复位,当 clk 的频率稳定后,可以把 rstn 置高,让模块处于工作状态。
|
||||
|
||||
如果 clk 一开始就是稳定的(例如直接来自晶振输入),那么 rstn 可以直接置为 1'b1 。
|
||||
|
||||
如果 clk 经过一段时间后才能稳定(例如来自 FPGA 的 PLL 或 MMCM),那么 rstn 应该接 PLL/MMCM 的 locked 信号,保证 PLL 锁相成功(稳定)后,模块再开始工作。
|
||||
模块开始工作前,rstn_async 信号应该置低,让模块复位,然后把 rstn_async 置高,解除复位。
|
||||
|
||||
## 时钟频率的选取
|
||||
|
||||
模块内使用寄存器分频 4 倍产生 DDR1 驱动时钟(ddr_ck_p/ddr_ck_n)和 AXI4 总线用户时钟(aclk)。本节讲述如何决定驱动时钟 clk 的频率。
|
||||
模块内将驱动时钟 clk 分频 4 倍产生 DDR1 时钟(ddr_ck_p/ddr_ck_n)和 AXI4 总线用户时钟(aclk)。本节讲述如何决定驱动时钟 clk 的频率。
|
||||
|
||||
首先,时钟频率受限于 DDR1 芯片。考虑到所有的 DDR1 的接口频率至少为 75MHz ,则 clk 的下限是 75\*4=300MHz。而 clk 的上限就取决于 DDR1 的芯片型号,例如对于 MT46V64M8P-5B ,查芯片手册可知,-5B 后缀的 DDR1 在 CAS Latency (CL)=2 时最高时钟频率是 133MHz,则 clk 的上限是 133\*4=532MHz 。
|
||||
首先,时钟频率受限于 DDR1 芯片。考虑到所有的 DDR1 的接口频率至少为 75MHz ,则 clk 的下限是 75\*4=300MHz。
|
||||
|
||||
而 clk 的上限就也取决于 DDR1 的芯片型号,例如对于 MT46V64M8P-5B ,查芯片手册可知,-5B 后缀的 DDR1 在 CAS Latency (CL)=2 时最高时钟频率是 133MHz,则 clk 的上限是 133\*4=532MHz 。
|
||||
|
||||
> 注意:本控制器固定 CAS Latency (CL) = 2。
|
||||
|
||||
另外,时钟频率的上限还受限于 FPGA 的速度,太高的时钟频率容易导致时序不收敛。该控制器充分考虑时序安全设计,大多数寄存器工作在频率较低用户时钟域;个别寄存器工作在用户时钟的 2 倍频率的时钟下,且输入端口的组合逻辑非常短;还有一个寄存器工作在高频的 clk 下,但输入端口直接来自于上一级的寄存器输出(没有组合逻辑)。因此,即使在速度级别很低的 EP4CE6E22C8N 上,在 300MHz 的驱动时钟下也能保证模块正确运行。在速度等级更高的 FPGA (例如 EP4CE22F17C6N)上,驱动时钟的频率可以更高(例如400MHz)。
|
||||
另外,时钟频率的上限还受限于 FPGA 的速度,太高的时钟频率容易导致时序不收敛。本设计充分考虑时序安全设计,大多数寄存器工作在频率较低用户时钟域;个别寄存器工作在用户时钟的 2 倍频率的时钟下,且输入端口的组合逻辑非常短;还有一个寄存器工作在高频的 clk 下,但输入端口直接来自于上一级的寄存器输出(没有组合逻辑)。因此,即使在速度级别很低的 EP4CE6E22C8N 上,在 300MHz 的驱动时钟下也能保证模块正确运行。在速度等级更高的 FPGA (例如 EP4CE22F17C6N)上,驱动时钟的频率可以更高(例如400MHz)。
|
||||
|
||||
## 模块接口:DDR1接口
|
||||
|
||||
@ -163,7 +165,7 @@ rstn 是低电平复位信号,正常工作时应该置高。clk 是驱动时
|
||||
|
||||
可以看出 DDR1 接口的一些信号的位宽是和参数有关的,用户需要根据 DDR1 的芯片选型来确定模块参数。详见 [位宽参数的确定](#位宽参数的确定)。
|
||||
|
||||
想了解 DDR1 接口在初始化、读写、刷新时的波形,请进行 [Verilog仿真](#Verilog仿真)。
|
||||
想了解 DDR1 接口在初始化、读写、刷新时的波形,请进行 [仿真](#仿真)。
|
||||
|
||||
## 模块接口:AXI4从接口
|
||||
|
||||
@ -329,20 +331,24 @@ AXI4 总线的地址(awaddr和araddr)统一是字节地址,模块会根据
|
||||
_______________________
|
||||
ddr_a XXXXXX__RA_XXXXXXX_CA0_X_CA1_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
|
||||
|
||||
# 示例程序
|
||||
|
||||
## 示例程序:自测
|
||||
|
||||
我基于我画的 [FPGA+DDR1测试板](#硬件设计示例) 做了一个 DDR1 读写自测程序,工程目录是 [example-selftest](./example-selftest),请用 Quartus II 13.1 打开它。
|
||||
我基于我画的 [FPGA+DDR1测试板](#硬件设计示例) 做了一个 DDR1 读写自测程序,工程目录是 example-selftest ,请用 Quartus 打开它。
|
||||
|
||||
该工程包含以下文件:
|
||||
|
||||
| 文件名称 | 用途 |
|
||||
| :---- | :--- |
|
||||
| [top.sv](./example-selftest/RTL/top.sv) | 顶层 |
|
||||
| [axi_self_test_master.sv](./example-selftest/RTL/axi_self_test_master.sv) | 是 AXI4 主机,通过 AXI4 先把有规律的数据写入 DDR1,然后读回,比较读回的数据是否符合规律,并对不匹配的情况进行计数。 |
|
||||
| [ddr_sdram_ctrl.sv](./RTL/ddr_sdram_ctrl.sv) | DDR1 控制器 |
|
||||
| [pll.v](./example-selftest/IP/pll.v) | 使用板上 50MHz 晶振产生 300MHz 时钟,输出给 DDR1 控制器 |
|
||||
| example-selftest/RTL/top.sv | 顶层 |
|
||||
| example-selftest/RTL/axi_self_test_master.sv | 是 AXI4 主机,通过 AXI4 先把有规律的数据写入 DDR1,然后读回,比较读回的数据是否符合规律,并对不匹配的情况进行计数。 |
|
||||
| example-selftest/RTL/pll.v | 使用板上 50MHz 晶振产生 300MHz 时钟,输出给 DDR1 控制器 |
|
||||
| /RTL/ddr_sdram_ctrl.sv | DDR1 控制器 |
|
||||
|
||||
该示例程序的行为是:
|
||||
|
||||
**写入**:该工程开始运行后,会先通过 AXI4 把整个 DDR1 都写一遍,直接把地址字写入相应的地址。例如,如果 AXI4 的数据宽度是 16bit,那么地址 0x000002 处写 0x0001。地址 0x123456 处写 0x3456。
|
||||
|
||||
@ -350,28 +356,26 @@ AXI4 总线的地址(awaddr和araddr)统一是字节地址,模块会根据
|
||||
|
||||
**SignalTap抓波形**:该工程包含一个 SignalTap 文件 stp1.stp,在程序运行时,可以用它查看 DDR1 接口上的波形。它以 error=1 为触发信号,因此如果读写自测没有出错,它就不会被触发。因为该工程随时都在读取 DDR1,要想看 DDR1 接口上的波形,直接按“停止”按钮即可。
|
||||
|
||||
**修改 AXI4 突发长度**:在 [top.sv](./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 之间的任意突发长度的。
|
||||
**修改 AXI4 突发长度**:在 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](./example-uart-read-write),请用 Quartus II 13.1 打开它。
|
||||
我基于我画的 [FPGA+DDR1测试板](#硬件设计示例) 做了一个 UART 读写程序,使用该程序,你可以通过 UART 命令,以不同的突发长度来读写 DDR1。工程目录是 example-uart-read-write ,请用 Quartus 打开它。
|
||||
|
||||
该工程包含以下文件:
|
||||
|
||||
| 文件名称 | 用途 |
|
||||
| :---- | :--- |
|
||||
| [top.sv](./example-uart-read-write/RTL/top.sv) | 顶层 |
|
||||
| [uart2axi4.sv](./example-uart-read-write/RTL/uart2axi4.sv) | 是 AXI4 主机,能把 UART RX 收到的命令转换成 AXI4 读写操作,并把读操作读出的数据通过 UART TX 发送出去 |
|
||||
| [uart_rx.sv](./example-uart-read-write/RTL/uart_rx.sv) | UART RX 接收器,被 uart2axi4.sv 调用 |
|
||||
| [axis2uarttx.sv](./example-uart-read-write/RTL/axis2uarttx.sv) | UART TX 发送器,被 uart2axi4.sv 调用 |
|
||||
| [ddr_sdram_ctrl.sv](./RTL/ddr_sdram_ctrl.sv) | DDR1 控制器 |
|
||||
| [pll.v](./example-uart-read-write/IP/pll.v) | 使用板上 50MHz 晶振产生 300MHz 时钟,输出给 DDR1 控制器 |
|
||||
| example-uart-read-write/RTL/top.sv | 顶层 |
|
||||
| example-uart-read-write/RTL/uart2axi4.sv | 是 AXI4 主机,能把 UART RX 收到的命令转换成 AXI4 读写操作,并把读操作读出的数据通过 UART TX 发送出去 |
|
||||
| example-uart-read-write/RTL/pll.v | 使用板上 50MHz 晶振产生 300MHz 时钟,输出给 DDR1 控制器 |
|
||||
| RTL/ddr_sdram_ctrl.sv | DDR1 控制器 |
|
||||
|
||||
[FPGA+DDR1测试板](#硬件设计示例)上有一个 CH340E 芯片(USB 转 UART),因此插上 USB 线后就可以在电脑上看见 UART 对应的 COM 口(需要先在[这里](http://www.wch.cn/product/CH340.html)下载安装 CH341 的驱动)。
|
||||
[FPGA+DDR1测试板](#硬件设计示例)上有一个 CH340E 芯片(USB 转 UART),因此插上 USB 线后就可以在电脑上看见 UART 对应的 COM 口(需要先在 [www.wch.cn/product/CH340.html](http://www.wch.cn/product/CH340.html) 下载安装 CH341 的驱动)。
|
||||
|
||||
工程上传 FPGA 后,双击打开我编写的一个串口小工具 [UartSession.exe](./UartSession.exe) ,根据提示打开板子对应的 COM 口,然后打如下的命令+回车,可以把 0x0123 0x4567 0x89ab 0xcdef 这 4 个数据写入起始地址0x12345。(AXI4总线上会产生一个突发长度为 4 的写操作)。
|
||||
工程上传 FPGA 后,双击打开我编写的一个串口小工具 UartSession.exe ,根据提示打开板子对应的 COM 口,然后打如下的命令+回车,可以把 0x0123 0x4567 0x89ab 0xcdef 这 4 个数据写入起始地址 0x12345。(AXI4总线上会产生一个突发长度为 4 的写操作)。
|
||||
|
||||
w12345 0123 4567 89ab cdef
|
||||
|
||||
@ -381,7 +385,7 @@ AXI4 总线的地址(awaddr和araddr)统一是字节地址,模块会根据
|
||||
|
||||
效果如下图,前4个数据 (0123 4567 89ab cdef) 就是我们已经写入 DDR1 的,后4个数据我们没写过,是 DDR1 初始化后自带的随机数据。
|
||||
|
||||
| ![UART读写](./images/UartSession.png) |
|
||||
| ![](./figures/UartSession.png) |
|
||||
| :--: |
|
||||
| 图:使用 UartSession.exe 测试 DDR1 读写 |
|
||||
|
||||
@ -393,44 +397,33 @@ AXI4 总线的地址(awaddr和araddr)统一是字节地址,模块会根据
|
||||
|
||||
r0 1e
|
||||
|
||||
# Verilog仿真
|
||||
|
||||
|
||||
# 仿真
|
||||
|
||||
## 建立仿真工程
|
||||
|
||||
仿真所需要的文件在目录 [sim-selftest](./sim-selftest) 里,你可以用以下 Verilog 文件建立仿真工程:
|
||||
仿真所需要的文件在目录 SIM 里,其中:
|
||||
|
||||
| 文件路径 | 用途 |
|
||||
| :---- | :--- |
|
||||
| [sim-selftest/SRC/tb_ddr_ctrl.sv](./sim-selftest/SRC/tb_ddr_ctrl.sv) | 仿真顶层 |
|
||||
| [sim-selftest/SRC/axi_self_test_master.sv](./sim-selftest/SRC/axi_self_test_master.sv) | 是 AXI4 主机,通过 AXI4 先把有规律的数据写入 DDR1,然后读回,比较读回的数据是否符合规律,并对不匹配的情况进行计数。 |
|
||||
| [RTL/ddr_sdram_ctrl.sv](./RTL/ddr_sdram_ctrl.sv) | DDR1 控制器 |
|
||||
| [sim-selftest/DDR_MODEL/ddr.v](./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](./sim-selftest/DDR_MODEL/ddr_parameters.vh) | DDR1 仿真模型的参数配置文件 |
|
||||
| tb_ddr_sdram_ctrl.sv | 仿真顶层 |
|
||||
| axi_self_test_master.sv | 是 AXI4 主机,通过 AXI4 先把有规律的数据写入 DDR1,然后读回,比较读回的数据是否符合规律,并对不匹配的情况进行计数。 |
|
||||
| micron_ddr_sdram_model.v | [MICRON 公司提供的 DDR1 仿真模型](https://www.micron.com/products/dram/ddr-sdram/part-catalog/mt46v64m8p-5b) |
|
||||
|
||||
该仿真工程的行为类似[自测程序](#示例程序:自测),[axi_self_test_master.sv](./sim-selftest/SRC/axi_self_test_master.sv) 作为 AXI4 主机,将有规律的数据写入 DDR1 中,只不过不是全部写入,而是只写入 DDR1 的前 16KB (因为仿真模型的存储空间有限),然后一轮一轮地反复读出数据,比较是否有不匹配的数据,若有,则在 error 信号上产生一个时钟周期的高电平。
|
||||
该仿真工程的行为和自测程序一样, axi_self_test_master.sv 作为 AXI4 主机,将有规律的数据写入 DDR1 中,只不过不是全部写入,而是只写入 DDR1 的前 16KB (因为仿真模型的存储空间有限),然后一轮一轮地反复读出数据,比较是否有不匹配的数据,若有,则在 error 信号上产生一个时钟周期的高电平。
|
||||
|
||||
## 运行仿真
|
||||
|
||||
建立工程后,直接运行仿真,得到如下波形。前 294us,AXI4 主机在进行前 16KB 的写入;294us 之后,AXI4 主机在不断的读出数据。error 信号一直为低电平说明读出的数据无误。
|
||||
使用 iverilog 进行仿真前,需要安装 iverilog ,见:[iverilog_usage](https://github.com/WangXuan95/WangXuan95/blob/main/iverilog_usage/iverilog_usage.md)
|
||||
|
||||
| ![仿真波形](./images/sim.png) |
|
||||
| :--: |
|
||||
| 图:仿真波形 |
|
||||
|
||||
你可以展开查看 AXI4 总线和 DDR1 接口的波形细节。这里不做赘述。
|
||||
然后双击 tb_ddr_sdram_ctrl_run_iverilog.bat 运行仿真,然后可以打开生成的 dump.vcd 文件查看波形。
|
||||
|
||||
## 修改仿真参数
|
||||
|
||||
以上仿真默认配置的参数是使用 MT46V64M8 ,即 ROW_BITS=13,COL_BITS=11,DQ_BITS=8。如果想对其它型号的 DDR1 芯片进行仿真,需要修改的参数如下:
|
||||
以上仿真默认配置的参数是使用 MT46V64M8 ,即 ROW_BITS=13,COL_BITS=11,DQ_BITS=8。
|
||||
|
||||
* 仿真顶层中的 **BA_BITS**:见 [sim-selftest/SRC/tb_ddr_ctrl.sv](./sim-selftest/SRC/tb_ddr_ctrl.sv) 第 8 行。
|
||||
* DDR1 模型中的 **BA_BITS**:见 [sim-selftest/DDR_MODEL/ddr_parameters.vh](./sim-selftest/DDR_MODEL/ddr_parameters.vh) 第 35 行。
|
||||
* 仿真顶层中的 **ROW_BITS**:见 [sim-selftest/SRC/tb_ddr_ctrl.sv](./sim-selftest/SRC/tb_ddr_ctrl.sv) 第 9 行。
|
||||
* DDR1 模型中的 **ROW_BITS**:见 [sim-selftest/DDR_MODEL/ddr_parameters.vh](./sim-selftest/DDR_MODEL/ddr_parameters.vh) 第 36 行。
|
||||
* 仿真顶层中的 **COL_BITS**:见 [sim-selftest/SRC/tb_ddr_ctrl.sv](./sim-selftest/SRC/tb_ddr_ctrl.sv) 第 10 行。
|
||||
* DDR1 模型中的 **COL_BITS**:见 [sim-selftest/DDR_MODEL/ddr_parameters.vh](./sim-selftest/DDR_MODEL/ddr_parameters.vh) 第 37 行。
|
||||
* 仿真顶层中的 **DQ_LEVEL**:见 [sim-selftest/SRC/tb_ddr_ctrl.sv](./sim-selftest/SRC/tb_ddr_ctrl.sv) 第 11 行。
|
||||
* DDR1 模型中的 **DQ_BITS**:见 [sim-selftest/DDR_MODEL/ddr_parameters.vh](./sim-selftest/DDR_MODEL/ddr_parameters.vh) 第 38 行。
|
||||
如果想对其它型号的 DDR1 芯片进行仿真,你需要在 tb_ddr_sdram_ctrl.sv 和 micron_ddr_sdram_model.v 里修改它们(注意两个文件要同步修改!)
|
||||
|
||||
对于 MICRON 公司的 DDR1 系列,这些参数应该这样修改:
|
||||
|
||||
@ -446,7 +439,9 @@ AXI4 总线的地址(awaddr和araddr)统一是字节地址,模块会根据
|
||||
| MT46V32M16 | 2 | 13 | 10 | 2 | 16 |
|
||||
| MT46V64M16 | 2 | 14 | 10 | 2 | 16 |
|
||||
|
||||
另外,你可以修改 [tb_ddr_ctrl.sv](./sim-selftest/SRC/tb_ddr_ctrl.sv) 的第 18 和 19 行来修改仿真时的突发读写的长度。
|
||||
另外,你可以修改 tb_ddr_sdram_ctrl.sv 的第 18 和 19 行来修改仿真时的突发读写的长度。
|
||||
|
||||
|
||||
|
||||
# 参考资料
|
||||
|
||||
|
@ -1,4 +1,11 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// Module : ddr_sdram_ctrl
|
||||
// Type : synthesizable, IP's top
|
||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
||||
// Function: DDR-SDRAM (DDR1) controller
|
||||
// with AXI4 interface
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
module ddr_sdram_ctrl #(
|
||||
parameter READ_BUFFER = 1,
|
||||
@ -14,9 +21,9 @@ module ddr_sdram_ctrl #(
|
||||
parameter [7:0] tR2I = 8'd7
|
||||
) (
|
||||
// driving clock and reset
|
||||
input wire rstn,
|
||||
input wire rstn_async,
|
||||
input wire clk, // driving clock, typically 300~532MHz
|
||||
// user interface ( meta AXI4 )
|
||||
// user interface ( AXI4 )
|
||||
output reg aresetn,
|
||||
output reg aclk, // freq = F(clk)/4
|
||||
input wire awvalid,
|
||||
@ -53,17 +60,16 @@ module ddr_sdram_ctrl #(
|
||||
|
||||
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 clk2 = '0;
|
||||
reg init_done = '0;
|
||||
reg [2:0] ref_idle = 3'd1, ref_real = '0;
|
||||
reg [9:0] ref_cnt = '0;
|
||||
reg [7:0] cnt = '0;
|
||||
enum logic [3:0] {RESET, IDLE, CLEARDLL, REFRESH, WPRE, WRITE, WRESP, WWAIT, RPRE, READ, RRESP, RWAIT} stat = RESET;
|
||||
|
||||
reg [7:0] burst_len;
|
||||
reg [7:0] burst_len = '0;
|
||||
wire burst_last = cnt==burst_len;
|
||||
reg [DQ_LEVEL-1:0] trash_lsb_addr;
|
||||
reg [COL_BITS-2:0] col_addr;
|
||||
reg [COL_BITS-2:0] col_addr = '0;
|
||||
|
||||
wire [ROW_BITS-1:0] ddr_a_col;
|
||||
generate if(COL_BITS>10) begin
|
||||
@ -73,55 +79,77 @@ end else begin
|
||||
end endgenerate
|
||||
|
||||
wire read_accessible, read_respdone;
|
||||
reg output_enable, output_enable_d1, output_enable_d2;
|
||||
reg output_enable='0, output_enable_d1='0, output_enable_d2='0;
|
||||
|
||||
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 o_v_a = '0;
|
||||
reg [(4<<DQ_LEVEL)-1:0] o_dh_a = '0;
|
||||
reg [(4<<DQ_LEVEL)-1:0] o_dl_a = '0;
|
||||
reg o_v_b = '0;
|
||||
reg [(4<<DQ_LEVEL)-1:0] o_dh_b = '0;
|
||||
reg o_dqs_c = '0;
|
||||
reg [(4<<DQ_LEVEL)-1:0] o_d_c = '0;
|
||||
reg [(4<<DQ_LEVEL)-1:0] o_d_d = '0;
|
||||
|
||||
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;
|
||||
reg i_v_a = '0;
|
||||
reg i_l_a = '0;
|
||||
reg i_v_b = '0;
|
||||
reg i_l_b = '0;
|
||||
reg i_v_c = '0;
|
||||
reg i_l_c = '0;
|
||||
reg i_dqs_c = '0;
|
||||
reg [(4<<DQ_LEVEL)-1:0] i_d_c = '0;
|
||||
reg i_v_d = '0;
|
||||
reg i_l_d = '0;
|
||||
reg [(8<<DQ_LEVEL)-1:0] i_d_d = '0;
|
||||
reg i_v_e = '0;
|
||||
reg i_l_e = '0;
|
||||
reg [(8<<DQ_LEVEL)-1:0] i_d_e = '0;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// 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
|
||||
localparam [ROW_BITS-1:0] DDR_A_DEFAULT = (ROW_BITS)'('b0100_0000_0000);
|
||||
localparam [ROW_BITS-1:0] DDR_A_MR0 = (ROW_BITS)'('b0001_0010_1001);
|
||||
localparam [ROW_BITS-1:0] DDR_A_MR_CLEAR_DLL = (ROW_BITS)'('b0000_0010_1001);
|
||||
|
||||
|
||||
initial ddr_cs_n = 1'b1;
|
||||
initial ddr_ras_n = 1'b1;
|
||||
initial ddr_cas_n = 1'b1;
|
||||
initial ddr_we_n = 1'b1;
|
||||
initial ddr_ba = '0;
|
||||
initial ddr_a = DDR_A_DEFAULT;
|
||||
|
||||
initial {aresetn, aclk} = '0;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// generate reset sync with clk
|
||||
// -------------------------------------------------------------------------------------
|
||||
reg rstn_clk = '0;
|
||||
reg [1:0] rstn_clk_l = '0;
|
||||
always @ (posedge clk or negedge rstn_async)
|
||||
if(~rstn_async)
|
||||
{rstn_clk, rstn_clk_l} <= '0;
|
||||
else
|
||||
{rstn_clk, rstn_clk_l} <= {rstn_clk_l, 1'b1};
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// generate reset sync with aclk
|
||||
// -------------------------------------------------------------------------------------
|
||||
reg rstn_aclk = '0;
|
||||
reg [1:0] rstn_aclk_l = '0;
|
||||
always @ (posedge aclk or negedge rstn_async)
|
||||
if(~rstn_async)
|
||||
{rstn_aclk, rstn_aclk_l} <= '0;
|
||||
else
|
||||
{rstn_aclk, rstn_aclk_l} <= {rstn_aclk_l, 1'b1};
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// generate clocks
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if(~rstn)
|
||||
always @ (posedge clk or negedge rstn_clk)
|
||||
if(~rstn_clk)
|
||||
{aclk,clk2} <= 2'b00;
|
||||
else
|
||||
{aclk,clk2} <= {aclk,clk2} + 2'b01;
|
||||
@ -129,8 +157,8 @@ always @ (posedge clk or negedge rstn)
|
||||
// -------------------------------------------------------------------------------------
|
||||
// generate user reset
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge aclk or negedge rstn)
|
||||
if(~rstn)
|
||||
always @ (posedge aclk or negedge rstn_aclk)
|
||||
if(~rstn_aclk)
|
||||
aresetn <= 1'b0;
|
||||
else
|
||||
aresetn <= init_done;
|
||||
@ -138,8 +166,8 @@ always @ (posedge aclk or negedge rstn)
|
||||
// -------------------------------------------------------------------------------------
|
||||
// refresh wptr self increasement
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge aclk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
always @ (posedge aclk or negedge rstn_aclk)
|
||||
if(~rstn_aclk) begin
|
||||
ref_cnt <= '0;
|
||||
ref_idle <= 3'd1;
|
||||
end else begin
|
||||
@ -178,8 +206,8 @@ assign arready = stat==IDLE && init_done && ref_real==ref_idle && ~awvalid && re
|
||||
// -------------------------------------------------------------------------------------
|
||||
// main FSM for generating DDR-SDRAM behavior
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge aclk or negedge rstn)
|
||||
if(~rstn) begin
|
||||
always @ (posedge aclk or negedge rstn_aclk)
|
||||
if(~rstn_aclk) begin
|
||||
ddr_cs_n <= 1'b1;
|
||||
ddr_ras_n <= 1'b1;
|
||||
ddr_cas_n <= 1'b1;
|
||||
@ -231,18 +259,12 @@ always @ (posedge aclk or negedge rstn)
|
||||
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;
|
||||
{ddr_ba, ddr_a, col_addr} <= awaddr[BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-2:DQ_LEVEL];
|
||||
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;
|
||||
{ddr_ba, ddr_a, col_addr} <= araddr[BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-2:DQ_LEVEL];
|
||||
burst_len <= arlen;
|
||||
stat <= RPRE;
|
||||
end
|
||||
@ -388,7 +410,7 @@ always @ (posedge aclk or negedge aresetn)
|
||||
// -------------------------------------------------------------------------------------
|
||||
// dq and dqs generate for output (write)
|
||||
// -------------------------------------------------------------------------------------
|
||||
always @ (posedge clk2) begin
|
||||
always @ (posedge clk2)
|
||||
if(~aclk) begin
|
||||
o_dqs_c <= 1'b0;
|
||||
o_d_c <= o_v_a ? o_dl_a : '0;
|
||||
@ -396,7 +418,6 @@ always @ (posedge clk2) begin
|
||||
o_dqs_c <= o_v_b;
|
||||
o_d_c <= o_v_b ? o_dh_b : '0;
|
||||
end
|
||||
end
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// dq delay for output (write)
|
||||
@ -446,20 +467,60 @@ always @ (posedge aclk or negedge aresetn)
|
||||
// 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} )
|
||||
);
|
||||
|
||||
localparam AWIDTH = 10;
|
||||
localparam DWIDTH = 1 + (8<<DQ_LEVEL);
|
||||
|
||||
reg [AWIDTH-1:0] wpt = '0, rpt = '0;
|
||||
reg dvalid = '0, valid = '0;
|
||||
reg [DWIDTH-1:0] datareg = '0;
|
||||
|
||||
wire rreq;
|
||||
reg [DWIDTH-1:0] fifo_rdata;
|
||||
|
||||
wire emptyn = rpt != wpt;
|
||||
|
||||
wire itready = rpt != (wpt + (AWIDTH)'(1));
|
||||
assign rvalid = valid | dvalid;
|
||||
assign rreq = emptyn & ( rready | ~rvalid );
|
||||
assign {rlast, rdata} = dvalid ? fifo_rdata : datareg;
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn)
|
||||
wpt <= 0;
|
||||
else if(i_v_e & itready)
|
||||
wpt <= wpt + (AWIDTH)'(1);
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn)
|
||||
rpt <= 0;
|
||||
else if(rreq & emptyn)
|
||||
rpt <= rpt + (AWIDTH)'(1);
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
dvalid <= 1'b0;
|
||||
valid <= 1'b0;
|
||||
datareg <= 0;
|
||||
end else begin
|
||||
dvalid <= rreq;
|
||||
if(dvalid)
|
||||
datareg <= fifo_rdata;
|
||||
if(rready)
|
||||
valid <= 1'b0;
|
||||
else if(dvalid)
|
||||
valid <= 1'b1;
|
||||
end
|
||||
|
||||
reg [DWIDTH-1:0] mem [(1<<AWIDTH)];
|
||||
|
||||
always @ (posedge aclk)
|
||||
if(i_v_e)
|
||||
mem[wpt] <= {i_l_e, i_d_e};
|
||||
|
||||
always @ (posedge aclk)
|
||||
fifo_rdata <= mem[rpt];
|
||||
|
||||
assign read_accessible = ~rvalid;
|
||||
assign read_respdone = rvalid;
|
||||
end else begin
|
||||
@ -471,123 +532,3 @@ end else begin
|
||||
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
|
||||
|
@ -1,4 +1,11 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// Module : axi_self_test_master
|
||||
// Type : synthesizable
|
||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
||||
// Function: write increase data to AXI4 slave,
|
||||
// then read data and check whether they are increasing
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
module axi_self_test_master #(
|
||||
parameter A_WIDTH_TEST = 26,
|
||||
@ -32,10 +39,13 @@ module axi_self_test_master #(
|
||||
output reg [ 15:0] error_cnt
|
||||
);
|
||||
|
||||
initial {awaddr, araddr} = '0;
|
||||
initial {error, error_cnt} = '0;
|
||||
|
||||
wire aw_end;
|
||||
reg awaddr_carry;
|
||||
reg [7:0] w_cnt;
|
||||
enum logic [2:0] {INIT, AW, W, B, AR, R} stat;
|
||||
reg awaddr_carry = '0;
|
||||
reg [7:0] w_cnt = '0;
|
||||
enum logic [2:0] {INIT, AW, W, B, AR, R} stat = INIT;
|
||||
|
||||
generate if(A_WIDTH_TEST<A_WIDTH)
|
||||
assign aw_end = awaddr[A_WIDTH_TEST];
|
||||
@ -47,12 +57,14 @@ assign awvalid = stat==AW;
|
||||
assign awlen = WBURST_LEN;
|
||||
assign wvalid = stat==W;
|
||||
assign wlast = w_cnt==WBURST_LEN;
|
||||
assign wdata = awaddr;
|
||||
assign wdata = (D_WIDTH)'(awaddr);
|
||||
assign bready = 1'b1;
|
||||
assign arvalid = stat==AR;
|
||||
assign arlen = RBURST_LEN;
|
||||
assign rready = 1'b1;
|
||||
|
||||
wire [A_WIDTH:0] araddr_next = {1'b0,araddr} + (A_WIDTH+1)'(1<<D_LEVEL);
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
{awaddr_carry, awaddr} <= '0;
|
||||
@ -72,7 +84,7 @@ always @ (posedge aclk or negedge aresetn)
|
||||
stat <= W;
|
||||
end
|
||||
W: if(wready) begin
|
||||
{awaddr_carry, awaddr} <= {awaddr_carry, awaddr} + (1<<D_LEVEL);
|
||||
{awaddr_carry, awaddr} <= {awaddr_carry, awaddr} + (A_WIDTH+1)'(1<<D_LEVEL);
|
||||
w_cnt <= w_cnt + 8'd1;
|
||||
if(wlast)
|
||||
stat <= B;
|
||||
@ -84,8 +96,6 @@ always @ (posedge aclk or negedge aresetn)
|
||||
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;
|
||||
@ -99,7 +109,7 @@ always @ (posedge aclk or negedge aresetn)
|
||||
// ------------------------------------------------------------
|
||||
// read and write mismatch detect
|
||||
// ------------------------------------------------------------
|
||||
wire [D_WIDTH-1:0] rdata_idle = araddr;
|
||||
wire [D_WIDTH-1:0] rdata_idle = (D_WIDTH)'(araddr);
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
error <= 1'b0;
|
@ -80,10 +80,105 @@
|
||||
|
||||
// DO NOT CHANGE THE TIMESCALE
|
||||
// MAKE SURE YOUR SIMULATOR USE "PS" RESOLUTION
|
||||
`timescale 1ns / 1ps
|
||||
`timescale 1ps/1ps
|
||||
|
||||
module micron_ddr_sdram_model (Clk, Clk_n, Cke, Cs_n, Ras_n, Cas_n, We_n, Ba , Addr, Dm, Dq, Dqs);
|
||||
|
||||
`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
|
||||
|
||||
module ddr (Clk, Clk_n, Cke, Cs_n, Ras_n, Cas_n, We_n, Ba , Addr, Dm, Dq, Dqs);
|
||||
`include "ddr_parameters.vh"
|
||||
|
||||
// Port Declarations
|
||||
input Clk;
|
@ -1,6 +1,20 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
module tb_ddr_ctrl();
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// Module : tb_ddr_sdram_ctrl
|
||||
// Type : simulation, top
|
||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
||||
// Function: testbench for ddr_sdram_ctrl
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
`timescale 1ps/1ps
|
||||
|
||||
module tb_ddr_sdram_ctrl();
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// simulation control
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
initial $dumpvars(0, tb_ddr_sdram_ctrl);
|
||||
initial #200000000 $finish; // simulation for 200us
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// DDR-SDRAM parameters
|
||||
@ -28,7 +42,7 @@ localparam D_WIDTH = (8<<DQ_LEVEL);
|
||||
// driving clock and reset generate
|
||||
// -------------------------------------------------------------------------------------
|
||||
reg rstn=1'b0, clk300m=1'b1;
|
||||
always #1.6667 clk300m = ~clk300m;
|
||||
always #1667 clk300m = ~clk300m;
|
||||
initial begin repeat(4) @(posedge clk300m); rstn<=1'b1; end
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
@ -76,8 +90,8 @@ wire error;
|
||||
// meta AXI4 master for testing
|
||||
// -------------------------------------------------------------------------------------
|
||||
axi_self_test_master #(
|
||||
.A_WIDTH_TEST( 12 ),
|
||||
.A_WIDTH ( A_WIDTH ),
|
||||
.A_WIDTH_TEST( 14 ),
|
||||
.D_WIDTH ( D_WIDTH ),
|
||||
.D_LEVEL ( DQ_LEVEL ),
|
||||
.WBURST_LEN ( WBURST_LEN ),
|
||||
@ -120,7 +134,7 @@ ddr_sdram_ctrl #(
|
||||
.tW2I ( 8'd6 ),
|
||||
.tR2I ( 8'd6 )
|
||||
) ddr_sdram_ctrl_i (
|
||||
.rstn ( rstn ),
|
||||
.rstn_async ( rstn ),
|
||||
.clk ( clk300m ),
|
||||
.aresetn ( aresetn ),
|
||||
.aclk ( aclk ),
|
||||
@ -157,9 +171,9 @@ ddr_sdram_ctrl #(
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// DDR-SDRAM simulation model
|
||||
// MICRON DDR-SDRAM simulation model
|
||||
// -------------------------------------------------------------------------------------
|
||||
ddr ddr_i (
|
||||
micron_ddr_sdram_model ddr_model_i (
|
||||
.Clk ( ddr_ck_p ),
|
||||
.Clk_n ( ddr_ck_n ),
|
||||
.Cke ( ddr_cke ),
|
5
SIM/tb_ddr_sdram_ctrl_run_iverilog.bat
Normal file
5
SIM/tb_ddr_sdram_ctrl_run_iverilog.bat
Normal file
@ -0,0 +1,5 @@
|
||||
del sim.out dump.vcd
|
||||
iverilog -g2005-sv -o sim.out tb_ddr_sdram_ctrl.sv axi_self_test_master.sv micron_ddr_sdram_model.v ../RTL/ddr_sdram_ctrl.sv
|
||||
vvp -n sim.out
|
||||
del sim.out
|
||||
pause
|
@ -1,4 +1,11 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// Module : axi_self_test_master
|
||||
// Type : synthesizable
|
||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
||||
// Function: write increase data to AXI4 slave,
|
||||
// then read data and check whether they are increasing
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
module axi_self_test_master #(
|
||||
parameter A_WIDTH_TEST = 26,
|
||||
@ -32,10 +39,13 @@ module axi_self_test_master #(
|
||||
output reg [ 15:0] error_cnt
|
||||
);
|
||||
|
||||
initial {awaddr, araddr} = '0;
|
||||
initial {error, error_cnt} = '0;
|
||||
|
||||
wire aw_end;
|
||||
reg awaddr_carry;
|
||||
reg [7:0] w_cnt;
|
||||
enum logic [2:0] {INIT, AW, W, B, AR, R} stat;
|
||||
reg awaddr_carry = '0;
|
||||
reg [7:0] w_cnt = '0;
|
||||
enum logic [2:0] {INIT, AW, W, B, AR, R} stat = INIT;
|
||||
|
||||
generate if(A_WIDTH_TEST<A_WIDTH)
|
||||
assign aw_end = awaddr[A_WIDTH_TEST];
|
||||
@ -47,12 +57,14 @@ assign awvalid = stat==AW;
|
||||
assign awlen = WBURST_LEN;
|
||||
assign wvalid = stat==W;
|
||||
assign wlast = w_cnt==WBURST_LEN;
|
||||
assign wdata = awaddr;
|
||||
assign wdata = (D_WIDTH)'(awaddr);
|
||||
assign bready = 1'b1;
|
||||
assign arvalid = stat==AR;
|
||||
assign arlen = RBURST_LEN;
|
||||
assign rready = 1'b1;
|
||||
|
||||
wire [A_WIDTH:0] araddr_next = {1'b0,araddr} + (A_WIDTH+1)'(1<<D_LEVEL);
|
||||
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
{awaddr_carry, awaddr} <= '0;
|
||||
@ -72,7 +84,7 @@ always @ (posedge aclk or negedge aresetn)
|
||||
stat <= W;
|
||||
end
|
||||
W: if(wready) begin
|
||||
{awaddr_carry, awaddr} <= {awaddr_carry, awaddr} + (1<<D_LEVEL);
|
||||
{awaddr_carry, awaddr} <= {awaddr_carry, awaddr} + (A_WIDTH+1)'(1<<D_LEVEL);
|
||||
w_cnt <= w_cnt + 8'd1;
|
||||
if(wlast)
|
||||
stat <= B;
|
||||
@ -84,8 +96,6 @@ always @ (posedge aclk or negedge aresetn)
|
||||
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;
|
||||
@ -99,7 +109,7 @@ always @ (posedge aclk or negedge aresetn)
|
||||
// ------------------------------------------------------------
|
||||
// read and write mismatch detect
|
||||
// ------------------------------------------------------------
|
||||
wire [D_WIDTH-1:0] rdata_idle = araddr;
|
||||
wire [D_WIDTH-1:0] rdata_idle = (D_WIDTH)'(araddr);
|
||||
always @ (posedge aclk or negedge aresetn)
|
||||
if(~aresetn) begin
|
||||
error <= 1'b0;
|
||||
|
@ -1,6 +1,14 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
module top(
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// Module : top
|
||||
// Type : synthesizable, FPGA's top, IP's example design
|
||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
||||
// Function: an example of ddr_sdram_ctrl,
|
||||
// write increase data to DDR,
|
||||
// then read data and check whether they are increasing
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
module top (
|
||||
input wire clk50m,
|
||||
|
||||
output wire ddr_ck_p, ddr_ck_n,
|
||||
@ -75,8 +83,8 @@ pll pll_i(
|
||||
// meta AXI4 master for testing
|
||||
// -------------------------------------------------------------------------------------
|
||||
axi_self_test_master #(
|
||||
.A_WIDTH ( A_WIDTH ),
|
||||
.A_WIDTH_TEST( A_WIDTH ),
|
||||
.A_WIDTH ( A_WIDTH ),
|
||||
.D_WIDTH ( D_WIDTH ),
|
||||
.D_LEVEL ( DQ_LEVEL ),
|
||||
.WBURST_LEN ( 8'd15 ),
|
||||
@ -119,7 +127,7 @@ ddr_sdram_ctrl #(
|
||||
.tW2I ( 8'd7 ),
|
||||
.tR2I ( 8'd7 )
|
||||
) ddr_ctrl_i(
|
||||
.rstn ( rstn ),
|
||||
.rstn_async ( rstn ),
|
||||
.clk ( clk300m ),
|
||||
.aresetn ( aresetn ),
|
||||
.aclk ( aclk ),
|
||||
|
@ -41,7 +41,7 @@ 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 LAST_QUARTUS_VERSION "18.1.0 Standard Edition"
|
||||
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
|
||||
@ -129,11 +129,13 @@ set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_ADVANCED_TRIGGER_
|
||||
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 VERILOG_FILE RTL/pll.v
|
||||
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
|
||||
@ -173,7 +175,42 @@ set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[34] -t
|
||||
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_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_STORAGE_QUALIFIER_BITS=47" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_INCREMENTAL_ROUTING=1" -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[0] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[1] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[2] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[3] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[4] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[5] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[6] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[7] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[8] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[9] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[10] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[11] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[12] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[13] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[14] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[15] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[16] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[17] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[18] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[19] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[20] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[21] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[22] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[23] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[24] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[25] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[26] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[27] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[28] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[29] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[30] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[31] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_PIPELINE=0" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_RAM_PIPELINE=0" -section_id auto_signaltap_0
|
||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_COUNTER_PIPELINE=0" -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
|
@ -1,138 +0,0 @@
|
||||
|
||||
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
|
@ -1,6 +1,13 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
module top(
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// Module : top
|
||||
// Type : synthesizable, FPGA's top, IP's example design
|
||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
||||
// Function: an example of ddr_sdram_ctrl,
|
||||
// use UART command to read/write DDR
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
module top (
|
||||
input wire clk50m,
|
||||
|
||||
output wire uart_tx,
|
||||
@ -114,7 +121,7 @@ ddr_sdram_ctrl #(
|
||||
.tW2I ( 8'd7 ),
|
||||
.tR2I ( 8'd7 )
|
||||
) ddr_ctrl_i(
|
||||
.rstn ( rstn ),
|
||||
.rstn_async ( rstn ),
|
||||
.clk ( clk300m ),
|
||||
.aresetn ( aresetn ),
|
||||
.aclk ( aclk ),
|
||||
|
@ -1,4 +1,10 @@
|
||||
`timescale 1 ns/1 ns
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// Module : uart2axi4
|
||||
// Type : synthesizable
|
||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
||||
// Function: convert UART command to AXI4 read/write action
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
module uart2axi4 #(
|
||||
parameter A_WIDTH = 26,
|
||||
@ -263,3 +269,232 @@ always @ (posedge clk)
|
||||
mem[wr_addr] <= wr_data;
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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 {4'h3, hex} + ((hex<4'hA) ? 8'h0 : 8'h7) ;
|
||||
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 <= 8'h0A;
|
||||
else
|
||||
txshift <= 8'h20;
|
||||
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
|
||||
|
||||
|
@ -1,71 +0,0 @@
|
||||
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
|
@ -41,19 +41,18 @@ 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 LAST_QUARTUS_VERSION "18.1.0 Standard Edition"
|
||||
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_global_assignment -name VERILOG_FILE RTL/pll.v
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE ../RTL/ddr_sdram_ctrl.sv
|
||||
|
||||
set_location_assignment PIN_23 -to clk50m
|
||||
|
||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
BIN
images/sim.png
BIN
images/sim.png
Binary file not shown.
Before Width: | Height: | Size: 34 KiB |
@ -1,124 +0,0 @@
|
||||
/****************************************************************************************
|
||||
*
|
||||
* 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
|
Loading…
x
Reference in New Issue
Block a user