From 3a71549cb87e1fbcef2be57eb68c63bab6ba810d Mon Sep 17 00:00:00 2001 From: WangXuan95 <629708558@qq.com> Date: Wed, 30 Mar 2022 02:03:32 +0800 Subject: [PATCH] update --- {hardware => PCB}/gerber.zip | Bin {hardware => PCB}/sch.pdf | 0 README.md | 117 +++--- RTL/ddr_sdram_ctrl.sv | 343 ++++++++---------- .../SRC => SIM}/axi_self_test_master.sv | 28 +- .../ddr.v => SIM/micron_ddr_sdram_model.v | 101 +++++- .../tb_ddr_sdram_ctrl.sv | 28 +- SIM/tb_ddr_sdram_ctrl_run_iverilog.bat | 5 + example-selftest/RTL/axi_self_test_master.sv | 30 +- example-selftest/{IP => RTL}/pll.v | 0 example-selftest/RTL/top.sv | 16 +- example-selftest/ddr_test.qsf | 45 ++- example-uart-read-write/RTL/axis2uarttx.sv | 138 ------- example-uart-read-write/{IP => RTL}/pll.v | 0 example-uart-read-write/RTL/top.sv | 13 +- example-uart-read-write/RTL/uart2axi4.sv | 237 +++++++++++- example-uart-read-write/RTL/uart_rx.sv | 71 ---- example-uart-read-write/ddr_test.qsf | 9 +- {images => figures}/UartSession.png | Bin {images => figures}/board.jpg | Bin images/sim.png | Bin 35139 -> 0 bytes sim-selftest/DDR_MODEL/ddr_parameters.vh | 124 ------- 22 files changed, 664 insertions(+), 641 deletions(-) rename {hardware => PCB}/gerber.zip (100%) rename {hardware => PCB}/sch.pdf (100%) rename {sim-selftest/SRC => SIM}/axi_self_test_master.sv (76%) rename sim-selftest/DDR_MODEL/ddr.v => SIM/micron_ddr_sdram_model.v (86%) rename sim-selftest/SRC/tb_ddr_ctrl.sv => SIM/tb_ddr_sdram_ctrl.sv (84%) create mode 100644 SIM/tb_ddr_sdram_ctrl_run_iverilog.bat rename example-selftest/{IP => RTL}/pll.v (100%) delete mode 100644 example-uart-read-write/RTL/axis2uarttx.sv rename example-uart-read-write/{IP => RTL}/pll.v (100%) delete mode 100644 example-uart-read-write/RTL/uart_rx.sv rename {images => figures}/UartSession.png (100%) rename {images => figures}/board.jpg (100%) delete mode 100644 images/sim.png delete mode 100644 sim-selftest/DDR_MODEL/ddr_parameters.vh diff --git a/hardware/gerber.zip b/PCB/gerber.zip similarity index 100% rename from hardware/gerber.zip rename to PCB/gerber.zip diff --git a/hardware/sch.pdf b/PCB/sch.pdf similarity index 100% rename from hardware/sch.pdf rename to PCB/sch.pdf diff --git a/README.md b/README.md index aa66d06..41a339e 100644 --- a/README.md +++ b/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 行来修改仿真时的突发读写的长度。 + + # 参考资料 diff --git a/RTL/ddr_sdram_ctrl.sv b/RTL/ddr_sdram_ctrl.sv index 48a7eef..865bb03 100644 --- a/RTL/ddr_sdram_ctrl.sv +++ b/RTL/ddr_sdram_ctrl.sv @@ -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<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<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<=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 <= (cyccnt1) + 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<=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 \ No newline at end of file diff --git a/example-uart-read-write/ddr_test.qsf b/example-uart-read-write/ddr_test.qsf index bb6648c..acfad47 100644 --- a/example-uart-read-write/ddr_test.qsf +++ b/example-uart-read-write/ddr_test.qsf @@ -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 diff --git a/images/UartSession.png b/figures/UartSession.png similarity index 100% rename from images/UartSession.png rename to figures/UartSession.png diff --git a/images/board.jpg b/figures/board.jpg similarity index 100% rename from images/board.jpg rename to figures/board.jpg diff --git a/images/sim.png b/images/sim.png deleted file mode 100644 index b0df3e588012714506607d14a244c4f5ff2d3d39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35139 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 diff --git a/sim-selftest/DDR_MODEL/ddr_parameters.vh b/sim-selftest/DDR_MODEL/ddr_parameters.vh deleted file mode 100644 index 6c37045..0000000 --- a/sim-selftest/DDR_MODEL/ddr_parameters.vh +++ /dev/null @@ -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