This commit is contained in:
WangXuan95 2022-04-01 21:15:25 +08:00
parent 9bf35a21cd
commit 0ffcfda9c3
12 changed files with 230 additions and 561 deletions

View File

@ -6,16 +6,16 @@ FPGA DDR-SDRAM
# 简介
|-------------------------| |--------------|
| | | |
----->| 驱动时钟和复位 | | |
| | | |
------------| | DDR-SDRAM接口 |--------->| |
| AXI4 | | | |
AXI4 master |----------->| AXI4 slave | | |
| | | | |
------------| |-------------------------| |--------------|
用户逻辑 DDR1 控制器 DDR1 芯片
|------------------------------| |-----------|
| | | |
----->| driving clock and reset | | |
| | | |
------------| | DDR-SDRAM interface |--------->| |
| AXI4 | | | |
AXI4 master |-------->| AXI4 slave | | |
| | | | |
------------| |------------------------------| |-----------|
用户逻辑 DDR1 控制器 DDR1 芯片
很多低端 FPGA 开发板使用 SDR-SDRAM 作为片外存储,而 DDR-SDRAM (DDR1) 比 SDR-SDRAM 容量更大价格更低。且与SDR-SDRAM一样DDR1也能使用低端FPGA的普通的IO管脚直接驱动。我编写了一个软核的 AXI4 接口的 DDR1 控制器。该控制器的特点有:
@ -80,7 +80,7 @@ FPGA DDR-SDRAM
| :---: |
| 图FPGA + DDR1 测试板 |
原理图见 PCB/sch.pdf PCB制造文件见 PCB/gerber.zip ,在布局布线时,使用双层板即可,不需像 DDR2 以上的设计那样刻意注意等长和阻抗匹配,因为该电路工作频率为双边沿 75MHz不是特别高只需注意让FPGA与DDR距离尽量近布线尽量短即可。比如我在布局时,把DDR1芯片放在了FPGA芯片正对的背面从而保证布线都较短。
该板子的原理图见 PCB/sch.pdf PCB制造文件见 PCB/gerber.zip 。它是个双层板,不需像 DDR2 、 DDR3 那样刻意注意等长和阻抗匹配,因为该电路工作频率为双边沿 75MHz不是特别高只需注意让FPGA与DDR距离尽量近布线尽量短即可。比如我把DDR1芯片放在了FPGA芯片正对的背面从而保证布线都较短。
该板子的设计在立创EDA中开放见 [oshwhub.com/wangxuan/fpga-ddr-ce-shi-ban](https://oshwhub.com/wangxuan/fpga-ddr-ce-shi-ban)。
@ -122,28 +122,28 @@ module ddr_sdram_ctrl #(
## 模块接口:驱动时钟和复位
该模块需要一个时钟和一个复位进行驱动,如下:
该模块需要一个驱动时钟和一个驱动复位,如下:
```Verilog
input wire rstn_async,
input wire clk,
input wire drv_clk,
```
rstn_async 是低电平复位信号正常工作时应该置高。clk 是驱动时钟,频率是用户时钟的 4 倍。
rstn_async 是低电平复位信号,正常工作时应该置高。drv_clk 是驱动时钟,频率是用户时钟的 4 倍。
模块开始工作前rstn_async 信号应该置低,让模块复位,然后把 rstn_async 置高,解除复位。
## 时钟频率的选取
模块内将驱动时钟 clk 分频 4 倍产生 DDR1 时钟ddr_ck_p/ddr_ck_n和 AXI4 总线用户时钟(aclk。本节讲述如何决定驱动时钟 clk 的频率。
模块内将驱动时钟 drv_clk 分频 4 倍产生 DDR1 时钟ddr_ck_p/ddr_ck_n和 AXI4 总线用户时钟clk。本节讲述如何决定驱动时钟 drv_clk 的频率。
首先,时钟频率受限于 DDR1 芯片。考虑到所有的 DDR1 的接口频率至少为 75MHz ,则 clk 的下限是 75\*4=300MHz。
首先,时钟频率受限于 DDR1 芯片。考虑到所有的 DDR1 的接口频率至少为 75MHz ,则 drv_clk 的下限是 75\*4=300MHz。
而 clk 的上限就也取决于 DDR1 的芯片型号,例如对于 MT46V64M8P-5B ,查芯片手册可知,-5B 后缀的 DDR1 在 CAS Latency (CL)=2 时最高时钟频率是 133MHz则 clk 的上限是 133\*4=532MHz 。
drv_clk 的上限就也取决于 DDR1 的芯片型号,例如对于 MT46V64M8P-5B ,查芯片手册可知,-5B 后缀的 DDR1 在 CAS Latency (CL)=2 时最高时钟频率是 133MHzdrv_clk 的上限是 133\*4=532MHz 。
> 注意:本控制器固定 CAS Latency (CL) = 2。
另外,时钟频率的上限还受限于 FPGA 的速度,太高的时钟频率容易导致时序不收敛。本设计充分考虑时序安全设计,大多数寄存器工作在频率较低用户时钟域;个别寄存器工作在用户时钟的 2 倍频率的时钟下,且输入端口的组合逻辑非常短;还有一个寄存器工作在高频的 clk 下,但输入端口直接来自于上一级的寄存器输出(没有组合逻辑)。因此,即使在速度级别很低的 EP4CE6E22C8N 上,在 300MHz 的驱动时钟下也能保证模块正确运行。在速度等级更高的 FPGA (例如 EP4CE22F17C6N驱动时钟的频率可以更高例如400MHz
另外,时钟频率的上限还受限于 FPGA 的速度,太高的时钟频率容易导致时序不收敛。本设计充分考虑时序安全设计,大多数寄存器工作在频率较低 clk 时钟域;个别寄存器工作在 clk 时钟的 2 倍频率的时钟下,且输入端口的组合逻辑非常短;还有一个寄存器工作在高频的 drv_clk 下,但输入端口直接来自于上一级的寄存器输出(没有组合逻辑)。因此,即使在速度级别很低的 EP4CE6E22C8N 上,在 300MHz 的驱动时钟下也能保证模块正确运行。在速度等级更高的 FPGA (例如 EP4CE22F17C6N驱动时钟的频率可以更高例如400MHz
## 模块接口DDR1接口
@ -172,11 +172,11 @@ rstn_async 是低电平复位信号正常工作时应该置高。clk 是驱
DDR1 控制器对外提供 AXI4 从接口AXI4 slave的时钟和复位信号如下。AXI4 主机应该用它们作为自己的时钟和复位。
```Verilog
output reg aresetn,
output reg aclk,
output reg rstn,
output reg clk,
```
以下是该模块的 AXI4 从接口,它们都与 aclk 时钟的上升沿同步,应该连接到 FPGA 内的的 AXI4 主机。
以下是该模块的 AXI4 从接口,它们都与 clk 时钟的上升沿同步,应该连接到 FPGA 内的的 AXI4 主机。
```Verilog
input wire awvalid,
@ -214,7 +214,7 @@ AXI4 总线的地址awaddr和araddr统一是字节地址模块会根据
### AXI4 写操作时序
__ __ __ __ __ __ __ __ __ __ __ __ _
aclk __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/
clk __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/
___________
awvalid ___/ \____________________________________________________________
_____
@ -245,7 +245,7 @@ AXI4 总线的地址awaddr和araddr统一是字节地址模块会根据
### AXI4 读操作时序
__ __ __ __ __ __ __ __ __ __ __ __ _
aclk __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/
clk __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/
___________
arvalid ___/ \____________________________________________________________
_____
@ -295,9 +295,9 @@ AXI4 总线的地址awaddr和araddr统一是字节地址模块会根据
本节讲述如何确定 **tREFC**、**tW2I** 和 **tR2I** 这 3 个时序参数。
我们知道DDR1 需要周期性的刷新动作,**tREFC** 就规定了刷新的时钟周期间隔(以 aclk为准。例如若用户时钟为 75MHz根据 MT46V64M8 的芯片手册,需要至多 7.8125us 刷新一次,考虑到 75MHz * 7.8125us = 585.9,则该参数可以设置为一个小于 585 的值,例如 10'd512。
我们知道DDR1 需要周期性的刷新动作,**tREFC** 就规定了刷新的时钟周期间隔(以 clk 为准)。例如,若用户时钟为 75MHz根据 MT46V64M8 的芯片手册,需要至多 7.8125us 刷新一次,考虑到 75MHz * 7.8125us = 585.9,则该参数可以设置为一个小于 585 的值,例如 10'd512。
**tW2I** 规定了一个写操作的最后一个写命令到下一个操作的激活命令(ACT)的时钟周期数(以 aclk 为准)的最小值。下图展示了一个 DDR1 接口上的写操作ddr_cas_n 的第一个上升沿代表了一个写操作的最后一个写命令结束ddr_ras_n 的第二个下降沿代表了下一个操作(可能是读、写、刷新)的开始,它们之间有 5 个时钟周期,**tW2I** 就是用来规定该周期数的下限的。**tW2I** 的默认值 8'd7 是一个兼容绝大多数 DDR1 的保守值,对于不同的 DDR1 芯片,有不同的缩小的余地(详见 DDR1 芯片 datasheet
**tW2I** 规定了一个写操作的最后一个写命令到下一个操作的激活命令(ACT)的时钟周期数(以 clk 为准)的最小值。下图展示了一个 DDR1 接口上的写操作ddr_cas_n 的第一个上升沿代表了一个写操作的最后一个写命令结束ddr_ras_n 的第二个下降沿代表了下一个操作(可能是读、写、刷新)的开始,它们之间有 5 个时钟周期,**tW2I** 就是用来规定该周期数的下限的。**tW2I** 的默认值 8'd7 是一个兼容绝大多数 DDR1 的保守值,对于不同的 DDR1 芯片,有不同的缩小的余地(详见 DDR1 芯片 datasheet
__ __ __ __ __ __ __ __ __ __ __ __
ddr_ck_p __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__
@ -314,7 +314,7 @@ AXI4 总线的地址awaddr和araddr统一是字节地址模块会根据
_______________________
ddr_a XXXXXX__RA_XXXXXXX_CA0_X_CA1_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
**tR2I** 规定了一个读操作的最后一个读命令到下一个操作的激活命令(ACT)的时钟周期数(以 aclk 为准)的最小值。下图展示了一个 DDR1 接口上的读操作ddr_cas_n 的第一个上升沿代表了一个读操作的最后一个读命令结束ddr_ras_n 的第二个下降沿代表了下一个操作(可能是读、写、刷新)的开始,它们之间有 5 个时钟周期,**tR2I** 就是用来规定该周期数的下限的。**tR2I** 的默认值 8'd7 是一个兼容绝大多数 DDR1 的保守值,对于不同的 DDR1 芯片,有不同的缩小的余地(详见 DDR1 芯片 datasheet
**tR2I** 规定了一个读操作的最后一个读命令到下一个操作的激活命令(ACT)的时钟周期数(以 clk 为准)的最小值。下图展示了一个 DDR1 接口上的读操作ddr_cas_n 的第一个上升沿代表了一个读操作的最后一个读命令结束ddr_ras_n 的第二个下降沿代表了下一个操作(可能是读、写、刷新)的开始,它们之间有 5 个时钟周期,**tR2I** 就是用来规定该周期数的下限的。**tR2I** 的默认值 8'd7 是一个兼容绝大多数 DDR1 的保守值,对于不同的 DDR1 芯片,有不同的缩小的余地(详见 DDR1 芯片 datasheet
__ __ __ __ __ __ __ __ __ __ __ __
ddr_ck_p __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__
@ -345,8 +345,7 @@ AXI4 总线的地址awaddr和araddr统一是字节地址模块会根据
| :---- | :--- |
| 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 控制器 |
| RTL/ddr_sdram_ctrl.sv | DDR1 控制器 |
该示例程序的行为是:
@ -370,7 +369,6 @@ AXI4 总线的地址awaddr和araddr统一是字节地址模块会根据
| :---- | :--- |
| 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 口(需要先在 [www.wch.cn/product/CH340.html](http://www.wch.cn/product/CH340.html) 下载安装 CH341 的驱动)。

View File

@ -22,10 +22,11 @@ module ddr_sdram_ctrl #(
) (
// driving clock and reset
input wire rstn_async,
input wire clk, // driving clock, typically 300~532MHz
// user interface ( AXI4 )
output reg aresetn,
output reg aclk, // freq = F(clk)/4
input wire drv_clk, // driving clock, typically 300~532MHz
// generate clock for AXI4
output reg rstn,
output reg clk, // freq = F(drv_clk)/4
// user interface (AXI4)
input wire awvalid,
output wire awready,
input wire [BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-2:0] awaddr, // byte address, not word address.
@ -45,7 +46,7 @@ module ddr_sdram_ctrl #(
output wire rlast,
output wire [(8<<DQ_LEVEL)-1:0] rdata,
// DDR-SDRAM interface
output wire ddr_ck_p, ddr_ck_n, // freq = F(clk)/4
output wire ddr_ck_p, ddr_ck_n, // freq = F(drv_clk)/4
output wire ddr_cke,
output reg ddr_cs_n,
output reg ddr_ras_n,
@ -120,26 +121,26 @@ initial ddr_we_n = 1'b1;
initial ddr_ba = '0;
initial ddr_a = DDR_A_DEFAULT;
initial {aresetn, aclk} = '0;
initial {rstn, clk} = '0;
// -------------------------------------------------------------------------------------
// generate reset sync with clk
// generate reset sync with drv_clk
// -------------------------------------------------------------------------------------
reg rstn_clk = '0;
reg [1:0] rstn_clk_l = '0;
always @ (posedge clk or negedge rstn_async)
reg [2:0] rstn_clk_l = '0;
always @ (posedge drv_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
// generate reset sync with clk
// -------------------------------------------------------------------------------------
reg rstn_aclk = '0;
reg [1:0] rstn_aclk_l = '0;
always @ (posedge aclk or negedge rstn_async)
reg [2:0] rstn_aclk_l = '0;
always @ (posedge clk or negedge rstn_async)
if(~rstn_async)
{rstn_aclk, rstn_aclk_l} <= '0;
else
@ -148,25 +149,25 @@ always @ (posedge aclk or negedge rstn_async)
// -------------------------------------------------------------------------------------
// generate clocks
// -------------------------------------------------------------------------------------
always @ (posedge clk or negedge rstn_clk)
always @ (posedge drv_clk or negedge rstn_clk)
if(~rstn_clk)
{aclk,clk2} <= 2'b00;
{clk,clk2} <= 2'b00;
else
{aclk,clk2} <= {aclk,clk2} + 2'b01;
{clk,clk2} <= {clk,clk2} + 2'b01;
// -------------------------------------------------------------------------------------
// generate user reset
// -------------------------------------------------------------------------------------
always @ (posedge aclk or negedge rstn_aclk)
always @ (posedge clk or negedge rstn_aclk)
if(~rstn_aclk)
aresetn <= 1'b0;
rstn <= 1'b0;
else
aresetn <= init_done;
rstn <= init_done;
// -------------------------------------------------------------------------------------
// refresh wptr self increasement
// -------------------------------------------------------------------------------------
always @ (posedge aclk or negedge rstn_aclk)
always @ (posedge clk or negedge rstn_aclk)
if(~rstn_aclk) begin
ref_cnt <= '0;
ref_idle <= 3'd1;
@ -184,8 +185,8 @@ always @ (posedge aclk or negedge rstn_aclk)
// -------------------------------------------------------------------------------------
// generate DDR clock
// -------------------------------------------------------------------------------------
assign ddr_ck_p = ~aclk;
assign ddr_ck_n = aclk;
assign ddr_ck_p = ~clk;
assign ddr_ck_n = clk;
assign ddr_cke = ~ddr_cs_n;
// -------------------------------------------------------------------------------------
@ -196,7 +197,7 @@ assign ddr_dqs = output_enable ? {DQS_BITS{o_dqs_c}} : 'z;
assign ddr_dq = output_enable ? o_d_d : 'z;
// -------------------------------------------------------------------------------------
// assignment for user interface (meta AXI4 interface)
// assignment for user interface (AXI4)
// -------------------------------------------------------------------------------------
assign awready = stat==IDLE && init_done && ref_real==ref_idle;
assign wready = stat==WRITE;
@ -206,7 +207,7 @@ 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_aclk)
always @ (posedge clk or negedge rstn_aclk)
if(~rstn_aclk) begin
ddr_cs_n <= 1'b1;
ddr_ras_n <= 1'b1;
@ -372,8 +373,8 @@ always @ (posedge aclk or negedge rstn_aclk)
// -------------------------------------------------------------------------------------
// output enable generate
// -------------------------------------------------------------------------------------
always @ (posedge aclk or negedge aresetn)
if(~aresetn) begin
always @ (posedge clk or negedge rstn)
if(~rstn) begin
output_enable <= 1'b0;
output_enable_d1 <= 1'b0;
output_enable_d2 <= 1'b0;
@ -386,8 +387,8 @@ always @ (posedge aclk or negedge aresetn)
// -------------------------------------------------------------------------------------
// output data latches --- stage A
// -------------------------------------------------------------------------------------
always @ (posedge aclk or negedge aresetn)
if(~aresetn) begin
always @ (posedge clk or negedge rstn)
if(~rstn) begin
o_v_a <= 1'b0;
{o_dh_a, o_dl_a} <= '0;
end else begin
@ -398,8 +399,8 @@ always @ (posedge aclk or negedge aresetn)
// -------------------------------------------------------------------------------------
// output data latches --- stage B
// -------------------------------------------------------------------------------------
always @ (posedge aclk or negedge aresetn)
if(~aresetn) begin
always @ (posedge clk or negedge rstn)
if(~rstn) begin
o_v_b <= 1'b0;
o_dh_b <= '0;
end else begin
@ -411,7 +412,7 @@ always @ (posedge aclk or negedge aresetn)
// dq and dqs generate for output (write)
// -------------------------------------------------------------------------------------
always @ (posedge clk2)
if(~aclk) begin
if(~clk) begin
o_dqs_c <= 1'b0;
o_d_c <= o_v_a ? o_dl_a : '0;
end else begin
@ -422,7 +423,7 @@ always @ (posedge clk2)
// -------------------------------------------------------------------------------------
// dq delay for output (write)
// -------------------------------------------------------------------------------------
always @ (posedge clk)
always @ (posedge drv_clk)
o_d_d <= o_d_c;
// -------------------------------------------------------------------------------------
@ -437,8 +438,8 @@ always @ (posedge clk2)
if(i_dqs_c)
i_d_d <= {ddr_dq, i_d_c};
always @ (posedge aclk or negedge aresetn)
if(~aresetn) begin
always @ (posedge clk or negedge rstn)
if(~rstn) begin
{i_v_a, i_v_b, i_v_c, i_v_d} <= '0;
{i_l_a, i_l_b, i_l_c, i_l_d} <= '0;
end else begin
@ -452,8 +453,8 @@ always @ (posedge aclk or negedge aresetn)
i_l_d <= i_l_c;
end
always @ (posedge aclk or negedge aresetn)
if(~aresetn) begin
always @ (posedge clk or negedge rstn)
if(~rstn) begin
i_v_e <= 1'b0;
i_l_e <= 1'b0;
i_d_e <= '0;
@ -485,20 +486,20 @@ generate if(READ_BUFFER) begin
assign rreq = emptyn & ( rready | ~rvalid );
assign {rlast, rdata} = dvalid ? fifo_rdata : datareg;
always @ (posedge aclk or negedge aresetn)
if(~aresetn)
always @ (posedge clk or negedge rstn)
if(~rstn)
wpt <= 0;
else if(i_v_e & itready)
wpt <= wpt + (AWIDTH)'(1);
always @ (posedge aclk or negedge aresetn)
if(~aresetn)
always @ (posedge clk or negedge rstn)
if(~rstn)
rpt <= 0;
else if(rreq & emptyn)
rpt <= rpt + (AWIDTH)'(1);
always @ (posedge aclk or negedge aresetn)
if(~aresetn) begin
always @ (posedge clk or negedge rstn)
if(~rstn) begin
dvalid <= 1'b0;
valid <= 1'b0;
datareg <= 0;
@ -514,11 +515,11 @@ generate if(READ_BUFFER) begin
reg [DWIDTH-1:0] mem [(1<<AWIDTH)];
always @ (posedge aclk)
always @ (posedge clk)
if(i_v_e)
mem[wpt] <= {i_l_e, i_d_e};
always @ (posedge aclk)
always @ (posedge clk)
fifo_rdata <= mem[rpt];
assign read_accessible = ~rvalid;

View File

@ -15,8 +15,8 @@ module axi_self_test_master #(
parameter [7:0] WBURST_LEN = 8'd7,
parameter [7:0] RBURST_LEN = 8'd7
)(
input wire aresetn,
input wire aclk,
input wire rstn,
input wire clk,
output wire awvalid,
input wire awready,
output reg [A_WIDTH-1:0] awaddr,
@ -65,8 +65,8 @@ 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
always @ (posedge clk or negedge rstn)
if(~rstn) begin
{awaddr_carry, awaddr} <= '0;
w_cnt <= 8'd0;
araddr <= '0;
@ -110,8 +110,8 @@ always @ (posedge aclk or negedge aresetn)
// read and write mismatch detect
// ------------------------------------------------------------
wire [D_WIDTH-1:0] rdata_idle = (D_WIDTH)'(araddr);
always @ (posedge aclk or negedge aresetn)
if(~aresetn) begin
always @ (posedge clk or negedge rstn)
if(~rstn) begin
error <= 1'b0;
error_cnt <= 16'd0;
end else begin

View File

@ -40,13 +40,13 @@ localparam DQ_BITS = (4<<DQ_LEVEL);
localparam DQS_BITS = ((1<<DQ_LEVEL)+1)/2;
// -------------------------------------------------------------------------------------
// meta AXI4 burst length parameters
// AXI4 burst length parameters
// -------------------------------------------------------------------------------------
localparam [7:0] WBURST_LEN = 8'd7;
localparam [7:0] RBURST_LEN = 8'd7;
// -------------------------------------------------------------------------------------
// meta AXI4 parameters
// AXI4 parameters
// -------------------------------------------------------------------------------------
localparam A_WIDTH = BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-1;
localparam D_WIDTH = (8<<DQ_LEVEL);
@ -54,9 +54,9 @@ localparam D_WIDTH = (8<<DQ_LEVEL);
// -------------------------------------------------------------------------------------
// driving clock and reset generate
// -------------------------------------------------------------------------------------
reg rstn=1'b0, clk300m=1'b1;
reg rstn_async=1'b0, clk300m=1'b1;
always #1667 clk300m = ~clk300m;
initial begin repeat(4) @(posedge clk300m); rstn<=1'b1; end
initial begin repeat(4) @(posedge clk300m); rstn_async<=1'b1; end
// -------------------------------------------------------------------------------------
// DDR-SDRAM signal
@ -71,10 +71,10 @@ tri [DQS_BITS-1:0] ddr_dqs;
tri [ DQ_BITS-1:0] ddr_dq;
// -------------------------------------------------------------------------------------
// meta AXI4 interface
// AXI4 interface
// -------------------------------------------------------------------------------------
wire aresetn;
wire aclk;
wire rstn;
wire clk;
wire awvalid;
wire awready;
wire [A_WIDTH-1:0] awaddr;
@ -95,7 +95,7 @@ wire rlast;
wire [D_WIDTH-1:0] rdata;
// -------------------------------------------------------------------------------------
// meta AXI4 master for testing
// AXI4 master for testing
// -------------------------------------------------------------------------------------
axi_self_test_master #(
.A_WIDTH_TEST( 12 ),
@ -105,8 +105,8 @@ axi_self_test_master #(
.WBURST_LEN ( WBURST_LEN ),
.RBURST_LEN ( RBURST_LEN )
) axi_m_i (
.aresetn ( aresetn ),
.aclk ( aclk ),
.rstn ( rstn ),
.clk ( clk ),
.awvalid ( awvalid ),
.awready ( awready ),
.awaddr ( awaddr ),
@ -142,10 +142,10 @@ ddr_sdram_ctrl #(
.tW2I ( 8'd6 ),
.tR2I ( 8'd6 )
) ddr_sdram_ctrl_i (
.rstn_async ( rstn ),
.clk ( clk300m ),
.aresetn ( aresetn ),
.aclk ( aclk ),
.rstn_async ( rstn_async ),
.drv_clk ( clk300m ),
.rstn ( rstn ),
.clk ( clk ),
.awvalid ( awvalid ),
.awready ( awready ),
.awaddr ( awaddr ),

View File

@ -15,8 +15,8 @@ module axi_self_test_master #(
parameter [7:0] WBURST_LEN = 8'd7,
parameter [7:0] RBURST_LEN = 8'd7
)(
input wire aresetn,
input wire aclk,
input wire rstn,
input wire clk,
output wire awvalid,
input wire awready,
output reg [A_WIDTH-1:0] awaddr,
@ -65,8 +65,8 @@ 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
always @ (posedge clk or negedge rstn)
if(~rstn) begin
{awaddr_carry, awaddr} <= '0;
w_cnt <= 8'd0;
araddr <= '0;
@ -110,8 +110,8 @@ always @ (posedge aclk or negedge aresetn)
// read and write mismatch detect
// ------------------------------------------------------------
wire [D_WIDTH-1:0] rdata_idle = (D_WIDTH)'(araddr);
always @ (posedge aclk or negedge aresetn)
if(~aresetn) begin
always @ (posedge clk or negedge rstn)
if(~rstn) begin
error <= 1'b0;
error_cnt <= 16'd0;
end else begin

View File

@ -1,115 +0,0 @@
`timescale 1 ns / 1 ns
// synopsys translate_on
module pll (
input wire inclk0,
output wire c0,
output wire locked
);
wire [4:0] sub_wire0;
wire sub_wire2;
wire [0:0] sub_wire5 = 1'h0;
wire [0:0] sub_wire1 = sub_wire0[0:0];
assign c0 = sub_wire1;
assign locked = sub_wire2;
wire sub_wire3 = inclk0;
wire [1:0] sub_wire4 = {sub_wire5, sub_wire3};
altpll altpll_component (
.inclk (sub_wire4),
.clk (sub_wire0),
.locked (sub_wire2),
.activeclock (),
.areset (1'b0),
.clkbad (),
.clkena ({6{1'b1}}),
.clkloss (),
.clkswitch (1'b0),
.configupdate (1'b0),
.enable0 (),
.enable1 (),
.extclk (),
.extclkena ({4{1'b1}}),
.fbin (1'b1),
.fbmimicbidir (),
.fbout (),
.fref (),
.icdrclk (),
.pfdena (1'b1),
.phasecounterselect ({4{1'b1}}),
.phasedone (),
.phasestep (1'b1),
.phaseupdown (1'b1),
.pllena (1'b1),
.scanaclr (1'b0),
.scanclk (1'b0),
.scanclkena (1'b1),
.scandata (1'b0),
.scandataout (),
.scandone (),
.scanread (1'b0),
.scanwrite (1'b0),
.sclkout0 (),
.sclkout1 (),
.vcooverrange (),
.vcounderrange ());
defparam
altpll_component.bandwidth_type = "AUTO",
altpll_component.clk0_divide_by = 1,
altpll_component.clk0_duty_cycle = 50,
altpll_component.clk0_multiply_by = 6,
altpll_component.clk0_phase_shift = "0",
altpll_component.compensate_clock = "CLK0",
altpll_component.inclk0_input_frequency = 20000,
altpll_component.intended_device_family = "Cyclone IV E",
altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll",
altpll_component.lpm_type = "altpll",
altpll_component.operation_mode = "NORMAL",
altpll_component.pll_type = "AUTO",
altpll_component.port_activeclock = "PORT_UNUSED",
altpll_component.port_areset = "PORT_UNUSED",
altpll_component.port_clkbad0 = "PORT_UNUSED",
altpll_component.port_clkbad1 = "PORT_UNUSED",
altpll_component.port_clkloss = "PORT_UNUSED",
altpll_component.port_clkswitch = "PORT_UNUSED",
altpll_component.port_configupdate = "PORT_UNUSED",
altpll_component.port_fbin = "PORT_UNUSED",
altpll_component.port_inclk0 = "PORT_USED",
altpll_component.port_inclk1 = "PORT_UNUSED",
altpll_component.port_locked = "PORT_USED",
altpll_component.port_pfdena = "PORT_UNUSED",
altpll_component.port_phasecounterselect = "PORT_UNUSED",
altpll_component.port_phasedone = "PORT_UNUSED",
altpll_component.port_phasestep = "PORT_UNUSED",
altpll_component.port_phaseupdown = "PORT_UNUSED",
altpll_component.port_pllena = "PORT_UNUSED",
altpll_component.port_scanaclr = "PORT_UNUSED",
altpll_component.port_scanclk = "PORT_UNUSED",
altpll_component.port_scanclkena = "PORT_UNUSED",
altpll_component.port_scandata = "PORT_UNUSED",
altpll_component.port_scandataout = "PORT_UNUSED",
altpll_component.port_scandone = "PORT_UNUSED",
altpll_component.port_scanread = "PORT_UNUSED",
altpll_component.port_scanwrite = "PORT_UNUSED",
altpll_component.port_clk0 = "PORT_USED",
altpll_component.port_clk1 = "PORT_UNUSED",
altpll_component.port_clk2 = "PORT_UNUSED",
altpll_component.port_clk3 = "PORT_UNUSED",
altpll_component.port_clk4 = "PORT_UNUSED",
altpll_component.port_clk5 = "PORT_UNUSED",
altpll_component.port_clkena0 = "PORT_UNUSED",
altpll_component.port_clkena1 = "PORT_UNUSED",
altpll_component.port_clkena2 = "PORT_UNUSED",
altpll_component.port_clkena3 = "PORT_UNUSED",
altpll_component.port_clkena4 = "PORT_UNUSED",
altpll_component.port_clkena5 = "PORT_UNUSED",
altpll_component.port_extclk0 = "PORT_UNUSED",
altpll_component.port_extclk1 = "PORT_UNUSED",
altpll_component.port_extclk2 = "PORT_UNUSED",
altpll_component.port_extclk3 = "PORT_UNUSED",
altpll_component.self_reset_on_loss_lock = "OFF",
altpll_component.width_clock = 5;
endmodule

View File

@ -35,7 +35,7 @@ localparam DQ_BITS = (4<<DQ_LEVEL);
localparam DQS_BITS = ((1<<DQ_LEVEL)+1)/2;
// -------------------------------------------------------------------------------------
// meta AXI4 parameters
// AXI4 parameters
// -------------------------------------------------------------------------------------
localparam A_WIDTH = BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-1;
localparam D_WIDTH = (8<<DQ_LEVEL);
@ -44,13 +44,13 @@ localparam D_WIDTH = (8<<DQ_LEVEL);
// driving clock and reset
// -------------------------------------------------------------------------------------
wire clk300m;
wire rstn;
wire locked;
// -------------------------------------------------------------------------------------
// meta AXI4 interface
// AXI4 interface
// -------------------------------------------------------------------------------------
wire aresetn;
wire aclk;
wire rstn;
wire clk;
wire awvalid;
wire awready;
wire [A_WIDTH-1:0] awaddr;
@ -70,17 +70,17 @@ wire rready;
wire rlast;
wire [D_WIDTH-1:0] rdata;
// -------------------------------------------------------------------------------------
// PLL for generating 300MHz clock
// -------------------------------------------------------------------------------------
pll pll_i(
.inclk0 ( clk50m ),
.c0 ( clk300m ),
.locked ( rstn )
);
wire [3:0] subwire0;
altpll altpll_i( .inclk ( {1'b0, clk50m} ), .clk ( {subwire0, clk300m} ), .locked ( locked ), .activeclock (), .areset (1'b0), .clkbad (), .clkena ({6{1'b1}}), .clkloss (), .clkswitch (1'b0), .configupdate (1'b0), .enable0 (), .enable1 (), .extclk (), .extclkena ({4{1'b1}}), .fbin (1'b1), .fbmimicbidir (), .fbout (), .fref (), .icdrclk (), .pfdena (1'b1), .phasecounterselect ({4{1'b1}}), .phasedone (), .phasestep (1'b1), .phaseupdown (1'b1), .pllena (1'b1), .scanaclr (1'b0), .scanclk (1'b0), .scanclkena (1'b1), .scandata (1'b0), .scandataout (), .scandone (), .scanread (1'b0), .scanwrite (1'b0), .sclkout0 (), .sclkout1 (), .vcooverrange (), .vcounderrange ());
defparam altpll_i.bandwidth_type = "AUTO", altpll_i.clk0_divide_by = 1, altpll_i.clk0_duty_cycle = 50, altpll_i.clk0_multiply_by = 6, altpll_i.clk0_phase_shift = "0", altpll_i.compensate_clock = "CLK0", altpll_i.inclk0_input_frequency = 20000, altpll_i.intended_device_family = "Cyclone IV E", altpll_i.lpm_hint = "CBX_MODULE_PREFIX=pll", altpll_i.lpm_type = "altpll", altpll_i.operation_mode = "NORMAL", altpll_i.pll_type = "AUTO", altpll_i.port_activeclock = "PORT_UNUSED", altpll_i.port_areset = "PORT_UNUSED", altpll_i.port_clkbad0 = "PORT_UNUSED", altpll_i.port_clkbad1 = "PORT_UNUSED", altpll_i.port_clkloss = "PORT_UNUSED", altpll_i.port_clkswitch = "PORT_UNUSED", altpll_i.port_configupdate = "PORT_UNUSED", altpll_i.port_fbin = "PORT_UNUSED", altpll_i.port_inclk0 = "PORT_USED", altpll_i.port_inclk1 = "PORT_UNUSED", altpll_i.port_locked = "PORT_USED", altpll_i.port_pfdena = "PORT_UNUSED", altpll_i.port_phasecounterselect = "PORT_UNUSED", altpll_i.port_phasedone = "PORT_UNUSED", altpll_i.port_phasestep = "PORT_UNUSED", altpll_i.port_phaseupdown = "PORT_UNUSED", altpll_i.port_pllena = "PORT_UNUSED", altpll_i.port_scanaclr = "PORT_UNUSED", altpll_i.port_scanclk = "PORT_UNUSED", altpll_i.port_scanclkena = "PORT_UNUSED", altpll_i.port_scandata = "PORT_UNUSED", altpll_i.port_scandataout = "PORT_UNUSED", altpll_i.port_scandone = "PORT_UNUSED", altpll_i.port_scanread = "PORT_UNUSED", altpll_i.port_scanwrite = "PORT_UNUSED", altpll_i.port_clk0 = "PORT_USED", altpll_i.port_clk1 = "PORT_UNUSED", altpll_i.port_clk2 = "PORT_UNUSED", altpll_i.port_clk3 = "PORT_UNUSED", altpll_i.port_clk4 = "PORT_UNUSED", altpll_i.port_clk5 = "PORT_UNUSED", altpll_i.port_clkena0 = "PORT_UNUSED", altpll_i.port_clkena1 = "PORT_UNUSED", altpll_i.port_clkena2 = "PORT_UNUSED", altpll_i.port_clkena3 = "PORT_UNUSED", altpll_i.port_clkena4 = "PORT_UNUSED", altpll_i.port_clkena5 = "PORT_UNUSED", altpll_i.port_extclk0 = "PORT_UNUSED", altpll_i.port_extclk1 = "PORT_UNUSED", altpll_i.port_extclk2 = "PORT_UNUSED", altpll_i.port_extclk3 = "PORT_UNUSED", altpll_i.self_reset_on_loss_lock = "OFF", altpll_i.width_clock = 5;
// -------------------------------------------------------------------------------------
// meta AXI4 master for testing
// AXI4 master for testing
// -------------------------------------------------------------------------------------
axi_self_test_master #(
.A_WIDTH_TEST( A_WIDTH ),
@ -90,8 +90,8 @@ axi_self_test_master #(
.WBURST_LEN ( 8'd15 ),
.RBURST_LEN ( 8'd15 )
) axi_m_i (
.aresetn ( aresetn ),
.aclk ( aclk ),
.rstn ( rstn ),
.clk ( clk ),
.awvalid ( awvalid ),
.awready ( awready ),
.awaddr ( awaddr ),
@ -114,6 +114,7 @@ axi_self_test_master #(
.error_cnt ( error_cnt )
);
// -------------------------------------------------------------------------------------
// DDR-SDRAM controller
// -------------------------------------------------------------------------------------
@ -127,10 +128,10 @@ ddr_sdram_ctrl #(
.tW2I ( 8'd7 ),
.tR2I ( 8'd7 )
) ddr_ctrl_i(
.rstn_async ( rstn ),
.clk ( clk300m ),
.aresetn ( aresetn ),
.aclk ( aclk ),
.rstn_async ( locked ),
.drv_clk ( clk300m ),
.rstn ( rstn ),
.clk ( clk ),
.awvalid ( awvalid ),
.awready ( awready ),
.awaddr ( awaddr ),

View File

@ -132,7 +132,6 @@ set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_clk -to "ddr_c
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 SIGNALTAP_FILE SignalTap/stp1.stp

View File

@ -1,115 +0,0 @@
`timescale 1 ns / 1 ns
// synopsys translate_on
module pll (
input wire inclk0,
output wire c0,
output wire locked
);
wire [4:0] sub_wire0;
wire sub_wire2;
wire [0:0] sub_wire5 = 1'h0;
wire [0:0] sub_wire1 = sub_wire0[0:0];
assign c0 = sub_wire1;
assign locked = sub_wire2;
wire sub_wire3 = inclk0;
wire [1:0] sub_wire4 = {sub_wire5, sub_wire3};
altpll altpll_component (
.inclk (sub_wire4),
.clk (sub_wire0),
.locked (sub_wire2),
.activeclock (),
.areset (1'b0),
.clkbad (),
.clkena ({6{1'b1}}),
.clkloss (),
.clkswitch (1'b0),
.configupdate (1'b0),
.enable0 (),
.enable1 (),
.extclk (),
.extclkena ({4{1'b1}}),
.fbin (1'b1),
.fbmimicbidir (),
.fbout (),
.fref (),
.icdrclk (),
.pfdena (1'b1),
.phasecounterselect ({4{1'b1}}),
.phasedone (),
.phasestep (1'b1),
.phaseupdown (1'b1),
.pllena (1'b1),
.scanaclr (1'b0),
.scanclk (1'b0),
.scanclkena (1'b1),
.scandata (1'b0),
.scandataout (),
.scandone (),
.scanread (1'b0),
.scanwrite (1'b0),
.sclkout0 (),
.sclkout1 (),
.vcooverrange (),
.vcounderrange ());
defparam
altpll_component.bandwidth_type = "AUTO",
altpll_component.clk0_divide_by = 1,
altpll_component.clk0_duty_cycle = 50,
altpll_component.clk0_multiply_by = 6,
altpll_component.clk0_phase_shift = "0",
altpll_component.compensate_clock = "CLK0",
altpll_component.inclk0_input_frequency = 20000,
altpll_component.intended_device_family = "Cyclone IV E",
altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll",
altpll_component.lpm_type = "altpll",
altpll_component.operation_mode = "NORMAL",
altpll_component.pll_type = "AUTO",
altpll_component.port_activeclock = "PORT_UNUSED",
altpll_component.port_areset = "PORT_UNUSED",
altpll_component.port_clkbad0 = "PORT_UNUSED",
altpll_component.port_clkbad1 = "PORT_UNUSED",
altpll_component.port_clkloss = "PORT_UNUSED",
altpll_component.port_clkswitch = "PORT_UNUSED",
altpll_component.port_configupdate = "PORT_UNUSED",
altpll_component.port_fbin = "PORT_UNUSED",
altpll_component.port_inclk0 = "PORT_USED",
altpll_component.port_inclk1 = "PORT_UNUSED",
altpll_component.port_locked = "PORT_USED",
altpll_component.port_pfdena = "PORT_UNUSED",
altpll_component.port_phasecounterselect = "PORT_UNUSED",
altpll_component.port_phasedone = "PORT_UNUSED",
altpll_component.port_phasestep = "PORT_UNUSED",
altpll_component.port_phaseupdown = "PORT_UNUSED",
altpll_component.port_pllena = "PORT_UNUSED",
altpll_component.port_scanaclr = "PORT_UNUSED",
altpll_component.port_scanclk = "PORT_UNUSED",
altpll_component.port_scanclkena = "PORT_UNUSED",
altpll_component.port_scandata = "PORT_UNUSED",
altpll_component.port_scandataout = "PORT_UNUSED",
altpll_component.port_scandone = "PORT_UNUSED",
altpll_component.port_scanread = "PORT_UNUSED",
altpll_component.port_scanwrite = "PORT_UNUSED",
altpll_component.port_clk0 = "PORT_USED",
altpll_component.port_clk1 = "PORT_UNUSED",
altpll_component.port_clk2 = "PORT_UNUSED",
altpll_component.port_clk3 = "PORT_UNUSED",
altpll_component.port_clk4 = "PORT_UNUSED",
altpll_component.port_clk5 = "PORT_UNUSED",
altpll_component.port_clkena0 = "PORT_UNUSED",
altpll_component.port_clkena1 = "PORT_UNUSED",
altpll_component.port_clkena2 = "PORT_UNUSED",
altpll_component.port_clkena3 = "PORT_UNUSED",
altpll_component.port_clkena4 = "PORT_UNUSED",
altpll_component.port_clkena5 = "PORT_UNUSED",
altpll_component.port_extclk0 = "PORT_UNUSED",
altpll_component.port_extclk1 = "PORT_UNUSED",
altpll_component.port_extclk2 = "PORT_UNUSED",
altpll_component.port_extclk3 = "PORT_UNUSED",
altpll_component.self_reset_on_loss_lock = "OFF",
altpll_component.width_clock = 5;
endmodule

View File

@ -34,7 +34,7 @@ localparam DQ_BITS = (4<<DQ_LEVEL);
localparam DQS_BITS = ((1<<DQ_LEVEL)+1)/2;
// -------------------------------------------------------------------------------------
// meta AXI4 parameters
// AXI4 parameters
// -------------------------------------------------------------------------------------
localparam A_WIDTH = BA_BITS+ROW_BITS+COL_BITS+DQ_LEVEL-1;
localparam D_WIDTH = (8<<DQ_LEVEL);
@ -43,13 +43,13 @@ localparam D_WIDTH = (8<<DQ_LEVEL);
// driving clock and reset
// -------------------------------------------------------------------------------------
wire clk300m;
wire rstn;
wire locked;
// -------------------------------------------------------------------------------------
// meta AXI4 interface
// AXI4 interface
// -------------------------------------------------------------------------------------
wire aresetn;
wire aclk;
wire rstn;
wire clk;
wire awvalid;
wire awready;
wire [A_WIDTH-1:0] awaddr;
@ -69,23 +69,23 @@ wire rready;
wire rlast;
wire [D_WIDTH-1:0] rdata;
// -------------------------------------------------------------------------------------
// PLL for generating 300MHz clock
// -------------------------------------------------------------------------------------
pll pll_i(
.inclk0 ( clk50m ),
.c0 ( clk300m ),
.locked ( rstn )
);
wire [3:0] subwire0;
altpll altpll_i( .inclk ( {1'b0, clk50m} ), .clk ( {subwire0, clk300m} ), .locked ( locked ), .activeclock (), .areset (1'b0), .clkbad (), .clkena ({6{1'b1}}), .clkloss (), .clkswitch (1'b0), .configupdate (1'b0), .enable0 (), .enable1 (), .extclk (), .extclkena ({4{1'b1}}), .fbin (1'b1), .fbmimicbidir (), .fbout (), .fref (), .icdrclk (), .pfdena (1'b1), .phasecounterselect ({4{1'b1}}), .phasedone (), .phasestep (1'b1), .phaseupdown (1'b1), .pllena (1'b1), .scanaclr (1'b0), .scanclk (1'b0), .scanclkena (1'b1), .scandata (1'b0), .scandataout (), .scandone (), .scanread (1'b0), .scanwrite (1'b0), .sclkout0 (), .sclkout1 (), .vcooverrange (), .vcounderrange ());
defparam altpll_i.bandwidth_type = "AUTO", altpll_i.clk0_divide_by = 1, altpll_i.clk0_duty_cycle = 50, altpll_i.clk0_multiply_by = 6, altpll_i.clk0_phase_shift = "0", altpll_i.compensate_clock = "CLK0", altpll_i.inclk0_input_frequency = 20000, altpll_i.intended_device_family = "Cyclone IV E", altpll_i.lpm_hint = "CBX_MODULE_PREFIX=pll", altpll_i.lpm_type = "altpll", altpll_i.operation_mode = "NORMAL", altpll_i.pll_type = "AUTO", altpll_i.port_activeclock = "PORT_UNUSED", altpll_i.port_areset = "PORT_UNUSED", altpll_i.port_clkbad0 = "PORT_UNUSED", altpll_i.port_clkbad1 = "PORT_UNUSED", altpll_i.port_clkloss = "PORT_UNUSED", altpll_i.port_clkswitch = "PORT_UNUSED", altpll_i.port_configupdate = "PORT_UNUSED", altpll_i.port_fbin = "PORT_UNUSED", altpll_i.port_inclk0 = "PORT_USED", altpll_i.port_inclk1 = "PORT_UNUSED", altpll_i.port_locked = "PORT_USED", altpll_i.port_pfdena = "PORT_UNUSED", altpll_i.port_phasecounterselect = "PORT_UNUSED", altpll_i.port_phasedone = "PORT_UNUSED", altpll_i.port_phasestep = "PORT_UNUSED", altpll_i.port_phaseupdown = "PORT_UNUSED", altpll_i.port_pllena = "PORT_UNUSED", altpll_i.port_scanaclr = "PORT_UNUSED", altpll_i.port_scanclk = "PORT_UNUSED", altpll_i.port_scanclkena = "PORT_UNUSED", altpll_i.port_scandata = "PORT_UNUSED", altpll_i.port_scandataout = "PORT_UNUSED", altpll_i.port_scandone = "PORT_UNUSED", altpll_i.port_scanread = "PORT_UNUSED", altpll_i.port_scanwrite = "PORT_UNUSED", altpll_i.port_clk0 = "PORT_USED", altpll_i.port_clk1 = "PORT_UNUSED", altpll_i.port_clk2 = "PORT_UNUSED", altpll_i.port_clk3 = "PORT_UNUSED", altpll_i.port_clk4 = "PORT_UNUSED", altpll_i.port_clk5 = "PORT_UNUSED", altpll_i.port_clkena0 = "PORT_UNUSED", altpll_i.port_clkena1 = "PORT_UNUSED", altpll_i.port_clkena2 = "PORT_UNUSED", altpll_i.port_clkena3 = "PORT_UNUSED", altpll_i.port_clkena4 = "PORT_UNUSED", altpll_i.port_clkena5 = "PORT_UNUSED", altpll_i.port_extclk0 = "PORT_UNUSED", altpll_i.port_extclk1 = "PORT_UNUSED", altpll_i.port_extclk2 = "PORT_UNUSED", altpll_i.port_extclk3 = "PORT_UNUSED", altpll_i.self_reset_on_loss_lock = "OFF", altpll_i.width_clock = 5;
// -------------------------------------------------------------------------------------
// meta AXI4 master for testing
// AXI4 master for testing
// -------------------------------------------------------------------------------------
uart2axi4 #(
.A_WIDTH ( A_WIDTH )
) uart_axi_i (
.aresetn ( aresetn ),
.aclk ( aclk ),
.rstn ( rstn ),
.clk ( clk ),
.awvalid ( awvalid ),
.awready ( awready ),
.awaddr ( awaddr ),
@ -108,6 +108,7 @@ uart2axi4 #(
.uart_rx ( uart_rx )
);
// -------------------------------------------------------------------------------------
// DDR-SDRAM controller
// -------------------------------------------------------------------------------------
@ -121,10 +122,10 @@ ddr_sdram_ctrl #(
.tW2I ( 8'd7 ),
.tR2I ( 8'd7 )
) ddr_ctrl_i(
.rstn_async ( rstn ),
.clk ( clk300m ),
.aresetn ( aresetn ),
.aclk ( aclk ),
.rstn_async ( locked ),
.drv_clk ( clk300m ),
.rstn ( rstn ),
.clk ( clk ),
.awvalid ( awvalid ),
.awready ( awready ),
.awaddr ( awaddr ),

View File

@ -10,8 +10,8 @@ module uart2axi4 #(
parameter A_WIDTH = 26,
parameter D_WIDTH = 16
) (
input wire aresetn,
input wire aclk,
input wire rstn,
input wire clk,
output wire awvalid,
input wire awready,
@ -83,7 +83,7 @@ reg [ 7:0] wbuf_waddr;
reg [D_WIDTH-1:0] wbuf_wdata;
reg [ 7:0] wbuf_raddr;
wire[ 7:0] wbuf_raddr_n = stat == AXI_W && wready ? wbuf_raddr + 8'd1 : wbuf_raddr;
wire[D_WIDTH-1:0] wbuf_rdata;
reg [D_WIDTH-1:0] wbuf_rdata;
enum logic [3:0] {IDLE, INVALID, GADDR, GRLEN, GWDATA, AXI_AR, AXI_R, AXI_AW, AXI_W, AXI_B} stat;
assign awvalid = stat == AXI_AW;
@ -93,8 +93,8 @@ assign wdata = wbuf_rdata;
assign bready = stat == AXI_B;
assign arvalid = stat == AXI_AR;
always @ (posedge aclk or negedge aresetn)
if(~aresetn) begin
always @ (posedge clk or negedge rstn)
if(~rstn) begin
awaddr <= '0;
awlen <= '0;
araddr <= '0;
@ -198,36 +198,86 @@ always @ (posedge aclk or negedge aresetn)
endcase
end
ram_for_axi4write #(
.ADDR_LEN ( 8 ),
.DATA_LEN ( D_WIDTH )
) ram_for_axi4write_i (
.clk ( aclk ),
.wr_req ( wbuf_wen ),
.wr_addr ( wbuf_waddr ),
.wr_data ( wbuf_wdata ),
.rd_addr ( wbuf_raddr_n ),
.rd_data ( wbuf_rdata )
);
uart_rx#(
.CLK_DIV ( 162 ),
.CLK_PART ( 6 )
) uart_rx_i (
.rstn ( aresetn ),
.clk ( aclk ),
.rx ( uart_rx ),
.rvalid ( rx_valid ),
.rdata ( rx_data )
);
logic [D_WIDTH-1:0] mem_for_axi4write [256];
always @ (posedge clk)
wbuf_rdata <= mem_for_axi4write[wbuf_raddr_n];
always @ (posedge clk)
if(wbuf_wen)
mem_for_axi4write[wbuf_waddr] <= wbuf_wdata;
localparam CLK_DIV = 162;
localparam CLK_PART = 6;
reg uart_rx_done = 1'b0;
reg [ 7:0] uart_rx_data = 8'h0;
reg [ 2:0] uart_rx_supercnt=3'h0;
reg [31:0] uart_rx_cnt = 0;
reg [ 7:0] uart_rx_databuf = 8'h0;
reg [ 5:0] uart_rx_status=6'h0, uart_rx_shift=6'h0;
reg uart_rxr=1'b1;
wire recvbit = (uart_rx_shift[1]&uart_rx_shift[0]) | (uart_rx_shift[0]&uart_rxr) | (uart_rxr&uart_rx_shift[1]) ;
wire [2:0] supercntreverse = {uart_rx_supercnt[0], uart_rx_supercnt[1], uart_rx_supercnt[2]};
assign rx_valid = uart_rx_done;
assign rx_data = uart_rx_data;
always @ (posedge clk or negedge rstn)
if(~rstn)
uart_rxr <= 1'b1;
else
uart_rxr <= uart_rx;
always @ (posedge clk or negedge rstn)
if(~rstn) begin
uart_rx_done <= 1'b0;
uart_rx_data <= 8'h0;
uart_rx_status <= 6'h0;
uart_rx_shift <= 6'h0;
uart_rx_databuf <= 8'h0;
uart_rx_cnt <= 0;
end else begin
uart_rx_done <= 1'b0;
if( (supercntreverse<CLK_PART) ? (uart_rx_cnt>=CLK_DIV) : (uart_rx_cnt>=CLK_DIV-1) ) begin
if(uart_rx_status==0) begin
if(uart_rx_shift == 6'b111_000)
uart_rx_status <= 1;
end else begin
if(uart_rx_status[5] == 1'b0) begin
if(uart_rx_status[1:0] == 2'b11)
uart_rx_databuf <= {recvbit, uart_rx_databuf[7:1]};
uart_rx_status <= uart_rx_status + 5'b1;
end else begin
if(uart_rx_status<62) begin
uart_rx_status <= 62;
uart_rx_data <= uart_rx_databuf;
uart_rx_done <= 1'b1;
end else begin
uart_rx_status <= uart_rx_status + 6'd1;
end
end
end
uart_rx_shift <= {uart_rx_shift[4:0], uart_rxr};
uart_rx_supercnt <= uart_rx_supercnt + 3'h1;
uart_rx_cnt <= 0;
end else
uart_rx_cnt <= uart_rx_cnt + 1;
end
axis2uarttx #(
.CLK_DIV ( 651 ),
.DATA_WIDTH ( D_WIDTH ),
.FIFO_ASIZE ( 10 )
) uart_tx_i (
.aresetn ( aresetn ),
.aclk ( aclk ),
.rstn ( rstn ),
.clk ( clk ),
.tvalid ( rvalid ),
.tready ( rready ),
.tlast ( rlast ),
@ -242,136 +292,20 @@ endmodule
module ram_for_axi4write #(
parameter ADDR_LEN = 12,
parameter DATA_LEN = 8
) (
input logic clk,
input logic wr_req,
input logic [ADDR_LEN-1:0] rd_addr, wr_addr,
output logic [DATA_LEN-1:0] rd_data,
input logic [DATA_LEN-1:0] wr_data
);
localparam RAM_SIZE = (1<<ADDR_LEN);
logic [DATA_LEN-1:0] mem [RAM_SIZE];
initial rd_data = 0;
always @ (posedge clk)
rd_data <= mem[rd_addr];
always @ (posedge clk)
if(wr_req)
mem[wr_addr] <= wr_data;
endmodule
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 rstn,
input logic clk,
input logic tvalid,
input logic tlast,
output logic tready,
input logic [DATA_WIDTH-1:0] tdata,
// UART TX signal
output logic uart_tx
output logic uart_tx
);
localparam TX_WIDTH = (DATA_WIDTH+3) / 4;
@ -390,30 +324,30 @@ 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;
assign tready = (fifo_rpt != fifo_wpt_next) & rstn;
always @ (posedge aclk or negedge aresetn)
if(~aresetn)
always @ (posedge clk or negedge rstn)
if(~rstn)
uart_tx <= 1'b1;
else begin
uart_tx <= uart_txb;
end
always @ (posedge aclk or negedge aresetn)
if(~aresetn)
always @ (posedge clk or negedge rstn)
if(~rstn)
fifo_wpt <= '0;
else begin
if(tvalid & tready) fifo_wpt <= fifo_wpt_next;
end
always @ (posedge aclk or negedge aresetn)
if(~aresetn)
always @ (posedge clk or negedge rstn)
if(~rstn)
cyccnt <= 0;
else
cyccnt <= (cyccnt<CLK_DIV-1) ? cyccnt+1 : 0;
always @ (posedge aclk or negedge aresetn)
if(~aresetn) begin
always @ (posedge clk or negedge rstn)
if(~rstn) begin
fifo_rpt <= '0;
endofline <= 1'b0;
data <= '0;
@ -453,48 +387,14 @@ always @ (posedge aclk or negedge aresetn)
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;
logic [DATA_WIDTH:0] mem_for_axi_stream_to_uart_tx_fifo [1<<FIFO_ASIZE];
always @ (posedge clk)
rd_data <= mem[rd_addr];
{fifo_tlast, fifo_data} <= mem_for_axi_stream_to_uart_tx_fifo[fifo_rpt];
always @ (posedge clk)
if(wr_req)
mem[wr_addr] <= wr_data;
if(tvalid & tready)
mem_for_axi_stream_to_uart_tx_fifo[fifo_wpt] <= {tlast, tdata};
endmodule

View File

@ -51,7 +51,6 @@ 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/uart2axi4.sv
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