DDR2(6):8通道的DDR2控制器
前文说道,我毕业设计的一部分是实现8目摄像头的传图显示,并基于此做一些核心图像处理。一晃时间就过去了多年,当初在实验室同窗共砚,召唤师峡谷切磋拳剑,情景宛在目前。临风远念,想诸位师兄同窗,岁至中年,然风采笑貌,当如昔日也…
图像处理部分是导师的课题核心,不方便公开,但 8 通道的 DDR2 控制器是参考网络资料后自行设计的代码,这里分享出来,希望后来者遇到类似课题,能够有所帮助。
总体框图如下所示:

以下是源码,其中 DDR2_8port 是控制器的顶层文件,当时做了两个版本,两个版本的内部都调用了 DDR2_burst 模块和 FIFO 模块。
1、DDR2_8port v1
(1) inst
inst
//==========================================================================
//== DDR2_8port
//==========================================================================
DDR2_8port u_DDR2_8port
(
//时钟和复位 ------------------------------------
.pll_ref_clk (clk_100m ), //DDR2输入时钟
.global_reset_n (sys_rst_n ), //全局复位信号
//DDR2端口 --------------------------------------
.mem_odt (mem_odt ), //DDR2片上终结信号
.mem_cs_n (mem_cs_n ), //DDR2片选信号
.mem_cke (mem_cke ), //DDR2时钟使能信号
.mem_addr (mem_addr ), //DDR2地址总线
.mem_ba (mem_ba ), //DDR2BANK信号
.mem_ras_n (mem_ras_n ), //DDR2行地址选择信号
.mem_cas_n (mem_cas_n ), //DDR2列地址选择信号
.mem_we_n (mem_we_n ), //DDR2写使能信号
.mem_dm (mem_dm ), //DDR2数据掩膜信号
.mem_clk (mem_clk ), //DDR2时钟信号
.mem_clk_n (mem_clk_n ), //DDR2时钟反相信号
.mem_dq (mem_dq ), //DDR2数据总线
.mem_dqs (mem_dqs ), //DDR2数据源同步信号
//DDR2控制 --------------------------------------
.DDR2_rst_n ( ), //DDR2 IP核同步复位
.pingpang_vld (1'b1 ), //乒乓操作
.min_addr (0 ), //最小地址
.max_addr (320*360 ), //最大地址
.burst_len (80 ), //突发长度(行/4)
//通道0 -----------------------------------------
.ch0_en (1'b1 ), //通道0 使能
.ch0_addr (3'h0 ), //通道0 地址
.ch0_wr_clk (ch0_clk ), //通道0 写侧时钟
.ch0_wr_data (ch0_data ), //通道0 写侧数据
.ch0_wr_vld (ch0_vld ), //通道0 写侧有效
.ch0_wr_vsync (ch0_vsync ), //通道0 写侧同步
.ch0_rd_clk (clk_VGA ), //通道0 读侧时钟
.ch0_rd_data (ch0_VGA_din ), //通道0 读侧数据
.ch0_rd_req (ch0_VGA_req ), //通道0 读侧请求
.ch0_rd_vsync (VGA_vsync ), //通道0 读侧同步
//通道1 -----------------------------------------
.ch1_en (1'b1 ), //通道1 使能
.ch1_addr (3'h1 ), //通道1 地址
.ch1_wr_clk (ch1_clk ), //通道1 写侧时钟
.ch1_wr_data (ch1_data ), //通道1 写侧数据
.ch1_wr_vld (ch1_vld ), //通道1 写侧有效
.ch1_wr_vsync (ch1_vsync ), //通道1 写侧同步
.ch1_rd_clk (clk_VGA ), //通道1 读侧时钟
.ch1_rd_data (ch1_VGA_din ), //通道1 读侧数据
.ch1_rd_req (ch1_VGA_req ), //通道1 读侧请求
.ch1_rd_vsync (VGA_vsync ), //通道1 读侧同步
//通道2 -----------------------------------------
.ch2_en (1'b1 ), //通道2 使能
.ch2_addr (3'h2 ), //通道2 地址
.ch2_wr_clk (ch2_clk ), //通道2 写侧时钟
.ch2_wr_data (ch2_data ), //通道2 写侧数据
.ch2_wr_vld (ch2_vld ), //通道2 写侧有效
.ch2_wr_vsync (ch2_vsync ), //通道2 写侧同步
.ch2_rd_clk (clk_VGA ), //通道2 读侧时钟
.ch2_rd_data (ch2_VGA_din ), //通道2 读侧数据
.ch2_rd_req (ch2_VGA_req ), //通道2 读侧请求
.ch2_rd_vsync (VGA_vsync ), //通道2 读侧同步
//通道3 -----------------------------------------
.ch3_en (1'b1 ), //通道3 使能
.ch3_addr (3'h3 ), //通道3 地址
.ch3_wr_clk (ch3_clk ), //通道3 写侧时钟
.ch3_wr_data (ch3_data ), //通道3 写侧数据
.ch3_wr_vld (ch3_vld ), //通道3 写侧有效
.ch3_wr_vsync (ch3_vsync ), //通道3 写侧同步
.ch3_rd_clk (clk_VGA ), //通道3 读侧时钟
.ch3_rd_data (ch3_VGA_din ), //通道3 读侧数据
.ch3_rd_req (ch3_VGA_req ), //通道3 读侧请求
.ch3_rd_vsync (VGA_vsync ), //通道3 读侧同步
//通道4 -----------------------------------------
.ch4_en (1'b1 ), //通道4 使能
.ch4_addr (3'h4 ), //通道4 地址
.ch4_wr_clk (ch4_clk ), //通道4 写侧时钟
.ch4_wr_data (ch4_data ), //通道4 写侧数据
.ch4_wr_vld (ch4_vld ), //通道4 写侧有效
.ch4_wr_vsync (ch4_vsync ), //通道4 写侧同步
.ch4_rd_clk (clk_VGA ), //通道4 读侧时钟
.ch4_rd_data (ch4_VGA_din ), //通道4 读侧数据
.ch4_rd_req (ch4_VGA_req ), //通道4 读侧请求
.ch4_rd_vsync (VGA_vsync ), //通道4 读侧同步
//通道5 -----------------------------------------
.ch5_en (1'b1 ), //通道5 使能
.ch5_addr (3'h5 ), //通道5 地址
.ch5_wr_clk (ch5_clk ), //通道5 写侧时钟
.ch5_wr_data (ch5_data ), //通道5 写侧数据
.ch5_wr_vld (ch5_vld ), //通道5 写侧有效
.ch5_wr_vsync (ch5_vsync ), //通道5 写侧同步
.ch5_rd_clk (clk_VGA ), //通道5 读侧时钟
.ch5_rd_data (ch5_VGA_din ), //通道5 读侧数据
.ch5_rd_req (ch5_VGA_req ), //通道5 读侧请求
.ch5_rd_vsync (VGA_vsync ), //通道5 读侧同步
//通道6 -----------------------------------------
.ch6_en (1'b1 ), //通道6 使能
.ch6_addr (3'h6 ), //通道6 地址
.ch6_wr_clk (ch6_clk ), //通道6 写侧时钟
.ch6_wr_data (ch6_data ), //通道6 写侧数据
.ch6_wr_vld (ch6_vld ), //通道6 写侧有效
.ch6_wr_vsync (ch6_vsync ), //通道6 写侧同步
.ch6_rd_clk (clk_VGA ), //通道6 读侧时钟
.ch6_rd_data (ch6_VGA_din ), //通道6 读侧数据
.ch6_rd_req (ch6_VGA_req ), //通道6 读侧请求
.ch6_rd_vsync (VGA_vsync ), //通道6 读侧同步
//通道7 -----------------------------------------
.ch7_en (1'b1 ), //通道7 使能
.ch7_addr (3'h7 ), //通道7 地址
.ch7_wr_clk (ch7_clk ), //通道7 写侧时钟
.ch7_wr_data (ch7_data ), //通道7 写侧数据
.ch7_wr_vld (ch7_vld ), //通道7 写侧有效
.ch7_wr_vsync (ch7_vsync ), //通道7 写侧同步
.ch7_rd_clk (clk_VGA ), //通道7 读侧时钟
.ch7_rd_data (ch7_VGA_din ), //通道7 读侧数据
.ch7_rd_req (ch7_VGA_req ), //通道7 读侧请求
.ch7_rd_vsync (VGA_vsync ) //通道7 读侧同步
);
(2) DDR2_8port
DDR2_8port
//**************************************************************************
// *** 名称 : DDR2_8port.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2020年6月
// *** 描述 : 多通道视频读写突发的控制模块,每个通道都可以选择是否使用
//**************************************************************************
module DDR2_8port
//============================< 参数 >======================================
#(
parameter MEM_DM_W = 4 , //DDR2 dm位宽
parameter MEM_DQS_W = 4 , //DDR2 dqs位宽
parameter MEM_BANK_W = 3 , //DDR2 bank位宽
parameter MEM_ADDR_W = 13 , //DDR2 地址位宽
parameter MEM_DQ_W = 32 , //DDR2 数据位宽,一片16两片32
//-------------------------------------------------------
parameter LOCAL_SIZE_W = 3 , //DDR2 IP核local_size位宽
parameter LOCAL_DATA_W = 64 , //DDR2 IP核数据位宽
parameter LOCAL_ADDR_W = 25 //DDR2 IP核地址位宽
)
//============================< 端口 >======================================
(
//时钟和复位 --------------------------------------------
input pll_ref_clk , //DDR2输入时钟
input global_reset_n , //全局复位信号
//DDR2端口 ----------------------------------------------
output mem_odt , //DDR2片上终结信号
output mem_cs_n , //DDR2片选信号
output mem_cke , //DDR2时钟使能信号
output [MEM_ADDR_W -1:0] mem_addr , //DDR2地址总线
output [MEM_BANK_W -1:0] mem_ba , //DDR2BANK信号
output mem_ras_n , //DDR2行地址选择信号
output mem_cas_n , //DDR2列地址选择信号
output mem_we_n , //DDR2写使能信号
output [MEM_DM_W -1:0] mem_dm , //DDR2数据掩膜信号
inout mem_clk , //DDR2时钟信号
inout mem_clk_n , //DDR2时钟反相信号
inout [MEM_DQ_W -1:0] mem_dq , //DDR2数据总线
inout [MEM_DQS_W -1:0] mem_dqs , //DDR2数据源同步信号
//DDR3控制 ----------------------------------------------
output DDR2_rst_n , //DDR2 同步复位
input pingpang_vld , //乒乓操作
input [LOCAL_ADDR_W -3:0] min_addr , //起始地址,3位选通1位乒乓再扩大4倍:-4+2
input [LOCAL_ADDR_W -3:0] max_addr , //结束地址,3位选通1位乒乓再扩大4倍:-4+2
input [LOCAL_ADDR_W -3:0] burst_len , //突发长度
//通道0 -------------------------------------------------
input ch0_en , //通道0 使能
input [ 2:0] ch0_addr , //通道0 地址
input ch0_wr_clk , //通道0 写侧时钟
input [15:0] ch0_wr_data , //通道0 写侧数据
input ch0_wr_vld , //通道0 写侧有效
input ch0_wr_vsync , //通道0 写侧同步
input ch0_rd_clk , //通道0 读侧时钟
output [15:0] ch0_rd_data , //通道0 读侧数据
input ch0_rd_req , //通道0 读侧请求
input ch0_rd_vsync , //通道0 读侧同步
//通道1 -------------------------------------------------
input ch1_en , //通道1 使能
input [ 2:0] ch1_addr , //通道1 地址
input ch1_wr_clk , //通道1 写侧时钟
input [15:0] ch1_wr_data , //通道1 写侧数据
input ch1_wr_vld , //通道1 写侧有效
input ch1_wr_vsync , //通道1 写侧同步
input ch1_rd_clk , //通道1 读侧时钟
output [15:0] ch1_rd_data , //通道1 读侧数据
input ch1_rd_req , //通道1 读侧请求
input ch1_rd_vsync , //通道1 读侧同步
//通道2 -------------------------------------------------
input ch2_en , //通道2 使能
input [ 2:0] ch2_addr , //通道2 地址
input ch2_wr_clk , //通道2 写侧时钟
input [15:0] ch2_wr_data , //通道2 写侧数据
input ch2_wr_vld , //通道2 写侧有效
input ch2_wr_vsync , //通道2 写侧同步
input ch2_rd_clk , //通道2 读侧时钟
output [15:0] ch2_rd_data , //通道2 读侧数据
input ch2_rd_req , //通道2 读侧请求
input ch2_rd_vsync , //通道2 读侧同步
//通道3 -------------------------------------------------
input ch3_en , //通道3 使能
input [ 2:0] ch3_addr , //通道3 地址
input ch3_wr_clk , //通道3 写侧 时钟
input [15:0] ch3_wr_data , //通道3 写侧 数据
input ch3_wr_vld , //通道3 写侧 有效
input ch3_wr_vsync , //通道3 写侧 同步
input ch3_rd_clk , //通道3 读侧 时钟
output [15:0] ch3_rd_data , //通道3 读侧 数据
input ch3_rd_req , //通道3 读侧 请求
input ch3_rd_vsync , //通道3 读侧 同步
//通道4 -------------------------------------------------
input ch4_en , //通道4 使能
input [ 2:0] ch4_addr , //通道4 地址
input ch4_wr_clk , //通道4 写侧时钟
input [15:0] ch4_wr_data , //通道4 写侧数据
input ch4_wr_vld , //通道4 写侧有效
input ch4_wr_vsync , //通道4 写侧同步
input ch4_rd_clk , //通道4 读侧时钟
output [15:0] ch4_rd_data , //通道4 读侧数据
input ch4_rd_req , //通道4 读侧请求
input ch4_rd_vsync , //通道4 读侧同步
//通道5 -------------------------------------------------
input ch5_en , //通道5 使能
input [ 2:0] ch5_addr , //通道5 地址
input ch5_wr_clk , //通道5 写侧时钟
input [15:0] ch5_wr_data , //通道5 写侧数据
input ch5_wr_vld , //通道5 写侧有效
input ch5_wr_vsync , //通道5 写侧同步
input ch5_rd_clk , //通道5 读侧时钟
output [15:0] ch5_rd_data , //通道5 读侧数据
input ch5_rd_req , //通道5 读侧请求
input ch5_rd_vsync , //通道5 读侧同步
//通道6 -------------------------------------------------
input ch6_en , //通道6 使能
input [ 2:0] ch6_addr , //通道6 地址
input ch6_wr_clk , //通道6 写侧时钟
input [15:0] ch6_wr_data , //通道6 写侧数据
input ch6_wr_vld , //通道6 写侧有效
input ch6_wr_vsync , //通道6 写侧同步
input ch6_rd_clk , //通道6 读侧时钟
output [15:0] ch6_rd_data , //通道6 读侧数据
input ch6_rd_req , //通道6 读侧请求
input ch6_rd_vsync , //通道6 读侧 同步
//通道0 -------------------------------------------------
input ch7_en , //通道7 使能
input [ 2:0] ch7_addr , //通道7 地址
input ch7_wr_clk , //通道7 写侧时钟
input [15:0] ch7_wr_data , //通道7 写侧数据
input ch7_wr_vld , //通道7 写侧有效
input ch7_wr_vsync , //通道7 写侧同步
input ch7_rd_clk , //通道7 读侧时钟
output [15:0] ch7_rd_data , //通道7 读侧数据
input ch7_rd_req , //通道7 读侧请求
input ch7_rd_vsync //通道7 读侧同步
);
//============================< 信号 >======================================
wire phy_clk ; //DDR2工作时钟
wire [LOCAL_DATA_W -1:0] burst_rd_data ; //读突发数据
wire [LOCAL_DATA_W -1:0] burst_wr_data ; //写突发数据
wire burst_rd_ack ; //读突发应答信号
wire burst_wr_ack ; //写突发应答信号
wire burst_rd_done ; //突发读完成信号
wire burst_wr_done ; //突发写完成信号
reg burst_wr_req ; //突发写请求
reg burst_rd_req ; //突发读请求
//FIFO --------------------------------------------------
wire [LOCAL_DATA_W -1:0] ch0_wrFIFO_q ; //通道0读数据
wire [LOCAL_DATA_W -1:0] ch1_wrFIFO_q ; //通道1读数据
wire [LOCAL_DATA_W -1:0] ch2_wrFIFO_q ; //通道2读数据
wire [LOCAL_DATA_W -1:0] ch3_wrFIFO_q ; //通道3读数据
wire [LOCAL_DATA_W -1:0] ch4_wrFIFO_q ; //通道4读数据
wire [LOCAL_DATA_W -1:0] ch5_wrFIFO_q ; //通道5读数据
wire [LOCAL_DATA_W -1:0] ch6_wrFIFO_q ; //通道6读数据
wire [LOCAL_DATA_W -1:0] ch7_wrFIFO_q ; //通道7读数据
wire [ 7:0] ch0_wrFIFO_rdusedw ; //通道0写FIFO剩余数据个数
wire [ 7:0] ch1_wrFIFO_rdusedw ; //通道1写FIFO剩余数据个数
wire [ 7:0] ch2_wrFIFO_rdusedw ; //通道2写FIFO剩余数据个数
wire [ 7:0] ch3_wrFIFO_rdusedw ; //通道3写FIFO剩余数据个数
wire [ 7:0] ch4_wrFIFO_rdusedw ; //通道4写FIFO剩余数据个数
wire [ 7:0] ch5_wrFIFO_rdusedw ; //通道5写FIFO剩余数据个数
wire [ 7:0] ch6_wrFIFO_rdusedw ; //通道6写FIFO剩余数据个数
wire [ 7:0] ch7_wrFIFO_rdusedw ; //通道7写FIFO剩余数据个数
wire [ 7:0] ch0_rdFIFO_wrusedw ; //通道0读FIFO剩余数据个数
wire [ 7:0] ch1_rdFIFO_wrusedw ; //通道1读FIFO剩余数据个数
wire [ 7:0] ch2_rdFIFO_wrusedw ; //通道2读FIFO剩余数据个数
wire [ 7:0] ch3_rdFIFO_wrusedw ; //通道3读FIFO剩余数据个数
wire [ 7:0] ch4_rdFIFO_wrusedw ; //通道4读FIFO剩余数据个数
wire [ 7:0] ch5_rdFIFO_wrusedw ; //通道5读FIFO剩余数据个数
wire [ 7:0] ch6_rdFIFO_wrusedw ; //通道6读FIFO剩余数据个数
wire [ 7:0] ch7_rdFIFO_wrusedw ; //通道7读FIFO剩余数据个数
//FIFO异步清0 -------------------------------------------
reg ch0_wr_vsync_r ; //通道0 写的场信号打一拍
reg ch1_wr_vsync_r ; //通道1 写的场信号打一拍
reg ch2_wr_vsync_r ; //通道2 写的场信号打一拍
reg ch3_wr_vsync_r ; //通道3 写的场信号打一拍
reg ch4_wr_vsync_r ; //通道4 写的场信号打一拍
reg ch5_wr_vsync_r ; //通道5 写的场信号打一拍
reg ch6_wr_vsync_r ; //通道6 写的场信号打一拍
reg ch7_wr_vsync_r ; //通道7 写的场信号打一拍
reg ch0_rd_vsync_r ; //通道0 写的场信号打一拍
reg ch1_rd_vsync_r ; //通道1 写的场信号打一拍
reg ch2_rd_vsync_r ; //通道2 写的场信号打一拍
reg ch3_rd_vsync_r ; //通道3 写的场信号打一拍
reg ch4_rd_vsync_r ; //通道4 写的场信号打一拍
reg ch5_rd_vsync_r ; //通道5 写的场信号打一拍
reg ch6_rd_vsync_r ; //通道6 写的场信号打一拍
reg ch7_rd_vsync_r ; //通道7 写的场信号打一拍
wire ch0_wr_rst ; //通道0 写的场复位信号
wire ch1_wr_rst ; //通道1 写的场复位信号
wire ch2_wr_rst ; //通道2 写的场复位信号
wire ch3_wr_rst ; //通道3 写的场复位信号
wire ch4_wr_rst ; //通道4 写的场复位信号
wire ch5_wr_rst ; //通道5 写的场复位信号
wire ch6_wr_rst ; //通道6 写的场复位信号
wire ch7_wr_rst ; //通道7 写的场复位信号
wire ch0_rd_rst ; //通道0 写的场复位信号
wire ch1_rd_rst ; //通道1 写的场复位信号
wire ch2_rd_rst ; //通道2 写的场复位信号
wire ch3_rd_rst ; //通道3 写的场复位信号
wire ch4_rd_rst ; //通道4 写的场复位信号
wire ch5_rd_rst ; //通道5 写的场复位信号
wire ch6_rd_rst ; //通道6 写的场复位信号
wire ch7_rd_rst ; //通道7 写的场复位信号
//-------------------------------------------------------
reg ch0_wr_addr_msb ; //通道0乒乓操作写分区
reg ch0_rd_addr_msb ; //通道0乒乓操作读分区
reg ch1_wr_addr_msb ; //通道1乒乓操作写分区
reg ch1_rd_addr_msb ; //通道1乒乓操作读分区
reg ch2_wr_addr_msb ; //通道2乒乓操作写分区
reg ch2_rd_addr_msb ; //通道2乒乓操作读分区
reg ch3_wr_addr_msb ; //通道3乒乓操作写分区
reg ch3_rd_addr_msb ; //通道3乒乓操作读分区
reg ch4_wr_addr_msb ; //通道4乒乓操作写分区
reg ch4_rd_addr_msb ; //通道4乒乓操作读分区
reg ch5_wr_addr_msb ; //通道5乒乓操作写分区
reg ch5_rd_addr_msb ; //通道5乒乓操作读分区
reg ch6_wr_addr_msb ; //通道6乒乓操作写分区
reg ch6_rd_addr_msb ; //通道6乒乓操作读分区
reg ch7_wr_addr_msb ; //通道7乒乓操作写分区
reg ch7_rd_addr_msb ; //通道7乒乓操作读分区
//-------------------------------------------------------
reg [LOCAL_ADDR_W -3:2] ch0_wr_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch1_wr_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch2_wr_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch3_wr_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch4_wr_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch5_wr_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch6_wr_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch7_wr_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch0_rd_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch1_rd_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch2_rd_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch3_rd_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch4_rd_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch5_rd_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch6_rd_addr ; //地址除以4
reg [LOCAL_ADDR_W -3:2] ch7_rd_addr ; //地址除以4
//-------------------------------------------------------
wire [LOCAL_ADDR_W -1:0] burst_wr_addr ; //写突发地址
wire [LOCAL_ADDR_W -1:0] burst_rd_addr ; //读突发地址
reg [ 2:0] wr_ch ; //写通道
reg [ 2:0] rd_ch ; //读通道
reg [ 5:0] state ; //状态机
//============================< 参数 >======================================
localparam IDLE = 6'b000001 ; //空闲
localparam ARBIT = 6'b000010 ; //仲裁
localparam WR = 6'b000100 ; //写
localparam WR_DONE = 6'b001000 ; //写完成
localparam RD = 6'b010000 ; //读
localparam RD_DONE = 6'b100000 ; //读完成
//==========================================================================
//== DDR2突发读写模块,实现一段长度的突发读写
//==========================================================================
DDR2_burst u_DDR2_burst
(
//DDR2 IP核接口 -------------------------------------
.pll_ref_clk (pll_ref_clk ), //DDR2 参考时钟
.global_reset_n (global_reset_n ), //DDR2 全局复位
.phy_clk (phy_clk ), //DDR2 工作时钟
.DDR2_rst_n (DDR2_rst_n ), //DDR2 同步复位
//突发读写接口 --------------------------------------
.burst_rd_req (burst_rd_req ), //突发读请求
.burst_wr_req (burst_wr_req ), //突发写请求
.burst_rd_len (burst_len ), //突发读长度
.burst_wr_len (burst_len ), //突发写长度
.burst_rd_addr (burst_rd_addr ), //突发读地址
.burst_wr_addr (burst_wr_addr ), //突发写地址
.burst_rd_data (burst_rd_data ), //突发读数据
.burst_wr_data (burst_wr_data ), //突发写数据
.burst_rd_ack (burst_rd_ack ), //突发读应答,连接FIFO
.burst_wr_ack (burst_wr_ack ), //突发写应答,连接FIFO
.burst_rd_done (burst_rd_done ), //突发读完成信号
.burst_wr_done (burst_wr_done ), //突发写完成信号
//DDR2 芯片接口 --------------------------------------
.mem_odt (mem_odt ), //DDR2片上终结信号
.mem_cs_n (mem_cs_n ), //DDR2片选信号
.mem_cke (mem_cke ), //DDR2时钟使能信号
.mem_addr (mem_addr ), //DDR2地址总线
.mem_ba (mem_ba ), //DDR2bank信号
.mem_ras_n (mem_ras_n ), //DDR2行地址选择信号
.mem_cas_n (mem_cas_n ), //DDR2列地址选择信号
.mem_we_n (mem_we_n ), //DDR2写使能信号
.mem_dm (mem_dm ), //DDR2数据掩膜信号
.mem_clk (mem_clk ), //DDR2时钟信号
.mem_clk_n (mem_clk_n ), //DDR2时钟反相信号
.mem_dq (mem_dq ), //DDR2数据总线
.mem_dqs (mem_dqs ) //DDR2数据源同步信号
);
//==========================================================================
//== FIFO的异步复位
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch0_wr_vsync_r <= 1'b0;
ch1_wr_vsync_r <= 1'b0;
ch2_wr_vsync_r <= 1'b0;
ch3_wr_vsync_r <= 1'b0;
ch4_wr_vsync_r <= 1'b0;
ch5_wr_vsync_r <= 1'b0;
ch6_wr_vsync_r <= 1'b0;
ch7_wr_vsync_r <= 1'b0;
ch0_rd_vsync_r <= 1'b0;
ch1_rd_vsync_r <= 1'b0;
ch2_rd_vsync_r <= 1'b0;
ch3_rd_vsync_r <= 1'b0;
ch4_rd_vsync_r <= 1'b0;
ch5_rd_vsync_r <= 1'b0;
ch6_rd_vsync_r <= 1'b0;
ch7_rd_vsync_r <= 1'b0;
end
else begin
ch0_wr_vsync_r <= ch0_wr_vsync;
ch1_wr_vsync_r <= ch1_wr_vsync;
ch2_wr_vsync_r <= ch2_wr_vsync;
ch3_wr_vsync_r <= ch3_wr_vsync;
ch4_wr_vsync_r <= ch4_wr_vsync;
ch5_wr_vsync_r <= ch5_wr_vsync;
ch6_wr_vsync_r <= ch6_wr_vsync;
ch7_wr_vsync_r <= ch7_wr_vsync;
ch0_rd_vsync_r <= ch0_rd_vsync;
ch1_rd_vsync_r <= ch1_rd_vsync;
ch2_rd_vsync_r <= ch2_rd_vsync;
ch3_rd_vsync_r <= ch3_rd_vsync;
ch4_rd_vsync_r <= ch4_rd_vsync;
ch5_rd_vsync_r <= ch5_rd_vsync;
ch6_rd_vsync_r <= ch6_rd_vsync;
ch7_rd_vsync_r <= ch7_rd_vsync;
end
end
assign ch0_wr_rst = 0;//ch0_wr_vsync_r && !ch0_wr_vsync;
assign ch1_wr_rst = 0;//ch1_wr_vsync_r && !ch1_wr_vsync;
assign ch2_wr_rst = 0;//ch2_wr_vsync_r && !ch2_wr_vsync;
assign ch3_wr_rst = 0;//ch3_wr_vsync_r && !ch3_wr_vsync;
assign ch4_wr_rst = 0;//ch4_wr_vsync_r && !ch4_wr_vsync;
assign ch5_wr_rst = 0;//ch5_wr_vsync_r && !ch5_wr_vsync;
assign ch6_wr_rst = 0;//ch6_wr_vsync_r && !ch6_wr_vsync;
assign ch7_wr_rst = 0;//ch7_wr_vsync_r && !ch7_wr_vsync;
assign ch0_rd_rst = !ch0_rd_vsync_r && ch0_rd_vsync;
assign ch1_rd_rst = !ch1_rd_vsync_r && ch1_rd_vsync;
assign ch2_rd_rst = !ch2_rd_vsync_r && ch2_rd_vsync;
assign ch3_rd_rst = !ch3_rd_vsync_r && ch3_rd_vsync;
assign ch4_rd_rst = !ch4_rd_vsync_r && ch4_rd_vsync;
assign ch5_rd_rst = !ch5_rd_vsync_r && ch5_rd_vsync;
assign ch6_rd_rst = !ch6_rd_vsync_r && ch6_rd_vsync;
assign ch7_rd_rst = !ch7_rd_vsync_r && ch7_rd_vsync;
//==========================================================================
//== 根据FIFO的状态,选择读写操作通道
//==========================================================================
//写通道
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
wr_ch <= 3'h0;
end
else if(state == ARBIT && ch0_en && ch0_wrFIFO_rdusedw >= burst_len) begin
wr_ch <= 3'h0;
end
else if(state == ARBIT && ch1_en && ch1_wrFIFO_rdusedw >= burst_len) begin
wr_ch <= 3'h1;
end
else if(state == ARBIT && ch2_en && ch2_wrFIFO_rdusedw >= burst_len) begin
wr_ch <= 3'h2;
end
else if(state == ARBIT && ch3_en && ch3_wrFIFO_rdusedw >= burst_len) begin
wr_ch <= 3'h3;
end
else if(state == ARBIT && ch4_en && ch4_wrFIFO_rdusedw >= burst_len) begin
wr_ch <= 3'h4;
end
else if(state == ARBIT && ch5_en && ch5_wrFIFO_rdusedw >= burst_len) begin
wr_ch <= 3'h5;
end
else if(state == ARBIT && ch6_en && ch6_wrFIFO_rdusedw >= burst_len) begin
wr_ch <= 3'h6;
end
else if(state == ARBIT && ch7_en && ch7_wrFIFO_rdusedw >= burst_len) begin
wr_ch <= 3'h7;
end
end
//读通道
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
rd_ch <= 3'h0;
end
else if(state == ARBIT && ch0_en && ch0_rdFIFO_wrusedw < burst_len) begin
rd_ch <= 3'h0;
end
else if(state == ARBIT && ch1_en && ch1_rdFIFO_wrusedw < burst_len) begin
rd_ch <= 3'h1;
end
else if(state == ARBIT && ch2_en && ch2_rdFIFO_wrusedw < burst_len) begin
rd_ch <= 3'h2;
end
else if(state == ARBIT && ch3_en && ch3_rdFIFO_wrusedw < burst_len) begin
rd_ch <= 3'h3;
end
else if(state == ARBIT && ch4_en && ch4_rdFIFO_wrusedw < burst_len) begin
rd_ch <= 3'h4;
end
else if(state == ARBIT && ch5_en && ch5_rdFIFO_wrusedw < burst_len) begin
rd_ch <= 3'h5;
end
else if(state == ARBIT && ch6_en && ch6_rdFIFO_wrusedw < burst_len) begin
rd_ch <= 3'h6;
end
else if(state == ARBIT && ch7_en && ch7_rdFIFO_wrusedw < burst_len) begin
rd_ch <= 3'h7;
end
end
//==========================================================================
//== FIFO
//==========================================================================
//写FIFO通道0
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch0
(
.wrclk (ch0_wr_clk ),
.wrreq (ch0_wr_vld ),
.data (ch0_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wr_ack && wr_ch==3'h0 ),
.q (ch0_wrFIFO_q ),
.rdusedw (ch0_wrFIFO_rdusedw ),
.aclr (!DDR2_rst_n || ch0_wr_rst )
);
//写FIFO通道1
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch1
(
.wrclk (ch1_wr_clk ),
.wrreq (ch1_wr_vld ),
.data (ch1_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wr_ack && wr_ch==3'h1 ),
.q (ch1_wrFIFO_q ),
.rdusedw (ch1_wrFIFO_rdusedw ),
.aclr (!DDR2_rst_n || ch1_wr_rst )
);
//写FIFO通道2
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch2
(
.wrclk (ch2_wr_clk ),
.wrreq (ch2_wr_vld ),
.data (ch2_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wr_ack && wr_ch==3'h2 ),
.q (ch2_wrFIFO_q ),
.rdusedw (ch2_wrFIFO_rdusedw ),
.aclr (!DDR2_rst_n || ch2_wr_rst )
);
//写FIFO通道3
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch3
(
.wrclk (ch3_wr_clk ),
.wrreq (ch3_wr_vld ),
.data (ch3_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wr_ack && wr_ch==3'h3 ),
.q (ch3_wrFIFO_q ),
.rdusedw (ch3_wrFIFO_rdusedw ),
.aclr (!DDR2_rst_n || ch3_wr_rst )
);
//写FIFO通道4
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch4
(
.wrclk (ch4_wr_clk ),
.wrreq (ch4_wr_vld ),
.data (ch4_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wr_ack && wr_ch==3'h4 ),
.q (ch4_wrFIFO_q ),
.rdusedw (ch4_wrFIFO_rdusedw ),
.aclr (!DDR2_rst_n || ch4_wr_rst )
);
//写FIFO通道5
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch5
(
.wrclk (ch5_wr_clk ),
.wrreq (ch5_wr_vld ),
.data (ch5_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wr_ack && wr_ch==3'h5 ),
.q (ch5_wrFIFO_q ),
.rdusedw (ch5_wrFIFO_rdusedw ),
.aclr (!DDR2_rst_n || ch5_wr_rst )
);
//写FIFO通道6
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch6
(
.wrclk (ch6_wr_clk ),
.wrreq (ch6_wr_vld ),
.data (ch6_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wr_ack && wr_ch==3'h6 ),
.q (ch6_wrFIFO_q ),
.rdusedw (ch6_wrFIFO_rdusedw ),
.aclr (!DDR2_rst_n || ch6_wr_rst )
);
//写FIFO通道7
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch7
(
.wrclk (ch7_wr_clk ),
.wrreq (ch7_wr_vld ),
.data (ch7_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wr_ack && wr_ch==3'h7 ),
.q (ch7_wrFIFO_q ),
.rdusedw (ch7_wrFIFO_rdusedw ),
.aclr (!DDR2_rst_n || ch7_wr_rst )
);
//根据通道选择写入相应FIFO的数据
//---------------------------------------------------
assign burst_wr_data = (wr_ch == 3'h7) ? ch7_wrFIFO_q :
(wr_ch == 3'h6) ? ch6_wrFIFO_q :
(wr_ch == 3'h5) ? ch5_wrFIFO_q :
(wr_ch == 3'h4) ? ch4_wrFIFO_q :
(wr_ch == 3'h3) ? ch3_wrFIFO_q :
(wr_ch == 3'h2) ? ch2_wrFIFO_q :
(wr_ch == 3'h1) ? ch1_wrFIFO_q :
ch0_wrFIFO_q ;
//读FIFO通道0
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch0
(
.wrclk (phy_clk ),
.wrreq (burst_rd_ack && rd_ch==3'h0 ),
.data (burst_rd_data ),
.rdclk (ch0_rd_clk ),
.rdreq (ch0_rd_req ),
.q (ch0_rd_data ), //输出到端口0
.wrusedw (ch0_rdFIFO_wrusedw ),
.aclr (!DDR2_rst_n || ch0_rd_rst )
);
//读FIFO通道1
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch1
(
.wrclk (phy_clk ),
.wrreq (burst_rd_ack && rd_ch==3'h1 ),
.data (burst_rd_data ),
.rdclk (ch1_rd_clk ),
.rdreq (ch1_rd_req ),
.q (ch1_rd_data ), //输出到端口1
.wrusedw (ch1_rdFIFO_wrusedw ),
.aclr (!DDR2_rst_n || ch1_rd_rst )
);
//读FIFO通道2
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch2
(
.wrclk (phy_clk ),
.wrreq (burst_rd_ack && rd_ch==3'h2 ),
.data (burst_rd_data ),
.rdclk (ch2_rd_clk ),
.rdreq (ch2_rd_req ),
.q (ch2_rd_data ), //输出到端口2
.wrusedw (ch2_rdFIFO_wrusedw ),
.aclr (!DDR2_rst_n || ch2_rd_rst )
);
//读FIFO通道3
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch3
(
.wrclk (phy_clk ),
.wrreq (burst_rd_ack && rd_ch==3'h3 ),
.data (burst_rd_data ),
.rdclk (ch3_rd_clk ),
.rdreq (ch3_rd_req ),
.q (ch3_rd_data ), //输出到端口3
.wrusedw (ch3_rdFIFO_wrusedw ),
.aclr (!DDR2_rst_n || ch3_rd_rst )
);
//读FIFO通道4
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch4
(
.wrclk (phy_clk ),
.wrreq (burst_rd_ack && rd_ch==3'h4 ),
.data (burst_rd_data ),
.rdclk (ch4_rd_clk ),
.rdreq (ch4_rd_req ),
.q (ch4_rd_data ), //输出到端口4
.wrusedw (ch4_rdFIFO_wrusedw ),
.aclr (!DDR2_rst_n || ch4_rd_rst )
);
//读FIFO通道5
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch5
(
.wrclk (phy_clk ),
.wrreq (burst_rd_ack && rd_ch==3'h5 ),
.data (burst_rd_data ),
.rdclk (ch5_rd_clk ),
.rdreq (ch5_rd_req ),
.q (ch5_rd_data ), //输出到端口5
.wrusedw (ch5_rdFIFO_wrusedw ),
.aclr (!DDR2_rst_n || ch5_rd_rst )
);
//读FIFO通道6
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch6
(
.wrclk (phy_clk ),
.wrreq (burst_rd_ack && rd_ch==3'h6 ),
.data (burst_rd_data ),
.rdclk (ch6_rd_clk ),
.rdreq (ch6_rd_req ),
.q (ch6_rd_data ), //输出到端口6
.wrusedw (ch6_rdFIFO_wrusedw ),
.aclr (!DDR2_rst_n || ch6_rd_rst )
);
//读FIFO通道7
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch7
(
.wrclk (phy_clk ),
.wrreq (burst_rd_ack && rd_ch==3'h7 ),
.data (burst_rd_data ),
.rdclk (ch7_rd_clk ),
.rdreq (ch7_rd_req ),
.q (ch7_rd_data ), //输出到端口7
.wrusedw (ch7_rdFIFO_wrusedw ),
.aclr (!DDR2_rst_n || ch7_rd_rst )
);
//==========================================================================
//== 状态机
//==========================================================================
always @(posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
state <= IDLE;
end
else begin
case(state)
//--------------------------------------------------- 空闲
IDLE: begin
state = ARBIT;
end
//--------------------------------------------------- 仲裁
ARBIT: begin
if((ch0_en && ch0_wrFIFO_rdusedw >= burst_len) || (ch1_en && ch1_wrFIFO_rdusedw >= burst_len) ||
(ch2_en && ch2_wrFIFO_rdusedw >= burst_len) || (ch3_en && ch3_wrFIFO_rdusedw >= burst_len) ||
(ch4_en && ch4_wrFIFO_rdusedw >= burst_len) || (ch5_en && ch5_wrFIFO_rdusedw >= burst_len) ||
(ch6_en && ch6_wrFIFO_rdusedw >= burst_len) || (ch7_en && ch7_wrFIFO_rdusedw >= burst_len))
state = WR;
else if((ch0_en && ch0_rdFIFO_wrusedw < burst_len) || (ch1_en && ch1_rdFIFO_wrusedw < burst_len) ||
(ch2_en && ch2_rdFIFO_wrusedw < burst_len) || (ch3_en && ch3_rdFIFO_wrusedw < burst_len) ||
(ch4_en && ch4_rdFIFO_wrusedw < burst_len) || (ch5_en && ch5_rdFIFO_wrusedw < burst_len) ||
(ch6_en && ch6_rdFIFO_wrusedw < burst_len) || (ch7_en && ch7_rdFIFO_wrusedw < burst_len))
state = RD;
else if(!ch0_en && !ch1_en && !ch2_en && !ch3_en &&
!ch4_en && !ch5_en && !ch6_en && !ch7_en)
state = IDLE;
end
//--------------------------------------------------- 写
WR: begin
if(burst_wr_done)
state = WR_DONE;
end
//--------------------------------------------------- 写完成
WR_DONE:begin
state = IDLE;
end
//--------------------------------------------------- 读
RD: begin
if(burst_rd_done)
state = RD_DONE;
end
//--------------------------------------------------- 读完成
RD_DONE:begin
state = IDLE;
end
default: state = IDLE;
endcase
end
end
//==========================================================================
//== 读写请求
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
burst_wr_req <= 1'b0;
end
else if(burst_wr_req == 1'b0 && state == WR) begin
burst_wr_req <= 1'b1;
end
else if(burst_wr_req == 1'b1 && state == WR && burst_wr_done) begin
burst_wr_req <= 1'b0;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
burst_rd_req <= 1'b0;
end
else if(burst_rd_req == 1'b0 && state == RD) begin
burst_rd_req <= 1'b1;
end
else if(burst_rd_req == 1'b1 && state == RD && burst_rd_done) begin
burst_rd_req <= 1'b0;
end
end
//==========================================================================
//== 读写地址设计
//==========================================================================
//通道0
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch0_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch0_wr_rst) begin
ch0_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(wr_ch == 3'h0 && state == WR && burst_wr_done) begin
if(ch0_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch0_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch0_wr_addr <= ch0_wr_addr + burst_len;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch0_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch0_rd_rst) begin
ch0_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(rd_ch == 3'h0 && state == RD && burst_rd_done) begin
if(ch0_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch0_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch0_rd_addr <= ch0_rd_addr + burst_len;
end
end
//通道1
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch1_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch1_wr_rst) begin
ch1_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(wr_ch == 3'h1 && state == WR && burst_wr_done) begin
if(ch1_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch1_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch1_wr_addr <= ch1_wr_addr + burst_len;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch1_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch1_rd_rst) begin
ch1_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(rd_ch == 3'h1 && state == RD && burst_rd_done) begin
if(ch1_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch1_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch1_rd_addr <= ch1_rd_addr + burst_len;
end
end
//通道2
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch2_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch2_wr_rst) begin
ch2_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(wr_ch == 3'h2 && state == WR && burst_wr_done) begin
if(ch2_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch2_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch2_wr_addr <= ch2_wr_addr + burst_len;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch2_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch2_rd_rst) begin
ch2_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(rd_ch == 3'h2 && state == RD && burst_rd_done) begin
if(ch2_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch2_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch2_rd_addr <= ch2_rd_addr + burst_len;
end
end
//通道3
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch3_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch3_wr_rst) begin
ch3_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(wr_ch == 3'h3 && state == WR && burst_wr_done) begin
if(ch3_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch3_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch3_wr_addr <= ch3_wr_addr + burst_len;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch3_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch3_rd_rst) begin
ch3_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(rd_ch == 3'h3 && state == RD && burst_rd_done) begin
if(ch3_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch3_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch3_rd_addr <= ch3_rd_addr + burst_len;
end
end
//通道4
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch4_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch4_wr_rst) begin
ch4_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(wr_ch == 3'h4 && state == WR && burst_wr_done) begin
if(ch4_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch4_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch4_wr_addr <= ch4_wr_addr + burst_len;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch4_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch4_rd_rst) begin
ch4_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(rd_ch == 3'h4 && state == RD && burst_rd_done) begin
if(ch4_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch4_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch4_rd_addr <= ch4_rd_addr + burst_len;
end
end
//通道5
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch5_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch5_wr_rst) begin
ch5_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(wr_ch == 3'h5 && state == WR && burst_wr_done) begin
if(ch5_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch5_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch5_wr_addr <= ch5_wr_addr + burst_len;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch5_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch5_rd_rst) begin
ch5_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(rd_ch == 3'h5 && state == RD && burst_rd_done) begin
if(ch5_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch5_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch5_rd_addr <= ch5_rd_addr + burst_len;
end
end
//通道6
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch6_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch6_wr_rst) begin
ch6_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(wr_ch == 3'h6 && state == WR && burst_wr_done) begin
if(ch6_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch6_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch6_wr_addr <= ch6_wr_addr + burst_len;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch6_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch6_rd_rst) begin
ch6_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(rd_ch == 3'h6 && state == RD && burst_rd_done) begin
if(ch6_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch6_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch6_rd_addr <= ch6_rd_addr + burst_len;
end
end
//通道7
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch7_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch7_wr_rst) begin
ch7_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(wr_ch == 3'h7 && state == WR && burst_wr_done) begin
if(ch7_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch7_wr_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch7_wr_addr <= ch7_wr_addr + burst_len;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch7_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(ch7_rd_rst) begin
ch7_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
end
else if(rd_ch == 3'h7 && state == RD && burst_rd_done) begin
if(ch7_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch7_rd_addr <= min_addr[LOCAL_ADDR_W-3:0];
else
ch7_rd_addr <= ch7_rd_addr + burst_len;
end
end
//==========================================================================
//== 乒乓操作
//==========================================================================
//通道0
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch0_wr_addr_msb <= 1'b0;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h0 && state == WR && burst_wr_done) begin
if(ch0_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch0_wr_addr_msb <= ~ch0_wr_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch0_wr_addr_msb <= 1'b0;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch0_rd_addr_msb <= 1'b1;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h0 && state == RD && burst_rd_done) begin
if(ch0_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len && ch0_rd_addr_msb == ch0_wr_addr_msb)
ch0_rd_addr_msb <= ~ch0_rd_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch0_rd_addr_msb <= 1'b0;
end
end
//通道1
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch1_wr_addr_msb <= 1'b0;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h1 && state == WR && burst_wr_done) begin
if(ch1_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch1_wr_addr_msb <= ~ch1_wr_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch1_wr_addr_msb <= 1'b0;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch1_rd_addr_msb <= 1'b1;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h1 && state == RD && burst_rd_done) begin
if(ch1_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len && ch1_rd_addr_msb == ch1_wr_addr_msb)
ch1_rd_addr_msb <= ~ch1_rd_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch1_rd_addr_msb <= 1'b0;
end
end
//通道2
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch2_wr_addr_msb <= 1'b0;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h2 && state == WR && burst_wr_done) begin
if(ch2_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch2_wr_addr_msb <= ~ch2_wr_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch2_wr_addr_msb <= 1'b0;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch2_rd_addr_msb <= 1'b1;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h2 && state == RD && burst_rd_done) begin
if(ch2_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len && ch2_rd_addr_msb == ch2_wr_addr_msb)
ch2_rd_addr_msb <= ~ch2_rd_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch2_rd_addr_msb <= 1'b0;
end
end
//通道3
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch3_wr_addr_msb <= 1'b0;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h3 && state == WR && burst_wr_done) begin
if(ch3_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch3_wr_addr_msb <= ~ch3_wr_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch3_wr_addr_msb <= 1'b0;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch3_rd_addr_msb <= 1'b1;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h3 && state == RD && burst_rd_done) begin
if(ch3_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len && ch3_rd_addr_msb == ch3_wr_addr_msb)
ch3_rd_addr_msb <= ~ch3_rd_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch3_rd_addr_msb <= 1'b0;
end
end
//通道4
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch4_wr_addr_msb <= 1'b0;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h4 && state == WR && burst_wr_done) begin
if(ch4_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch4_wr_addr_msb <= ~ch4_wr_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch4_wr_addr_msb <= 1'b0;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch4_rd_addr_msb <= 1'b1;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h4 && state == RD && burst_rd_done) begin
if(ch4_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len && ch4_rd_addr_msb == ch4_wr_addr_msb)
ch4_rd_addr_msb <= ~ch4_rd_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch4_rd_addr_msb <= 1'b0;
end
end
//通道5
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch5_wr_addr_msb <= 1'b0;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h5 && state == WR && burst_wr_done) begin
if(ch5_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch5_wr_addr_msb <= ~ch5_wr_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch5_wr_addr_msb <= 1'b0;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch5_rd_addr_msb <= 1'b1;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h5 && state == RD && burst_rd_done) begin
if(ch5_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len && ch5_rd_addr_msb == ch5_wr_addr_msb)
ch5_rd_addr_msb <= ~ch5_rd_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch5_rd_addr_msb <= 1'b0;
end
end
//通道6
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch6_wr_addr_msb <= 1'b0;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h6 && state == WR && burst_wr_done) begin
if(ch6_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch6_wr_addr_msb <= ~ch6_wr_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch6_wr_addr_msb <= 1'b0;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch6_rd_addr_msb <= 1'b1;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h6 && state == RD && burst_rd_done) begin
if(ch6_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len && ch6_rd_addr_msb == ch6_wr_addr_msb)
ch6_rd_addr_msb <= ~ch6_rd_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch6_rd_addr_msb <= 1'b0;
end
end
//通道7
//---------------------------------------------------
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch7_wr_addr_msb <= 1'b0;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h7 && state == WR && burst_wr_done) begin
if(ch7_wr_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len)
ch7_wr_addr_msb <= ~ch7_wr_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch7_wr_addr_msb <= 1'b0;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
ch7_rd_addr_msb <= 1'b1;
end
else if(pingpang_vld == 1'b1 && wr_ch == 3'h7 && state == RD && burst_rd_done) begin
if(ch7_rd_addr == max_addr[LOCAL_ADDR_W-3:2] - burst_len && ch7_rd_addr_msb == ch7_wr_addr_msb)
ch7_rd_addr_msb <= ~ch7_rd_addr_msb;
end
else if(pingpang_vld == 1'b0) begin
ch7_rd_addr_msb <= 1'b0;
end
end
//==========================================================================
//== 地址拼接
//==========================================================================
assign burst_wr_addr = (wr_ch == 3'h7) ? {ch7_addr,ch7_wr_addr_msb,ch7_wr_addr} :
(wr_ch == 3'h6) ? {ch6_addr,ch6_wr_addr_msb,ch6_wr_addr} :
(wr_ch == 3'h5) ? {ch5_addr,ch5_wr_addr_msb,ch5_wr_addr} :
(wr_ch == 3'h4) ? {ch4_addr,ch4_wr_addr_msb,ch4_wr_addr} :
(wr_ch == 3'h3) ? {ch3_addr,ch3_wr_addr_msb,ch3_wr_addr} :
(wr_ch == 3'h2) ? {ch2_addr,ch2_wr_addr_msb,ch2_wr_addr} :
(wr_ch == 3'h1) ? {ch1_addr,ch1_wr_addr_msb,ch1_wr_addr} :
{ch0_addr,ch0_wr_addr_msb,ch0_wr_addr} ;
assign burst_rd_addr = (rd_ch == 3'h7) ? {ch7_addr,ch7_rd_addr_msb,ch7_rd_addr} :
(rd_ch == 3'h6) ? {ch6_addr,ch6_rd_addr_msb,ch6_rd_addr} :
(rd_ch == 3'h5) ? {ch5_addr,ch5_rd_addr_msb,ch5_rd_addr} :
(rd_ch == 3'h4) ? {ch4_addr,ch4_rd_addr_msb,ch4_rd_addr} :
(rd_ch == 3'h3) ? {ch3_addr,ch3_rd_addr_msb,ch3_rd_addr} :
(rd_ch == 3'h2) ? {ch2_addr,ch2_rd_addr_msb,ch2_rd_addr} :
(rd_ch == 3'h1) ? {ch1_addr,ch1_rd_addr_msb,ch1_rd_addr} :
{ch0_addr,ch0_rd_addr_msb,ch0_rd_addr} ;
endmodule
(3) DDR2_burst
DDR2_burst
//**************************************************************************
// *** 名称 : DDR2_burst.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2020年6月
// *** 描述 : 完成一次DDR2的突发读写
//**************************************************************************
module DDR2_burst
//============================< 参数 >======================================
#(
parameter MEM_DM_W = 4 , //DDR2 dm位宽
parameter MEM_DQS_W = 4 , //DDR2 dqs位宽
parameter MEM_BANK_W = 3 , //DDR2 bank位宽
parameter MEM_ADDR_W = 13 , //DDR2 地址位宽
parameter MEM_DQ_W = 32 , //DDR2 数据位宽,一片16两片32
//-------------------------------------------------------
parameter LOCAL_SIZE_W = 3 , //DDR2 IP核local_size位宽
parameter LOCAL_DATA_W = 64 , //DDR2 IP核数据位宽
parameter LOCAL_ADDR_W = 25 //DDR2 IP核地址位宽
)
//============================< 端口 >======================================
(
//DDR2 IP核接口 -----------------------------------------
input pll_ref_clk , //DDR2 参考时钟
input global_reset_n , //FPGA 全局复位
output phy_clk , //DDR2 工作时钟
output DDR2_rst_n , //DDR2 同步复位
//突发读写接口 ------------------------------------------
input burst_rd_req , //突发读请求
input burst_wr_req , //突发写请求
input [LOCAL_ADDR_W -3:0] burst_rd_len , //突发读长度
input [LOCAL_ADDR_W -3:0] burst_wr_len , //突发写长度
input [LOCAL_ADDR_W -1:0] burst_rd_addr , //突发读地址
input [LOCAL_ADDR_W -1:0] burst_wr_addr , //突发写地址
output [LOCAL_DATA_W -1:0] burst_rd_data , //突发读数据
input [LOCAL_DATA_W -1:0] burst_wr_data , //突发写数据
output burst_rd_ack , //突发读应答,连接FIFO
output burst_wr_ack , //突发写应答,连接FIFO
output reg burst_rd_done , //突发读完成信号
output reg burst_wr_done , //突发写完成信号
//DDR2 芯片接口 -----------------------------------------
output mem_odt , //DDR2 片上终结信号
output mem_cs_n , //DDR2 片选信号
output mem_cke , //DDR2 时钟使能信号
output [MEM_ADDR_W -1:0] mem_addr , //DDR2 地址总线
output [MEM_BANK_W -1:0] mem_ba , //DDR2 BANK信号
output mem_ras_n , //DDR2 行地址选择信号
output mem_cas_n , //DDR2 列地址选择信号
output mem_we_n , //DDR2 写使能信号
output [MEM_DM_W -1:0] mem_dm , //DDR2 数据掩膜信号
inout mem_clk , //DDR2 时钟信号
inout mem_clk_n , //DDR2 时钟反相信号
inout [MEM_DQ_W -1:0] mem_dq , //DDR2 数据总线
inout [MEM_DQS_W -1:0] mem_dqs //DDR2 数据源同步信号
);
//============================< 信号 >======================================
reg [LOCAL_ADDR_W -1:0] local_address ; //DDR2 IP核地址总线
wire local_write_req ; //DDR2 IP核写请求信号
wire local_read_req ; //DDR2 IP核读请求信号
wire local_burstbegin ; //DDR2 IP核突发起始信号
wire [LOCAL_DATA_W -1:0] local_wdata ; //DDR2 IP核写数据总线
reg [LOCAL_SIZE_W -1:0] local_size ; //DDR2 IP核突发大小
wire local_ready ; //DDR2 IP核准备好信号
wire [LOCAL_DATA_W -1:0] local_rdata ; //DDR2 IP核读数据总线
wire local_rdata_valid ; //DDR2 IP核读数据有效信号
wire reset_phy_clk_n ; //DDR2 IP核复位后同步信号
wire local_init_done ; //DDR2 IP核初始化完成信号
//-------------------------------------------------------
reg [4:0] state ; //状态机
reg [LOCAL_ADDR_W -1:0] wr_len ; //读突发长度
reg [LOCAL_ADDR_W -1:0] rd_len ; //写突发长度
reg [LOCAL_ADDR_W -1:0] wr_addr_cnt ; //写地址计数器
reg [LOCAL_ADDR_W -1:0] wr_burst_cnt ; //一次突发写内的数据计数
reg [LOCAL_ADDR_W -1:0] rd_addr_cnt ; //读地址计数器
reg [LOCAL_ADDR_W -1:0] rd_data_cnt ; //读数据计数器
//============================< 参数 >======================================
localparam WR_SIZE = 2 ; //总线写突发
localparam RD_SIZE = 2 ; //总线读突发
//------------------------------------------------------
localparam IDLE = 5'b00001 ; //空闲状态
localparam ARBIT = 5'b00010 ; //仲裁状态
localparam WR = 5'b00100 ; //写状态
localparam RD_ADDR = 5'b01000 ; //读状态
localparam RD_WAIT = 5'b10000 ; //读等待状态
//==========================================================================
//== DDR2 IP核,PLL 100Mhz,DDR2 166.7Mhz,Full Rate
//==========================================================================
DDR2 u_DDR2
(
.pll_ref_clk (pll_ref_clk ), //DDR2 参考时钟
.global_reset_n (global_reset_n ), //全局复位信号
.soft_reset_n (1'b1 ), //软复位信号
.local_address (local_address ), //DDR2 IP核地址总线
.local_write_req (local_write_req ), //DDR2 IP核写请求信号
.local_read_req (local_read_req ), //DDR2 IP核读请求信号
.local_burstbegin (local_burstbegin ), //DDR2 IP核突发起始信号
.local_wdata (local_wdata ), //DDR2 IP核写数据总线
.local_be (8'b1111_1111 ), //DDR2 IP核字节使能信号
.local_size (local_size ), //DDR2 IP核突发大小
.local_ready (local_ready ), //DDR2 IP核准备好信号
.local_rdata (local_rdata ), //DDR2 IP核读数据总线
.local_rdata_valid (local_rdata_valid ), //DDR2 IP核读数据有效信号
.local_refresh_ack ( ), //DDR2 IP核自刷新应答信号
.local_init_done (local_init_done ), //DDR2 IP核初始化完成信号
//---------------------------------------------------
.mem_odt (mem_odt ), //DDR2片上终结信号
.mem_cs_n (mem_cs_n ), //DDR2片选信号
.mem_cke (mem_cke ), //DDR2时钟使能信号
.mem_addr (mem_addr ), //DDR2地址总线
.mem_ba (mem_ba ), //DDR2组地址信号
.mem_ras_n (mem_ras_n ), //DDR2行地址选择信
.mem_cas_n (mem_cas_n ), //DDR2列地址选择信
.mem_we_n (mem_we_n ), //DDR2写使能信号
.mem_dm (mem_dm ), //DDR2数据掩膜信号
.mem_clk (mem_clk ), //DDR2时钟信号
.mem_clk_n (mem_clk_n ), //DDR2时钟反相信号
.mem_dq (mem_dq ), //DDR2数据总线
.mem_dqs (mem_dqs ), //DDR2数据源同步信号
.phy_clk (phy_clk ), //DDR2 IP核工作时钟
.reset_phy_clk_n (reset_phy_clk_n ), //DDR2 IP核同步后的复位信号
.reset_request_n ( ), //DDR2 IP核复位请求信号
.aux_full_rate_clk ( ), //DDR2 IP核全速率时钟
.aux_half_rate_clk ( ) //DDR2 IP核半速率时钟
);
//本模块复位信号
assign DDR2_rst_n = reset_phy_clk_n & local_init_done;
//==========================================================================
//== 状态机
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
state <= IDLE;
burst_wr_done <= 1'b0;
burst_rd_done <= 1'b0;
end
else begin
case(state)
IDLE: begin
burst_wr_done <= 1'b0;
burst_rd_done <= 1'b0;
state <= ARBIT;
end
ARBIT: begin
if(burst_wr_req) begin
state <= WR;
end
else if(burst_rd_req) begin
state <= RD_ADDR;
end
end
WR: begin
if(wr_addr_cnt + wr_burst_cnt >= wr_len - 1 && local_ready) begin
state <= IDLE;
burst_wr_done <= 1'b1;
end
end
RD_ADDR:begin
if(rd_addr_cnt >= rd_len - RD_SIZE && local_ready) begin
state <= RD_WAIT;
end
end
RD_WAIT:begin
if(rd_data_cnt >= rd_len - 1) begin
state <= IDLE;
burst_rd_done <= 1'b1;
end
end
default:
state <= IDLE;
endcase
end
end
//------------------------------------------ 状态机名称,测试用
reg [55:0] state_name; //1个字符8位宽
always @(*) begin
case(state)
IDLE : state_name = "IDLE";
ARBIT : state_name = "ARBIT";
WR : state_name = "WR";
RD_ADDR : state_name = "RD_ADDR";
RD_WAIT : state_name = "RD_WAIT";
default : state_name = "IDLE";
endcase
end
//==========================================================================
//== 在进入读状态前锁存读突发长度
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
wr_len <= 'h0;
end
else if(state == ARBIT && burst_wr_req) begin
wr_len <= burst_wr_len;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
rd_len <= 'h0;
end
else if(state == ARBIT && burst_rd_req) begin
rd_len <= burst_rd_len;
end
end
//==========================================================================
//== 写突发的数据计数:0101010101
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
wr_burst_cnt <= 'h0;
end
else if(state == WR && local_ready) begin
if(wr_burst_cnt >= WR_SIZE - 1)
wr_burst_cnt <= 'h0;
else
wr_burst_cnt <= wr_burst_cnt + 'h1;
end
end
//==========================================================================
//== 每凑齐2个数据则地址+2
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
wr_addr_cnt <= 'h0;
end
else if(state == WR && local_ready) begin
if(wr_addr_cnt + wr_burst_cnt >= wr_len - 1)
wr_addr_cnt <= 'h0;
else if(wr_burst_cnt >= WR_SIZE - 1)
wr_addr_cnt <= wr_addr_cnt + WR_SIZE;
end
end
//==========================================================================
//== 每给出读指令时读地址+2
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
rd_addr_cnt <= 'h0;
end
else if(state == RD_ADDR && local_ready) begin
if(rd_addr_cnt >= rd_len - RD_SIZE)
rd_addr_cnt <= 'h0;
else
rd_addr_cnt <= rd_addr_cnt + RD_SIZE;
end
end
//==========================================================================
//== 每读出一个数据地址递+1
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
rd_data_cnt <= 'h0;
end
else if(local_rdata_valid) begin
if(rd_data_cnt >= rd_len - 1)
rd_data_cnt <= 'h0;
else
rd_data_cnt <= rd_data_cnt + 'h1;
end
end
//==========================================================================
//== 锁存local_size并在最后一次读写时如果不足突发大小则更改local_size为不足的大小
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
local_size <= 'h0;
end
else if(state == ARBIT && burst_wr_req) begin
local_size <= (burst_wr_len >= WR_SIZE) ? WR_SIZE : burst_wr_len;
end
else if(state == ARBIT && burst_rd_req) begin
local_size <= (burst_rd_len >= RD_SIZE) ? RD_SIZE : burst_rd_len;
end
else if(state == WR && wr_burst_cnt == WR_SIZE - 1 && wr_addr_cnt + {WR_SIZE,1'b0} > wr_len && local_ready) begin
local_size <= wr_len - wr_addr_cnt - WR_SIZE;
end
else if(state == RD_ADDR && rd_addr_cnt + {RD_SIZE,1'b0} > rd_len && local_ready) begin
local_size <= rd_len - rd_addr_cnt - RD_SIZE;
end
end
//==========================================================================
//== 锁存local_address,并且在完成一次突发读写时递增读写地址
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
local_address <= 'h0;
end
else if(state == ARBIT && burst_wr_req) begin
local_address <= burst_wr_addr;
end
else if(state == ARBIT && burst_rd_req) begin
local_address <= burst_rd_addr;
end
else if(state == WR && (wr_burst_cnt == WR_SIZE - 1) && local_ready) begin
local_address <= local_address + WR_SIZE;
end
else if(state == RD_ADDR && local_ready) begin
local_address <= local_address + RD_SIZE;
end
end
//==========================================================================
//== 其他信号
//==========================================================================
//burstbegin信号,随便怎么写都行,直接赋值1'b1也能跑
assign local_burstbegin = (state == WR || state == RD_ADDR) ? 1'b1 : 1'b0;
//写数据
assign local_wdata = burst_wr_data;
//写应答,即写FIFO的读使能
assign burst_wr_ack = (state == WR && local_ready) ? 1'b1 : 1'b0;
//读数据
assign burst_rd_data = local_rdata;
//读应答,即读FIFO的写使能
assign burst_rd_ack = local_rdata_valid;
//写请求
assign local_write_req = (state == WR) ? 1'b1 : 1'b0;
//读请求
assign local_read_req = (state == RD_ADDR) ? 1'b1 : 1'b0;
endmodule
2、DDR2_8port v2
(1) inst
inst
//==========================================================================
//== DDR2_8port
//==========================================================================
DDR2_8port u_DDR2_8port
(
//时钟和复位 ------------------------------------
.pll_ref_clk (clk_100m ), //DDR2输入时钟
.global_reset_n (sys_rst_n ), //全局复位信号
//DDR2端口 --------------------------------------
.mem_odt (mem_odt ), //DDR2片上终结信号
.mem_cs_n (mem_cs_n ), //DDR2片选信号
.mem_cke (mem_cke ), //DDR2时钟使能信号
.mem_addr (mem_addr ), //DDR2地址总线
.mem_ba (mem_ba ), //DDR2BANK信号
.mem_ras_n (mem_ras_n ), //DDR2行地址选择信号
.mem_cas_n (mem_cas_n ), //DDR2列地址选择信号
.mem_we_n (mem_we_n ), //DDR2写使能信号
.mem_dm (mem_dm ), //DDR2数据掩膜信号
.mem_clk (mem_clk ), //DDR2时钟信号
.mem_clk_n (mem_clk_n ), //DDR2时钟反相信号
.mem_dq (mem_dq ), //DDR2数据总线
.mem_dqs (mem_dqs ), //DDR2数据源同步信号
//DDR2控制 --------------------------------------
.DDR2_init_done ( ), //DDR2 IP核初始化信号
.DDR2_phy_clk ( ), //DDR2 IP核输出时钟
.DDR2_phy_rst_n ( ), //DDR2 IP核输出的同步复位信号
//通道0 -----------------------------------------
.ch0_addr (3'h0 ), //通道0地址
.ch0_width (CH_WIDTH ), //通道0宽度
.ch0_height (CH_HEIGHT ), //通道0高度
.ch0_wr_clk (ch0_clk ), //通道0写时钟
.ch0_wr_data (ch0_data ), //通道0输入数据
.ch0_wr_vld (ch0_vld ), //通道0输入数据有效信号
.ch0_wr_vsync (ch0_vsync ), //通道0场信号(写)
.ch0_wr_en (1'b1 ), //通道0写使能
.ch0_rd_clk (clk_VGA ), //通道0读时钟
.ch0_rd_data (ch0_VGA_din ), //通道0输出数据
.ch0_rd_req (ch0_VGA_req ), //通道0输出请求
.ch0_rd_vsync (VGA_vsync ), //通道0场信号(读)
.ch0_rd_en (1'b1 ), //通道0读使能
//通道1 -----------------------------------------
.ch1_addr (3'h1 ), //通道1地址
.ch1_width (CH_WIDTH ), //通道1宽度
.ch1_height (CH_HEIGHT ), //通道1高度
.ch1_wr_clk (ch1_clk ), //通道1写时钟
.ch1_wr_data (ch1_data ), //通道1输入数据
.ch1_wr_vld (ch1_vld ), //通道1输入数据有效信号
.ch1_wr_vsync (ch1_vsync ), //通道1场信号(写)
.ch1_wr_en (1'b1 ), //通道1写使能
.ch1_rd_clk (clk_VGA ), //通道1读时钟
.ch1_rd_data (ch1_VGA_din ), //通道1输出数据
.ch1_rd_req (ch1_VGA_req ), //通道1输出请求
.ch1_rd_vsync (VGA_vsync ), //通道1场信号(读)
.ch1_rd_en (1'b1 ), //通道1读使能
//通道2 -----------------------------------------
.ch2_addr (3'h2 ), //通道2地址
.ch2_width (CH_WIDTH ), //通道2宽度
.ch2_height (CH_HEIGHT ), //通道2高度
.ch2_wr_clk (ch2_clk ), //通道2写时钟
.ch2_wr_data (ch2_data ), //通道2输入数据
.ch2_wr_vld (ch2_vld ), //通道2输入数据有效信号
.ch2_wr_vsync (ch2_vsync ), //通道2场信号(写)
.ch2_wr_en (1'b1 ), //通道2写使能
.ch2_rd_clk (clk_VGA ), //通道2读时钟
.ch2_rd_data (ch2_VGA_din ), //通道2输出数据
.ch2_rd_req (ch2_VGA_req ), //通道2输出请求
.ch2_rd_vsync (VGA_vsync ), //通道2场信号(读)
.ch2_rd_en (1'b1 ), //通道2读使能
//通道3 -----------------------------------------
.ch3_addr (3'h3 ), //通道3地址
.ch3_width (CH_WIDTH ), //通道3宽度
.ch3_height (CH_HEIGHT ), //通道3高度
.ch3_wr_clk (ch3_clk ), //通道3写时钟
.ch3_wr_data (ch3_data ), //通道3输入数据
.ch3_wr_vld (ch3_vld ), //通道3输入数据有效信号
.ch3_wr_vsync (ch3_vsync ), //通道3场信号(写)
.ch3_wr_en (1'b1 ), //通道3写使能
.ch3_rd_clk (clk_VGA ), //通道3读时钟
.ch3_rd_data (ch3_VGA_din ), //通道3输出数据
.ch3_rd_req (ch3_VGA_req ), //通道3输出请求
.ch3_rd_vsync (VGA_vsync ), //通道3场信号(读)
.ch3_rd_en (1'b1 ), //通道3读使能
//通道4 -----------------------------------------
.ch4_addr (3'h4 ), //通道4地址
.ch4_width (CH_WIDTH ), //通道4宽度
.ch4_height (CH_HEIGHT ), //通道4高度
.ch4_wr_clk (ch4_clk ), //通道4写时钟
.ch4_wr_data (ch4_data ), //通道4输入数据
.ch4_wr_vld (ch4_vld ), //通道4输入数据有效信号
.ch4_wr_vsync (ch4_vsync ), //通道4场信号(写)
.ch4_wr_en (1'b1 ), //通道4写使能
.ch4_rd_clk (clk_VGA ), //通道4读时钟
.ch4_rd_data (ch4_VGA_din ), //通道4输出数据
.ch4_rd_req (ch4_VGA_req ), //通道4输出请求
.ch4_rd_vsync (VGA_vsync ), //通道4场信号(读)
.ch4_rd_en (1'b1 ), //通道4读使能
//通道5 -----------------------------------------
.ch5_addr (3'h5 ), //通道5地址
.ch5_width (CH_WIDTH ), //通道5宽度
.ch5_height (CH_HEIGHT ), //通道5高度
.ch5_wr_clk (ch5_clk ), //通道5写时钟
.ch5_wr_data (ch5_data ), //通道5输入数据
.ch5_wr_vld (ch5_vld ), //通道5输入数据有效信号
.ch5_wr_vsync (ch5_vsync ), //通道5场信号(写)
.ch5_wr_en (1'b1 ), //通道5写使能
.ch5_rd_clk (clk_VGA ), //通道5读时钟
.ch5_rd_data (ch5_VGA_din ), //通道5输出数据
.ch5_rd_req (ch5_VGA_req ), //通道5输出请求
.ch5_rd_vsync (VGA_vsync ), //通道5场信号(读)
.ch5_rd_en (1'b1 ), //通道5读使能
//通道6 -----------------------------------------
.ch6_addr (3'h6 ), //通道6地址
.ch6_width (CH_WIDTH ), //通道6宽度
.ch6_height (CH_HEIGHT ), //通道6高度
.ch6_wr_clk (ch6_clk ), //通道6写时钟
.ch6_wr_data (ch6_data ), //通道6输入数据
.ch6_wr_vld (ch6_vld ), //通道6输入数据有效信号
.ch6_wr_vsync (ch6_vsync ), //通道6场信号(写)
.ch6_wr_en (1'b1 ), //通道6写使能
.ch6_rd_clk (clk_VGA ), //通道6读时钟
.ch6_rd_data (ch6_VGA_din ), //通道6输出数据
.ch6_rd_req (ch6_VGA_req ), //通道6输出请求
.ch6_rd_vsync (VGA_vsync ), //通道6场信号(读)
.ch6_rd_en (1'b1 ), //通道6读使能
//通道7 -----------------------------------------
.ch7_addr (3'h7 ), //通道7地址
.ch7_width (CH_WIDTH ), //通道7宽度
.ch7_height (CH_HEIGHT ), //通道7高度
.ch7_wr_clk (ch7_clk ), //通道7写时钟
.ch7_wr_data (ch7_data ), //通道7输入数据
.ch7_wr_vld (ch7_vld ), //通道7输入数据有效信号
.ch7_wr_vsync (ch7_vsync ), //通道7场信号(写)
.ch7_wr_en (1'b1 ), //通道7写使能
.ch7_rd_clk (clk_VGA ), //通道7读时钟
.ch7_rd_data (ch7_VGA_din ), //通道7输出数据
.ch7_rd_req (ch7_VGA_req ), //通道7输出请求
.ch7_rd_vsync (VGA_vsync ), //通道7场信号(读)
.ch7_rd_en (1'b1 ) //通道7读使能
);
(2) DDR2_port
DDR2_8port
`include "DDR2_param.v"
//**************************************************************************
// *** 名称 : DDR2_8port.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2020年6月
// *** 描述 : 多通道视频读写突发的控制模块,每个通道都可以选择是否使用,
// 行地址有10位,列地址有10位,wrFIFO深度1024,rdFIFO深度256,
// 位宽为64,综合考虑后,单通道最大支持1024x1024.
//**************************************************************************
module DDR2_8port
//============================< 端口 >======================================
(
//时钟和复位 ----------------------------------------
input pll_ref_clk , //DDR2输入时钟
input global_reset_n , //全局复位信号
//DDR2端口 ------------------------------------------
output mem_odt , //DDR2片上终结信号
output mem_cs_n , //DDR2片选信号
output mem_cke , //DDR2时钟使能信号
output [`MEM_ADDR_W -1:0] mem_addr , //DDR2地址总线
output [`MEM_BANK_W -1:0] mem_ba , //DDR2BANK信号
output mem_ras_n , //DDR2行地址选择信号
output mem_cas_n , //DDR2列地址选择信号
output mem_we_n , //DDR2写使能信号
output [`MEM_DM_W -1:0] mem_dm , //DDR2数据掩膜信号
inout mem_clk , //DDR2时钟信号
inout mem_clk_n , //DDR2时钟反相信号
inout [`MEM_DQ_W -1:0] mem_dq , //DDR2数据总线
inout [`MEM_DQS_W -1:0] mem_dqs , //DDR2数据源同步信号
//DDR2控制 ------------------------------------------
output DDR2_init_done , //DDR2 IP核初始化信号
output DDR2_phy_clk , //DDR2 IP核输出时钟
output DDR2_phy_rst_n , //DDR2 IP核输出的同步复位信号
//通道0 ---------------------------------------------
input [ 2:0] ch0_addr , //通道0地址
input [15:0] ch0_width , //通道0宽度
input [15:0] ch0_height , //通道0高度
input ch0_wr_clk , //通道0写时钟
input [15:0] ch0_wr_data , //通道0输入数据
input ch0_wr_vld , //通道0输入数据有效信号
input ch0_wr_vsync , //通道0场信号(写)
input ch0_wr_en , //通道0写使能
input ch0_rd_clk , //通道0读时钟
output [15:0] ch0_rd_data , //通道0输出数据
input ch0_rd_req , //通道0输出请求
input ch0_rd_vsync , //通道0场信号(读)
input ch0_rd_en , //通道0读使能
//通道1 ---------------------------------------------
input [ 2:0] ch1_addr , //通道1地址
input [15:0] ch1_width , //通道1宽度
input [15:0] ch1_height , //通道1高度
input ch1_wr_clk , //通道1写时钟
input [15:0] ch1_wr_data , //通道1输入数据
input ch1_wr_vld , //通道1输入数据有效信号
input ch1_wr_vsync , //通道1场信号(写)
input ch1_wr_en , //通道1写使能
input ch1_rd_clk , //通道1读时钟
output [15:0] ch1_rd_data , //通道1输出数据
input ch1_rd_req , //通道1输出请求
input ch1_rd_vsync , //通道1场信号(读)
input ch1_rd_en , //通道1读使能
//通道2 ---------------------------------------------
input [ 2:0] ch2_addr , //通道2地址
input [15:0] ch2_width , //通道2宽度
input [15:0] ch2_height , //通道2高度
input ch2_wr_clk , //通道2写时钟
input [15:0] ch2_wr_data , //通道2输入数据
input ch2_wr_vld , //通道2输入数据有效信号
input ch2_wr_vsync , //通道2场信号(写)
input ch2_wr_en , //通道2写使能
input ch2_rd_clk , //通道2读时钟
output [15:0] ch2_rd_data , //通道2输出数据
input ch2_rd_req , //通道2输出请求
input ch2_rd_vsync , //通道2场信号(读)
input ch2_rd_en , //通道2读使能
//通道3 ---------------------------------------------
input [ 2:0] ch3_addr , //通道3地址
input [15:0] ch3_width , //通道3宽度
input [15:0] ch3_height , //通道3高度
input ch3_wr_clk , //通道3写时钟
input [15:0] ch3_wr_data , //通道3输入数据
input ch3_wr_vld , //通道3输入数据有效信号
input ch3_wr_vsync , //通道3场信号(写)
input ch3_wr_en , //通道3写使能
input ch3_rd_clk , //通道3读时钟
output [15:0] ch3_rd_data , //通道3输出数据
input ch3_rd_req , //通道3输出请求
input ch3_rd_vsync , //通道3场信号(读)
input ch3_rd_en , //通道3读使能
//通道4 ---------------------------------------------
input [ 2:0] ch4_addr , //通道4地址
input [15:0] ch4_width , //通道4宽度
input [15:0] ch4_height , //通道4高度
input ch4_wr_clk , //通道4写时钟
input [15:0] ch4_wr_data , //通道4输入数据
input ch4_wr_vld , //通道4输入数据有效信号
input ch4_wr_vsync , //通道4场信号(写)
input ch4_wr_en , //通道4写使能
input ch4_rd_clk , //通道4读时钟
output [15:0] ch4_rd_data , //通道4输出数据
input ch4_rd_req , //通道4输出请求
input ch4_rd_vsync , //通道4场信号(读)
input ch4_rd_en , //通道4读使能
//通道5 ---------------------------------------------
input [ 2:0] ch5_addr , //通道5地址
input [15:0] ch5_width , //通道5宽度
input [15:0] ch5_height , //通道5高度
input ch5_wr_clk , //通道5写时钟
input [15:0] ch5_wr_data , //通道5输入数据
input ch5_wr_vld , //通道5输入数据有效信号
input ch5_wr_vsync , //通道5场信号(写)
input ch5_wr_en , //通道5写使能
input ch5_rd_clk , //通道5读时钟
output [15:0] ch5_rd_data , //通道5输出数据
input ch5_rd_req , //通道5输出请求
input ch5_rd_vsync , //通道5场信号(读)
input ch5_rd_en , //通道5读使能
//通道6 ---------------------------------------------
input [ 2:0] ch6_addr , //通道6地址
input [15:0] ch6_width , //通道6宽度
input [15:0] ch6_height , //通道6高度
input ch6_wr_clk , //通道6写时钟
input [15:0] ch6_wr_data , //通道6输入数据
input ch6_wr_vld , //通道6输入数据有效信号
input ch6_wr_vsync , //通道6场信号(写)
input ch6_wr_en , //通道6写使能
input ch6_rd_clk , //通道6读时钟
output [15:0] ch6_rd_data , //通道6输出数据
input ch6_rd_req , //通道6输出请求
input ch6_rd_vsync , //通道6场信号(读)
input ch6_rd_en , //通道6读使能
//通道7 ---------------------------------------------
input [ 2:0] ch7_addr , //通道7地址
input [15:0] ch7_width , //通道7宽度
input [15:0] ch7_height , //通道7高度
input ch7_wr_clk , //通道7写时钟
input [15:0] ch7_wr_data , //通道7输入数据
input ch7_wr_vld , //通道7输入数据有效信号
input ch7_wr_vsync , //通道7场信号(写)
input ch7_wr_en , //通道7写使能
input ch7_rd_clk , //通道7读时钟
output [15:0] ch7_rd_data , //通道7输出数据
input ch7_rd_req , //通道7输出请求
input ch7_rd_vsync , //通道7场信号(读)
input ch7_rd_en //通道7读使能
);
//============================< 信号 >======================================
wire [13:0] burst_len ; //读写突发长度
wire [`LOCAL_DATA_W -1:0] burst_rddata ; //读突发数据
wire [`LOCAL_DATA_W -1:0] burst_wrdata ; //写突发数据
wire burst_rdack ; //读突发应答信号
wire burst_wrack ; //写突发应答信号
wire burst_rddone ; //突发读完成信号
wire burst_wrdone ; //突发写完成信号
//---------------------------------------------------
wire phy_clk ; //DDR2 IP核工作时钟
wire reset_phy_clk_n ; //DDR2 IP核同步后的复位信号
wire local_init_done ; //DDR2 IP核初始化完成信号
wire rst_n ; //本模块使用的复位信号
//---------------------------------------------------
reg ch0_wr_vsync_r ; //通道0场信号打一拍
reg ch0_wr_rst ; //通道0场复位信号
reg ch1_wr_vsync_r ; //通道1场信号打一拍
reg ch1_wr_rst ; //通道1场复位信号
reg ch2_wr_vsync_r ; //通道2场信号打一拍
reg ch2_wr_rst ; //通道2场复位信号
reg ch3_wr_vsync_r ; //通道3场信号打一拍
reg ch3_wr_rst ; //通道3场复位信号
reg ch4_wr_vsync_r ; //通道4场信号打一拍
reg ch4_wr_rst ; //通道4场复位信号
reg ch5_wr_vsync_r ; //通道5场信号打一拍
reg ch5_wr_rst ; //通道5场复位信号
reg ch6_wr_vsync_r ; //通道6场信号打一拍
reg ch6_wr_rst ; //通道6场复位信号
reg ch7_wr_vsync_r ; //通道7场信号打一拍
reg ch7_wr_rst ; //通道7场复位信号
//---------------------------------------------------
reg ch0_rd_vsync_r ; //通道0场信号打一拍
reg ch0_rd_rst ; //通道0场复位信号
reg ch1_rd_vsync_r ; //通道1场信号打一拍
reg ch1_rd_rst ; //通道1场复位信号
reg ch2_rd_vsync_r ; //通道2场信号打一拍
reg ch2_rd_rst ; //通道2场复位信号
reg ch3_rd_vsync_r ; //通道3场信号打一拍
reg ch3_rd_rst ; //通道3场复位信号
reg ch4_rd_vsync_r ; //通道4场信号打一拍
reg ch4_rd_rst ; //通道4场复位信号
reg ch5_rd_vsync_r ; //通道5场信号打一拍
reg ch5_rd_rst ; //通道5场复位信号
reg ch6_rd_vsync_r ; //通道6场信号打一拍
reg ch6_rd_rst ; //通道6场复位信号
reg ch7_rd_vsync_r ; //通道7场信号打一拍
reg ch7_rd_rst ; //通道7场复位信号
//---------------------------------------------------
wire [`LOCAL_DATA_W -1:0] ch0_wrFIFO_q ; //通道0读数据
wire [`LOCAL_DATA_W -1:0] ch1_wrFIFO_q ; //通道1读数据
wire [`LOCAL_DATA_W -1:0] ch2_wrFIFO_q ; //通道2读数据
wire [`LOCAL_DATA_W -1:0] ch3_wrFIFO_q ; //通道3读数据
wire [`LOCAL_DATA_W -1:0] ch4_wrFIFO_q ; //通道4读数据
wire [`LOCAL_DATA_W -1:0] ch5_wrFIFO_q ; //通道5读数据
wire [`LOCAL_DATA_W -1:0] ch6_wrFIFO_q ; //通道6读数据
wire [`LOCAL_DATA_W -1:0] ch7_wrFIFO_q ; //通道7读数据
wire [ 8:0] ch0_wrFIFO_rdusedw ; //通道0写FIFO剩余数据个数
wire [ 8:0] ch1_wrFIFO_rdusedw ; //通道1写FIFO剩余数据个数
wire [ 8:0] ch2_wrFIFO_rdusedw ; //通道2写FIFO剩余数据个数
wire [ 8:0] ch3_wrFIFO_rdusedw ; //通道3写FIFO剩余数据个数
wire [ 8:0] ch4_wrFIFO_rdusedw ; //通道4写FIFO剩余数据个数
wire [ 8:0] ch5_wrFIFO_rdusedw ; //通道5写FIFO剩余数据个数
wire [ 8:0] ch6_wrFIFO_rdusedw ; //通道6写FIFO剩余数据个数
wire [ 8:0] ch7_wrFIFO_rdusedw ; //通道7写FIFO剩余数据个数
wire [ 8:0] ch0_rdFIFO_wrusedw ; //通道0读FIFO剩余数据个数
wire [ 8:0] ch1_rdFIFO_wrusedw ; //通道1读FIFO剩余数据个数
wire [ 8:0] ch2_rdFIFO_wrusedw ; //通道2读FIFO剩余数据个数
wire [ 8:0] ch3_rdFIFO_wrusedw ; //通道3读FIFO剩余数据个数
wire [ 8:0] ch4_rdFIFO_wrusedw ; //通道4读FIFO剩余数据个数
wire [ 8:0] ch5_rdFIFO_wrusedw ; //通道5读FIFO剩余数据个数
wire [ 8:0] ch6_rdFIFO_wrusedw ; //通道6读FIFO剩余数据个数
wire [ 8:0] ch7_rdFIFO_wrusedw ; //通道7读FIFO剩余数据个数
//---------------------------------------------------
reg [ 3:0] fsm_cs ; //状态机的当前状态
reg [ 3:0] fsm_ns ; //状态机的下一个状态
//---------------------------------------------------
reg [ 2:0] wrchannel ; //写通道
reg [ 2:0] rdchannel ; //读通道
//---------------------------------------------------
reg [15:0] ch0_wr_vcnt ; //通道0写行计数
reg [15:0] ch1_wr_vcnt ; //通道1写行计数
reg [15:0] ch2_wr_vcnt ; //通道2写行计数
reg [15:0] ch3_wr_vcnt ; //通道3写行计数
reg [15:0] ch4_wr_vcnt ; //通道4写行计数
reg [15:0] ch5_wr_vcnt ; //通道5写行计数
reg [15:0] ch6_wr_vcnt ; //通道6写行计数
reg [15:0] ch7_wr_vcnt ; //通道7写行计数
reg [15:0] ch0_rd_vcnt ; //通道0读行计数
reg [15:0] ch1_rd_vcnt ; //通道1读行计数
reg [15:0] ch2_rd_vcnt ; //通道2读行计数
reg [15:0] ch3_rd_vcnt ; //通道3读行计数
reg [15:0] ch4_rd_vcnt ; //通道4读行计数
reg [15:0] ch5_rd_vcnt ; //通道5读行计数
reg [15:0] ch6_rd_vcnt ; //通道6读行计数
reg [15:0] ch7_rd_vcnt ; //通道7读行计数
reg [`LOCAL_ADDR_W -1:0] burst_wraddr ; //写突发地址
reg [`LOCAL_ADDR_W -1:0] burst_rdaddr ; //读突发地址
//---------------------------------------------------
reg burst_wrreq ; //突发写请求
reg burst_rdreq ; //突发读请求
//---------------------------------------------------
reg [ 1:0] ch0_wraddr_msb ; //通道0乒乓操作写分区
reg [ 1:0] ch0_rdaddr_msb ; //通道0乒乓操作读分区
reg [ 1:0] ch1_wraddr_msb ; //通道1乒乓操作写分区
reg [ 1:0] ch1_rdaddr_msb ; //通道1乒乓操作读分区
reg [ 1:0] ch2_wraddr_msb ; //通道2乒乓操作写分区
reg [ 1:0] ch2_rdaddr_msb ; //通道2乒乓操作读分区
reg [ 1:0] ch3_wraddr_msb ; //通道3乒乓操作写分区
reg [ 1:0] ch3_rdaddr_msb ; //通道3乒乓操作读分区
reg [ 1:0] ch4_wraddr_msb ; //通道4乒乓操作写分区
reg [ 1:0] ch4_rdaddr_msb ; //通道4乒乓操作读分区
reg [ 1:0] ch5_wraddr_msb ; //通道5乒乓操作写分区
reg [ 1:0] ch5_rdaddr_msb ; //通道5乒乓操作读分区
reg [ 1:0] ch6_wraddr_msb ; //通道6乒乓操作写分区
reg [ 1:0] ch6_rdaddr_msb ; //通道6乒乓操作读分区
reg [ 1:0] ch7_wraddr_msb ; //通道7乒乓操作写分区
reg [ 1:0] ch7_rdaddr_msb ; //通道7乒乓操作读分区
//============================< 参数 >======================================
parameter FSM_IDLE = 4'h0 ; //空闲状态
parameter FSM_ARBIT = 4'h1 ; //仲裁状态
parameter FSM_WRITE = 4'h2 ; //写状态
parameter FSM_WREND = 4'h3 ; //写完成状态
parameter FSM_READ = 4'h4 ; //读状态
parameter FSM_RDEND = 4'h5 ; //读完成状态
//==========================================================================
//== DDR2突发读写模块,实现一段长度的突发读写
//==========================================================================
DDR2_burst u_DDR2_burst
(
//IP核引出接口 ----------------------------------
.pll_ref_clk (pll_ref_clk ), //DDR2 参考时钟
.global_reset_n (global_reset_n ), //全局复位信号,连接外部复位
.phy_clk (phy_clk ), //DDR2 IP核工作时钟
.reset_phy_clk_n (reset_phy_clk_n ), //DDR2 IP核同步后的复位信号
.local_init_done (local_init_done ), //DDR2 IP核初始化完成信号
//突发读写接口 ----------------------------------
.burst_rdreq (burst_rdreq ), //突发读请求
.burst_wrreq (burst_wrreq ), //突发写请求
.burst_rdlen (burst_len ), //突发读长度
.burst_wrlen (burst_len ), //突发写长度
.burst_rdaddr (burst_rdaddr ), //突发读地址
.burst_wraddr (burst_wraddr ), //突发写地址
.burst_rddata (burst_rddata ), //突发读数据
.burst_wrdata (burst_wrdata ), //突发写数据
.burst_rdack (burst_rdack ), //突发读应答,连接FIFO
.burst_wrack (burst_wrack ), //突发写应答,连接FIFO
.burst_rddone (burst_rddone ), //突发读完成信号
.burst_wrdone (burst_wrdone ), //突发写完成信号
//芯片接口 --------------------------------------
.mem_odt (mem_odt ), //DDR2片上终结信号
.mem_cs_n (mem_cs_n ), //DDR2片选信号
.mem_cke (mem_cke ), //DDR2时钟使能信号
.mem_addr (mem_addr ), //DDR2地址总线
.mem_ba (mem_ba ), //DDR2bank信号
.mem_ras_n (mem_ras_n ), //DDR2行地址选择信号
.mem_cas_n (mem_cas_n ), //DDR2列地址选择信号
.mem_we_n (mem_we_n ), //DDR2写使能信号
.mem_dm (mem_dm ), //DDR2数据掩膜信号
.mem_clk (mem_clk ), //DDR2时钟信号
.mem_clk_n (mem_clk_n ), //DDR2时钟反相信号
.mem_dq (mem_dq ), //DDR2数据总线
.mem_dqs (mem_dqs ) //DDR2数据源同步信号
);
//==========================================================================
//== 简单信号
//==========================================================================
//读写突发长度,16和64互转,长度/4
assign burst_len = ch0_width[15:2];
//DDR2初始化完成信号
assign DDR2_init_done = local_init_done;
//DDR2输出时钟信号
assign DDR2_phy_clk = phy_clk;
//DDR2复位信号
assign DDR2_phy_rst_n = reset_phy_clk_n;
//本模块复合复位信号
assign rst_n = reset_phy_clk_n && local_init_done;
//==========================================================================
//== 利用写侧场同步信号设计写FIFO的异步复位
//==========================================================================
//通道0
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch0_wr_vsync_r <= 1'h0;
end
else begin
ch0_wr_vsync_r <= ch0_wr_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch0_wr_rst <= 1'h0;
end
else if(!ch0_wr_vsync_r && ch0_wr_vsync) begin
ch0_wr_rst <= 1'b1;
end
else begin
ch0_wr_rst <= 1'b0;
end
end
//通道1
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch1_wr_vsync_r <= 1'h0;
end
else begin
ch1_wr_vsync_r <= ch1_wr_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch1_wr_rst <= 1'h0;
end
else if(!ch1_wr_vsync_r && ch1_wr_vsync) begin
ch1_wr_rst <= 1'b1;
end
else begin
ch1_wr_rst <= 1'b0;
end
end
//通道2
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch2_wr_vsync_r <= 1'h0;
end
else begin
ch2_wr_vsync_r <= ch2_wr_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch2_wr_rst <= 1'h0;
end
else if(!ch2_wr_vsync_r && ch2_wr_vsync) begin
ch2_wr_rst <= 1'b1;
end
else begin
ch2_wr_rst <= 1'b0;
end
end
//通道3
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch3_wr_vsync_r <= 1'h0;
end
else begin
ch3_wr_vsync_r <= ch3_wr_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch3_wr_rst <= 1'h0;
end
else if(!ch3_wr_vsync_r && ch3_wr_vsync) begin
ch3_wr_rst <= 1'b1;
end
else begin
ch3_wr_rst <= 1'b0;
end
end
//通道4
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch4_wr_vsync_r <= 1'h0;
end
else begin
ch4_wr_vsync_r <= ch4_wr_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch4_wr_rst <= 1'h0;
end
else if(!ch4_wr_vsync_r && ch4_wr_vsync) begin
ch4_wr_rst <= 1'b1;
end
else begin
ch4_wr_rst <= 1'b0;
end
end
//通道5
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch5_wr_vsync_r <= 1'h0;
end
else begin
ch5_wr_vsync_r <= ch5_wr_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch5_wr_rst <= 1'h0;
end
else if(!ch5_wr_vsync_r && ch5_wr_vsync) begin
ch5_wr_rst <= 1'b1;
end
else begin
ch5_wr_rst <= 1'b0;
end
end
//通道6
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch6_wr_vsync_r <= 1'h0;
end
else begin
ch6_wr_vsync_r <= ch6_wr_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch6_wr_rst <= 1'h0;
end
else if(!ch6_wr_vsync_r && ch6_wr_vsync) begin
ch6_wr_rst <= 1'b1;
end
else begin
ch6_wr_rst <= 1'b0;
end
end
//通道7
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch7_wr_vsync_r <= 1'h0;
end
else begin
ch7_wr_vsync_r <= ch7_wr_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch7_wr_rst <= 1'h0;
end
else if(!ch7_wr_vsync_r && ch7_wr_vsync) begin
ch7_wr_rst <= 1'b1;
end
else begin
ch7_wr_rst <= 1'b0;
end
end
//==========================================================================
//== 利用读侧场同步信号设计读FIFO的异步复位
//==========================================================================
//通道0
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch0_rd_vsync_r <= 1'h0;
end
else begin
ch0_rd_vsync_r <= ch0_rd_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch0_rd_rst <= 1'h0;
end
else if(!ch0_rd_vsync_r && ch0_rd_vsync) begin
ch0_rd_rst <= 1'b1;
end
else begin
ch0_rd_rst <= 1'b0;
end
end
//通道1
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch1_rd_vsync_r <= 1'h0;
end
else begin
ch1_rd_vsync_r <= ch1_rd_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch1_rd_rst <= 1'h0;
end
else if(!ch1_rd_vsync_r && ch1_rd_vsync) begin
ch1_rd_rst <= 1'b1;
end
else begin
ch1_rd_rst <= 1'b0;
end
end
//通道2
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch2_rd_vsync_r <= 1'h0;
end
else begin
ch2_rd_vsync_r <= ch2_rd_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch2_rd_rst <= 1'h0;
end
else if(!ch2_rd_vsync_r && ch2_rd_vsync) begin
ch2_rd_rst <= 1'b1;
end
else begin
ch2_rd_rst <= 1'b0;
end
end
//通道3
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch3_rd_vsync_r <= 1'h0;
end
else begin
ch3_rd_vsync_r <= ch3_rd_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch3_rd_rst <= 1'h0;
end
else if(!ch3_rd_vsync_r && ch3_rd_vsync) begin
ch3_rd_rst <= 1'b1;
end
else begin
ch3_rd_rst <= 1'b0;
end
end
//通道4
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch4_rd_vsync_r <= 1'h0;
end
else begin
ch4_rd_vsync_r <= ch4_rd_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch4_rd_rst <= 1'h0;
end
else if(!ch4_rd_vsync_r && ch4_rd_vsync) begin
ch4_rd_rst <= 1'b1;
end
else begin
ch4_rd_rst <= 1'b0;
end
end
//通道5
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch5_rd_vsync_r <= 1'h0;
end
else begin
ch5_rd_vsync_r <= ch5_rd_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch5_rd_rst <= 1'h0;
end
else if(!ch5_rd_vsync_r && ch5_rd_vsync) begin
ch5_rd_rst <= 1'b1;
end
else begin
ch5_rd_rst <= 1'b0;
end
end
//通道6
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch6_rd_vsync_r <= 1'h0;
end
else begin
ch6_rd_vsync_r <= ch6_rd_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch6_rd_rst <= 1'h0;
end
else if(!ch6_rd_vsync_r && ch6_rd_vsync) begin
ch6_rd_rst <= 1'b1;
end
else begin
ch6_rd_rst <= 1'b0;
end
end
//通道7
//---------------------------------------------------
//打拍
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch7_rd_vsync_r <= 1'h0;
end
else begin
ch7_rd_vsync_r <= ch7_rd_vsync;
end
end
//场起始信号当作场复位信号,高有效
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch7_rd_rst <= 1'h0;
end
else if(!ch7_rd_vsync_r && ch7_rd_vsync) begin
ch7_rd_rst <= 1'b1;
end
else begin
ch7_rd_rst <= 1'b0;
end
end
//==========================================================================
//== FIFO
//==========================================================================
//写FIFO通道0
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch0
(
.aclr (!rst_n || ch0_wr_rst ),
.data (ch0_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wrack && wrchannel==3'h0 ),
.wrclk (ch0_wr_clk ),
.wrreq (ch0_wr_vld ),
.q (ch0_wrFIFO_q ),
.rdempty ( ),
.rdusedw (ch0_wrFIFO_rdusedw ),
.wrfull ( ),
.wrusedw ( )
);
//写FIFO通道1
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch1
(
.aclr (!rst_n || ch1_wr_rst ),
.data (ch1_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wrack && wrchannel==3'h1 ),
.wrclk (ch1_wr_clk ),
.wrreq (ch1_wr_vld ),
.q (ch1_wrFIFO_q ),
.rdempty ( ),
.rdusedw (ch1_wrFIFO_rdusedw ),
.wrfull ( ),
.wrusedw ( )
);
//写FIFO通道2
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch2
(
.aclr (!rst_n || ch2_wr_rst ),
.data (ch2_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wrack && wrchannel==3'h2 ),
.wrclk (ch2_wr_clk ),
.wrreq (ch2_wr_vld ),
.q (ch2_wrFIFO_q ),
.rdempty ( ),
.rdusedw (ch2_wrFIFO_rdusedw ),
.wrfull ( ),
.wrusedw ( )
);
//写FIFO通道3
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch3
(
.aclr (!rst_n || ch3_wr_rst ),
.data (ch3_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wrack && wrchannel==3'h3 ),
.wrclk (ch3_wr_clk ),
.wrreq (ch3_wr_vld ),
.q (ch3_wrFIFO_q ),
.rdempty ( ),
.rdusedw (ch3_wrFIFO_rdusedw ),
.wrfull ( ),
.wrusedw ( )
);
//写FIFO通道4
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch4
(
.aclr (!rst_n || ch4_wr_rst ),
.data (ch4_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wrack && wrchannel==3'h4 ),
.wrclk (ch4_wr_clk ),
.wrreq (ch4_wr_vld ),
.q (ch4_wrFIFO_q ),
.rdempty ( ),
.rdusedw (ch4_wrFIFO_rdusedw ),
.wrfull ( ),
.wrusedw ( )
);
//写FIFO通道5
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch5
(
.aclr (!rst_n || ch5_wr_rst ),
.data (ch5_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wrack && wrchannel==3'h5 ),
.wrclk (ch5_wr_clk ),
.wrreq (ch5_wr_vld ),
.q (ch5_wrFIFO_q ),
.rdempty ( ),
.rdusedw (ch5_wrFIFO_rdusedw ),
.wrfull ( ),
.wrusedw ( )
);
//写FIFO通道6
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch6
(
.aclr (!rst_n || ch6_wr_rst ),
.data (ch6_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wrack && wrchannel==3'h6 ),
.wrclk (ch6_wr_clk ),
.wrreq (ch6_wr_vld ),
.q (ch6_wrFIFO_q ),
.rdempty ( ),
.rdusedw (ch6_wrFIFO_rdusedw ),
.wrfull ( ),
.wrusedw ( )
);
//写FIFO通道7
//---------------------------------------------------
wrFIFO_wr16_rd64_1024 wrFIFO_ch7
(
.aclr (!rst_n || ch7_wr_rst ),
.data (ch7_wr_data ),
.rdclk (phy_clk ),
.rdreq (burst_wrack && wrchannel==3'h7 ),
.wrclk (ch7_wr_clk ),
.wrreq (ch7_wr_vld ),
.q (ch7_wrFIFO_q ),
.rdempty ( ),
.rdusedw (ch7_wrFIFO_rdusedw ),
.wrfull ( ),
.wrusedw ( )
);
//根据通道选择写入相应FIFO的数据
//---------------------------------------------------
assign burst_wrdata = (wrchannel == 3'h7) ? ch7_wrFIFO_q :
(wrchannel == 3'h6) ? ch6_wrFIFO_q :
(wrchannel == 3'h5) ? ch5_wrFIFO_q :
(wrchannel == 3'h4) ? ch4_wrFIFO_q :
(wrchannel == 3'h3) ? ch3_wrFIFO_q :
(wrchannel == 3'h2) ? ch2_wrFIFO_q :
(wrchannel == 3'h1) ? ch1_wrFIFO_q :
ch0_wrFIFO_q ;
//读FIFO通道0
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch0
(
.aclr (!rst_n || ch0_rd_rst ),
.data (burst_rddata ),
.rdclk (ch0_rd_clk ),
.rdreq (ch0_rd_req ),
.wrclk (phy_clk ),
.wrreq (burst_rdack && rdchannel==3'h0 ),
.q (ch0_rd_data ), //输出到端口
.rdempty ( ),
.rdusedw ( ),
.wrfull ( ),
.wrusedw (ch0_rdFIFO_wrusedw )
);
//读FIFO通道1
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch1
(
.aclr (!rst_n || ch1_rd_rst ),
.data (burst_rddata ),
.rdclk (ch1_rd_clk ),
.rdreq (ch1_rd_req ),
.wrclk (phy_clk ),
.wrreq (burst_rdack && rdchannel==3'h1 ),
.q (ch1_rd_data ), //输出到端口
.rdempty ( ),
.rdusedw ( ),
.wrfull ( ),
.wrusedw (ch1_rdFIFO_wrusedw )
);
//读FIFO通道2
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch2
(
.aclr (!rst_n || ch2_rd_rst ),
.data (burst_rddata ),
.rdclk (ch2_rd_clk ),
.rdreq (ch2_rd_req ),
.wrclk (phy_clk ),
.wrreq (burst_rdack && rdchannel==3'h2 ),
.q (ch2_rd_data ), //输出到端口
.rdempty ( ),
.rdusedw ( ),
.wrfull ( ),
.wrusedw (ch2_rdFIFO_wrusedw )
);
//读FIFO通道3
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch3
(
.aclr (!rst_n || ch3_rd_rst ),
.data (burst_rddata ),
.rdclk (ch3_rd_clk ),
.rdreq (ch3_rd_req ),
.wrclk (phy_clk ),
.wrreq (burst_rdack && rdchannel==3'h3 ),
.q (ch3_rd_data ), //输出到端口
.rdempty ( ),
.rdusedw ( ),
.wrfull ( ),
.wrusedw (ch3_rdFIFO_wrusedw )
);
//读FIFO通道4
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch4
(
.aclr (!rst_n || ch4_rd_rst ),
.data (burst_rddata ),
.rdclk (ch4_rd_clk ),
.rdreq (ch4_rd_req ),
.wrclk (phy_clk ),
.wrreq (burst_rdack && rdchannel==3'h4 ),
.q (ch4_rd_data ), //输出到端口
.rdempty ( ),
.rdusedw ( ),
.wrfull ( ),
.wrusedw (ch4_rdFIFO_wrusedw )
);
//读FIFO通道1
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch5
(
.aclr (!rst_n || ch5_rd_rst ),
.data (burst_rddata ),
.rdclk (ch5_rd_clk ),
.rdreq (ch5_rd_req ),
.wrclk (phy_clk ),
.wrreq (burst_rdack && rdchannel==3'h5 ),
.q (ch5_rd_data ), //输出到端口
.rdempty ( ),
.rdusedw ( ),
.wrfull ( ),
.wrusedw (ch5_rdFIFO_wrusedw )
);
//读FIFO通道6
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch6
(
.aclr (!rst_n || ch6_rd_rst ),
.data (burst_rddata ),
.rdclk (ch6_rd_clk ),
.rdreq (ch6_rd_req ),
.wrclk (phy_clk ),
.wrreq (burst_rdack && rdchannel==3'h6 ),
.q (ch6_rd_data ), //输出到端口
.rdempty ( ),
.rdusedw ( ),
.wrfull ( ),
.wrusedw (ch6_rdFIFO_wrusedw )
);
//读FIFO通道3
//---------------------------------------------------
rdFIFO_wr64_rd16_256 rdFIFO_ch7
(
.aclr (!rst_n || ch7_rd_rst ),
.data (burst_rddata ),
.rdclk (ch7_rd_clk ),
.rdreq (ch7_rd_req ),
.wrclk (phy_clk ),
.wrreq (burst_rdack && rdchannel==3'h7 ),
.q (ch7_rd_data ), //输出到端口
.rdempty ( ),
.rdusedw ( ),
.wrfull ( ),
.wrusedw (ch7_rdFIFO_wrusedw )
);
//==========================================================================
//== 状态机
//==========================================================================
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n)
fsm_cs <= FSM_IDLE;
else
fsm_cs <= fsm_ns;
end
always @ (*) begin
case(fsm_cs)
//--------------------------------------------------- 空闲
FSM_IDLE:
fsm_ns = FSM_ARBIT;
//--------------------------------------------------- 仲裁
FSM_ARBIT:
if((ch0_wr_en && ch0_wrFIFO_rdusedw >= burst_len) || (ch1_wr_en && ch1_wrFIFO_rdusedw >= burst_len) ||
(ch2_wr_en && ch2_wrFIFO_rdusedw >= burst_len) || (ch3_wr_en && ch3_wrFIFO_rdusedw >= burst_len) ||
(ch4_wr_en && ch4_wrFIFO_rdusedw >= burst_len) || (ch5_wr_en && ch5_wrFIFO_rdusedw >= burst_len) ||
(ch6_wr_en && ch6_wrFIFO_rdusedw >= burst_len) || (ch7_wr_en && ch7_wrFIFO_rdusedw >= burst_len))
fsm_ns = FSM_WRITE;
else if((ch0_rd_en && 9'd256 - ch0_rdFIFO_wrusedw >= burst_len) || (ch1_rd_en && 9'd256 - ch1_rdFIFO_wrusedw >= burst_len) ||
(ch2_rd_en && 9'd256 - ch2_rdFIFO_wrusedw >= burst_len) || (ch3_rd_en && 9'd256 - ch3_rdFIFO_wrusedw >= burst_len) ||
(ch4_rd_en && 9'd256 - ch4_rdFIFO_wrusedw >= burst_len) || (ch5_rd_en && 9'd256 - ch5_rdFIFO_wrusedw >= burst_len) ||
(ch6_rd_en && 9'd256 - ch6_rdFIFO_wrusedw >= burst_len) || (ch7_rd_en && 9'd256 - ch7_rdFIFO_wrusedw >= burst_len))
fsm_ns = FSM_READ;
else if(!ch0_wr_en && !ch1_wr_en && !ch2_wr_en && !ch3_wr_en && !ch4_wr_en && !ch5_wr_en && !ch6_wr_en && !ch7_wr_en &&
!ch0_rd_en && !ch1_rd_en && !ch2_rd_en && !ch3_rd_en && !ch4_rd_en && !ch5_rd_en && !ch6_rd_en && !ch7_rd_en)
fsm_ns = FSM_IDLE;
else
fsm_ns = fsm_cs;
//--------------------------------------------------- 写
FSM_WRITE:
if(burst_wrdone)
fsm_ns = FSM_WREND;
else
fsm_ns = fsm_cs;
//--------------------------------------------------- 写完成
FSM_WREND:
fsm_ns = FSM_IDLE;
//--------------------------------------------------- 读
FSM_READ:
if(burst_rddone)
fsm_ns = FSM_RDEND;
else
fsm_ns = fsm_cs;
//--------------------------------------------------- 读完成
FSM_RDEND:
fsm_ns = FSM_IDLE;
default:
fsm_ns = FSM_IDLE;
endcase
end
//==========================================================================
//== 根据FIFO的状态,选择读写操作通道
//==========================================================================
//写通道
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
wrchannel <= 3'h0;
end
else if(fsm_cs == FSM_ARBIT && ch0_wr_en && ch0_wrFIFO_rdusedw >= burst_len) begin
wrchannel <= 3'h0;
end
else if(fsm_cs == FSM_ARBIT && ch1_wr_en && ch1_wrFIFO_rdusedw >= burst_len) begin
wrchannel <= 3'h1;
end
else if(fsm_cs == FSM_ARBIT && ch2_wr_en && ch2_wrFIFO_rdusedw >= burst_len) begin
wrchannel <= 3'h2;
end
else if(fsm_cs == FSM_ARBIT && ch3_wr_en && ch3_wrFIFO_rdusedw >= burst_len) begin
wrchannel <= 3'h3;
end
else if(fsm_cs == FSM_ARBIT && ch4_wr_en && ch4_wrFIFO_rdusedw >= burst_len) begin
wrchannel <= 3'h4;
end
else if(fsm_cs == FSM_ARBIT && ch5_wr_en && ch5_wrFIFO_rdusedw >= burst_len) begin
wrchannel <= 3'h5;
end
else if(fsm_cs == FSM_ARBIT && ch6_wr_en && ch6_wrFIFO_rdusedw >= burst_len) begin
wrchannel <= 3'h6;
end
else if(fsm_cs == FSM_ARBIT && ch7_wr_en && ch7_wrFIFO_rdusedw >= burst_len) begin
wrchannel <= 3'h7;
end
end
//读通道
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
rdchannel <= 3'h0;
end
else if(fsm_cs == FSM_ARBIT && ch0_rd_en && 9'd256 - ch0_rdFIFO_wrusedw >= burst_len) begin
rdchannel <= 3'h0;
end
else if(fsm_cs == FSM_ARBIT && ch1_rd_en && 9'd256 - ch1_rdFIFO_wrusedw >= burst_len) begin
rdchannel <= 3'h1;
end
else if(fsm_cs == FSM_ARBIT && ch2_rd_en && 9'd256 - ch2_rdFIFO_wrusedw >= burst_len) begin
rdchannel <= 3'h2;
end
else if(fsm_cs == FSM_ARBIT && ch3_rd_en && 9'd256 - ch3_rdFIFO_wrusedw >= burst_len) begin
rdchannel <= 3'h3;
end
else if(fsm_cs == FSM_ARBIT && ch4_rd_en && 9'd256 - ch4_rdFIFO_wrusedw >= burst_len) begin
rdchannel <= 3'h4;
end
else if(fsm_cs == FSM_ARBIT && ch5_rd_en && 9'd256 - ch5_rdFIFO_wrusedw >= burst_len) begin
rdchannel <= 3'h5;
end
else if(fsm_cs == FSM_ARBIT && ch6_rd_en && 9'd256 - ch6_rdFIFO_wrusedw >= burst_len) begin
rdchannel <= 3'h6;
end
else if(fsm_cs == FSM_ARBIT && ch7_rd_en && 9'd256 - ch7_rdFIFO_wrusedw >= burst_len) begin
rdchannel <= 3'h7;
end
end
//==========================================================================
//== 完成一次行突发后,写行的计数递增
//==========================================================================
//写通道0
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch0_wr_vcnt <= 16'h0;
end
else if((wrchannel == 3'h0 && fsm_cs == FSM_WRITE && burst_wrdone && ch0_wr_vcnt == ch0_height - 16'h1) || ch0_wr_rst) begin
ch0_wr_vcnt <= 16'h0;
end
else if(wrchannel == 3'h0 && fsm_cs == FSM_WRITE && burst_wrdone) begin
ch0_wr_vcnt <= ch0_wr_vcnt + 16'h1;
end
end
//写通道1
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch1_wr_vcnt <= 16'h0;
end
else if((wrchannel == 3'h1 && fsm_cs == FSM_WRITE && burst_wrdone && ch1_wr_vcnt == ch1_height - 16'h1) || ch1_wr_rst) begin
ch1_wr_vcnt <= 16'h0;
end
else if(wrchannel == 3'h1 && fsm_cs == FSM_WRITE && burst_wrdone) begin
ch1_wr_vcnt <= ch1_wr_vcnt + 16'h1;
end
end
//写通道2
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch2_wr_vcnt <= 16'h0;
end
else if((wrchannel == 3'h2 && fsm_cs == FSM_WRITE && burst_wrdone && ch2_wr_vcnt == ch2_height - 16'h1) || ch2_wr_rst) begin
ch2_wr_vcnt <= 16'h0;
end
else if(wrchannel == 3'h2 && fsm_cs == FSM_WRITE && burst_wrdone) begin
ch2_wr_vcnt <= ch2_wr_vcnt + 16'h1;
end
end
//写通道3
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch3_wr_vcnt <= 16'h0;
end
else if((wrchannel == 3'h3 && fsm_cs == FSM_WRITE && burst_wrdone && ch3_wr_vcnt == ch3_height - 16'h1) || ch3_wr_rst) begin
ch3_wr_vcnt <= 16'h0;
end
else if(wrchannel == 3'h3 && fsm_cs == FSM_WRITE && burst_wrdone) begin
ch3_wr_vcnt <= ch3_wr_vcnt + 16'h1;
end
end
//写通道4
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch4_wr_vcnt <= 16'h0;
end
else if((wrchannel == 3'h4 && fsm_cs == FSM_WRITE && burst_wrdone && ch4_wr_vcnt == ch4_height - 16'h1) || ch4_wr_rst) begin
ch4_wr_vcnt <= 16'h0;
end
else if(wrchannel == 3'h4 && fsm_cs == FSM_WRITE && burst_wrdone) begin
ch4_wr_vcnt <= ch4_wr_vcnt + 16'h1;
end
end
//写通道5
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch5_wr_vcnt <= 16'h0;
end
else if((wrchannel == 3'h5 && fsm_cs == FSM_WRITE && burst_wrdone && ch5_wr_vcnt == ch5_height - 16'h1) || ch5_wr_rst) begin
ch5_wr_vcnt <= 16'h0;
end
else if(wrchannel == 3'h5 && fsm_cs == FSM_WRITE && burst_wrdone) begin
ch5_wr_vcnt <= ch5_wr_vcnt + 16'h1;
end
end
//写通道6
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch6_wr_vcnt <= 16'h0;
end
else if((wrchannel == 3'h6 && fsm_cs == FSM_WRITE && burst_wrdone && ch6_wr_vcnt == ch6_height - 16'h1) || ch6_wr_rst) begin
ch6_wr_vcnt <= 16'h0;
end
else if(wrchannel == 3'h6 && fsm_cs == FSM_WRITE && burst_wrdone) begin
ch6_wr_vcnt <= ch6_wr_vcnt + 16'h1;
end
end
//写通道7
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch7_wr_vcnt <= 16'h0;
end
else if((wrchannel == 3'h7 && fsm_cs == FSM_WRITE && burst_wrdone && ch7_wr_vcnt == ch7_height - 16'h1) || ch7_wr_rst) begin
ch7_wr_vcnt <= 16'h0;
end
else if(wrchannel == 3'h7 && fsm_cs == FSM_WRITE && burst_wrdone) begin
ch7_wr_vcnt <= ch7_wr_vcnt + 16'h1;
end
end
//==========================================================================
//== 完成一次行突发后,读行的计数递增
//==========================================================================
//读通道0
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch0_rd_vcnt <= 16'h0;
end
else if((rdchannel == 3'h0 && fsm_cs == FSM_READ && burst_rddone && ch0_rd_vcnt == ch0_height - 16'h1) || ch0_rd_rst) begin
ch0_rd_vcnt <= 16'h0;
end
else if(rdchannel == 3'h0 && fsm_cs == FSM_READ && burst_rddone) begin
ch0_rd_vcnt <= ch0_rd_vcnt + 16'h1;
end
end
//读通道1
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch1_rd_vcnt <= 16'h0;
end
else if((rdchannel == 3'h1 && fsm_cs == FSM_READ && burst_rddone && ch1_rd_vcnt == ch1_height - 16'h1) || ch1_rd_rst) begin
ch1_rd_vcnt <= 16'h0;
end
else if(rdchannel == 3'h1 && fsm_cs == FSM_READ && burst_rddone) begin
ch1_rd_vcnt <= ch1_rd_vcnt + 16'h1;
end
end
//读通道2
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch2_rd_vcnt <= 16'h0;
end
else if((rdchannel == 3'h2 && fsm_cs == FSM_READ && burst_rddone && ch2_rd_vcnt == ch2_height - 16'h1) || ch2_rd_rst) begin
ch2_rd_vcnt <= 16'h0;
end
else if(rdchannel == 3'h2 && fsm_cs == FSM_READ && burst_rddone) begin
ch2_rd_vcnt <= ch2_rd_vcnt + 16'h1;
end
end
//读通道3
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch3_rd_vcnt <= 16'h0;
end
else if((rdchannel == 3'h3 && fsm_cs == FSM_READ && burst_rddone && ch3_rd_vcnt == ch3_height - 16'h1) || ch3_rd_rst) begin
ch3_rd_vcnt <= 16'h0;
end
else if(rdchannel == 3'h3 && fsm_cs == FSM_READ && burst_rddone) begin
ch3_rd_vcnt <= ch3_rd_vcnt + 16'h1;
end
end
//读通道4
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch4_rd_vcnt <= 16'h0;
end
else if((rdchannel == 3'h4 && fsm_cs == FSM_READ && burst_rddone && ch4_rd_vcnt == ch4_height - 16'h1) || ch4_rd_rst) begin
ch4_rd_vcnt <= 16'h0;
end
else if(rdchannel == 3'h4 && fsm_cs == FSM_READ && burst_rddone) begin
ch4_rd_vcnt <= ch4_rd_vcnt + 16'h1;
end
end
//读通道5
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch5_rd_vcnt <= 16'h0;
end
else if((rdchannel == 3'h5 && fsm_cs == FSM_READ && burst_rddone && ch5_rd_vcnt == ch5_height - 16'h1) || ch5_rd_rst) begin
ch5_rd_vcnt <= 16'h0;
end
else if(rdchannel == 3'h5 && fsm_cs == FSM_READ && burst_rddone) begin
ch5_rd_vcnt <= ch5_rd_vcnt + 16'h1;
end
end
//读通道6
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch6_rd_vcnt <= 16'h0;
end
else if((rdchannel == 3'h6 && fsm_cs == FSM_READ && burst_rddone && ch6_rd_vcnt == ch6_height - 16'h1) || ch6_rd_rst) begin
ch6_rd_vcnt <= 16'h0;
end
else if(rdchannel == 3'h6 && fsm_cs == FSM_READ && burst_rddone) begin
ch6_rd_vcnt <= ch6_rd_vcnt + 16'h1;
end
end
//读通道7
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch7_rd_vcnt <= 16'h0;
end
else if((rdchannel == 3'h7 && fsm_cs == FSM_READ && burst_rddone && ch7_rd_vcnt == ch7_height - 16'h1) || ch7_rd_rst) begin
ch7_rd_vcnt <= 16'h0;
end
else if(rdchannel == 3'h7 && fsm_cs == FSM_READ && burst_rddone) begin
ch7_rd_vcnt <= ch7_rd_vcnt + 16'h1;
end
end
//==========================================================================
//== 读写地址设计
//==========================================================================
//写地址:逐行,列[9:0],行[9:0]
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
burst_wraddr <= `LOCAL_ADDR_W'h0;
end
else if(wrchannel == 3'h0) begin
burst_wraddr <= {ch0_wraddr_msb,ch0_addr,20'h0} + {ch0_wr_vcnt[9:0],10'h0};
end
else if(wrchannel == 3'h1) begin
burst_wraddr <= {ch1_wraddr_msb,ch1_addr,20'h0} + {ch1_wr_vcnt[9:0],10'h0};
end
else if(wrchannel == 3'h2) begin
burst_wraddr <= {ch2_wraddr_msb,ch2_addr,20'h0} + {ch2_wr_vcnt[9:0],10'h0};
end
else if(wrchannel == 3'h3) begin
burst_wraddr <= {ch3_wraddr_msb,ch3_addr,20'h0} + {ch3_wr_vcnt[9:0],10'h0};
end
else if(wrchannel == 3'h4) begin
burst_wraddr <= {ch4_wraddr_msb,ch4_addr,20'h0} + {ch4_wr_vcnt[9:0],10'h0};
end
else if(wrchannel == 3'h5) begin
burst_wraddr <= {ch5_wraddr_msb,ch5_addr,20'h0} + {ch5_wr_vcnt[9:0],10'h0};
end
else if(wrchannel == 3'h6) begin
burst_wraddr <= {ch6_wraddr_msb,ch6_addr,20'h0} + {ch6_wr_vcnt[9:0],10'h0};
end
else if(wrchannel == 3'h7) begin
burst_wraddr <= {ch7_wraddr_msb,ch7_addr,20'h0} + {ch7_wr_vcnt[9:0],10'h0};
end
end
//读地址:逐行,列[9:0],行[9:0]
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
burst_rdaddr <= `LOCAL_ADDR_W'h0;
end
else if(rdchannel == 3'h0) begin
burst_rdaddr <= {ch0_rdaddr_msb,ch0_addr,20'h0} + {ch0_rd_vcnt[9:0],10'h0};
end
else if(rdchannel == 3'h1) begin
burst_rdaddr <= {ch1_rdaddr_msb,ch1_addr,20'h0} + {ch1_rd_vcnt[9:0],10'h0};
end
else if(rdchannel == 3'h2) begin
burst_rdaddr <= {ch2_rdaddr_msb,ch2_addr,20'h0} + {ch2_rd_vcnt[9:0],10'h0};
end
else if(rdchannel == 3'h3) begin
burst_rdaddr <= {ch3_rdaddr_msb,ch3_addr,20'h0} + {ch3_rd_vcnt[9:0],10'h0};
end
else if(rdchannel == 3'h4) begin
burst_rdaddr <= {ch4_rdaddr_msb,ch4_addr,20'h0} + {ch4_rd_vcnt[9:0],10'h0};
end
else if(rdchannel == 3'h5) begin
burst_rdaddr <= {ch5_rdaddr_msb,ch5_addr,20'h0} + {ch5_rd_vcnt[9:0],10'h0};
end
else if(rdchannel == 3'h6) begin
burst_rdaddr <= {ch6_rdaddr_msb,ch6_addr,20'h0} + {ch6_rd_vcnt[9:0],10'h0};
end
else if(rdchannel == 3'h7) begin
burst_rdaddr <= {ch7_rdaddr_msb,ch7_addr,20'h0} + {ch7_rd_vcnt[9:0],10'h0};
end
end
//==========================================================================
//== 读写请求
//==========================================================================
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
burst_wrreq <= 1'h0;
end
else if(burst_wrreq == 1'h0 && fsm_cs == FSM_WRITE) begin
burst_wrreq <= 1'b1;
end
else if(burst_wrreq == 1'h1 && fsm_cs == FSM_WRITE && burst_wrdone) begin
burst_wrreq <= 1'b0;
end
end
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
burst_rdreq <= 1'h0;
end
else if(burst_rdreq == 1'h0 && fsm_cs == FSM_READ) begin
burst_rdreq <= 1'b1;
end
else if(burst_rdreq == 1'h1 && fsm_cs == FSM_READ && burst_rddone) begin
burst_rdreq <= 1'b0;
end
end
//==========================================================================
//== 乒乓操作,写完一帧图像乒乓操作切换分区
//==========================================================================
//读写通道0
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch0_wraddr_msb <= 2'h1;
end
else if(wrchannel == 3'h0 && burst_wrdone && ch0_wr_vcnt == ch0_height - 16'h1 && ch0_rdaddr_msb != ch0_wraddr_msb + 2'h1) begin
ch0_wraddr_msb <= ch0_wraddr_msb + 2'h1;
end
end
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch0_rdaddr_msb <= 2'h0;
end
else if(rdchannel == 3'h0 && burst_rddone && ch0_rd_vcnt == ch0_height - 16'h1 && ch0_wraddr_msb != ch0_rdaddr_msb + 2'h1) begin
ch0_rdaddr_msb <= ch0_rdaddr_msb + 2'h1;
end
end
//读写通道1
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch1_wraddr_msb <= 2'h1;
end
else if(wrchannel == 3'h1 && burst_wrdone && ch1_wr_vcnt == ch1_height - 16'h1 && ch1_rdaddr_msb != ch1_wraddr_msb + 2'h1) begin
ch1_wraddr_msb <= ch1_wraddr_msb + 2'h1;
end
end
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch1_rdaddr_msb <= 2'h0;
end
else if(rdchannel == 3'h1 && burst_rddone && ch1_rd_vcnt == ch1_height - 16'h1 && ch1_wraddr_msb != ch1_rdaddr_msb + 2'h1) begin
ch1_rdaddr_msb <= ch1_rdaddr_msb + 2'h1;
end
end
//读写通道2
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch2_wraddr_msb <= 2'h1;
end
else if(wrchannel == 3'h2 && burst_wrdone && ch2_wr_vcnt == ch2_height - 16'h1 && ch2_rdaddr_msb != ch2_wraddr_msb + 2'h1) begin
ch2_wraddr_msb <= ch2_wraddr_msb + 2'h1;
end
end
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch2_rdaddr_msb <= 2'h0;
end
else if(rdchannel == 3'h2 && burst_rddone && ch2_rd_vcnt == ch2_height - 16'h1 && ch2_wraddr_msb != ch2_rdaddr_msb + 2'h1) begin
ch2_rdaddr_msb <= ch2_rdaddr_msb + 2'h1;
end
end
//读写通道3
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch3_wraddr_msb <= 2'h1;
end
else if(wrchannel == 3'h3 && burst_wrdone && ch3_wr_vcnt == ch3_height - 16'h1 && ch3_rdaddr_msb != ch3_wraddr_msb + 2'h1) begin
ch3_wraddr_msb <= ch3_wraddr_msb + 2'h1;
end
end
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch3_rdaddr_msb <= 2'h0;
end
else if(rdchannel == 3'h3 && burst_rddone && ch3_rd_vcnt == ch3_height - 16'h1 && ch3_wraddr_msb != ch3_rdaddr_msb + 2'h1) begin
ch3_rdaddr_msb <= ch3_rdaddr_msb + 2'h1;
end
end
//读写通道4
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch4_wraddr_msb <= 2'h1;
end
else if(wrchannel == 3'h4 && burst_wrdone && ch4_wr_vcnt == ch4_height - 16'h1 && ch4_rdaddr_msb != ch4_wraddr_msb + 2'h1) begin
ch4_wraddr_msb <= ch4_wraddr_msb + 2'h1;
end
end
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch4_rdaddr_msb <= 2'h0;
end
else if(rdchannel == 3'h4 && burst_rddone && ch4_rd_vcnt == ch4_height - 16'h1 && ch4_wraddr_msb != ch4_rdaddr_msb + 2'h1) begin
ch4_rdaddr_msb <= ch4_rdaddr_msb + 2'h1;
end
end
//读写通道5
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch5_wraddr_msb <= 2'h1;
end
else if(wrchannel == 3'h5 && burst_wrdone && ch5_wr_vcnt == ch5_height - 16'h1 && ch5_rdaddr_msb != ch5_wraddr_msb + 2'h1) begin
ch5_wraddr_msb <= ch5_wraddr_msb + 2'h1;
end
end
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch5_rdaddr_msb <= 2'h0;
end
else if(rdchannel == 3'h5 && burst_rddone && ch5_rd_vcnt == ch5_height - 16'h1 && ch5_wraddr_msb != ch5_rdaddr_msb + 2'h1) begin
ch5_rdaddr_msb <= ch5_rdaddr_msb + 2'h1;
end
end
//读写通道6
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch6_wraddr_msb <= 2'h1;
end
else if(wrchannel == 3'h6 && burst_wrdone && ch6_wr_vcnt == ch6_height - 16'h1 && ch6_rdaddr_msb != ch6_wraddr_msb + 2'h1) begin
ch6_wraddr_msb <= ch6_wraddr_msb + 2'h1;
end
end
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch6_rdaddr_msb <= 2'h0;
end
else if(rdchannel == 3'h6 && burst_rddone && ch6_rd_vcnt == ch6_height - 16'h1 && ch6_wraddr_msb != ch6_rdaddr_msb + 2'h1) begin
ch6_rdaddr_msb <= ch6_rdaddr_msb + 2'h1;
end
end
//读写通道7
//---------------------------------------------------
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch7_wraddr_msb <= 2'h1;
end
else if(wrchannel == 3'h7 && burst_wrdone && ch7_wr_vcnt == ch7_height - 16'h1 && ch7_rdaddr_msb != ch7_wraddr_msb + 2'h1) begin
ch7_wraddr_msb <= ch7_wraddr_msb + 2'h1;
end
end
always @ (posedge phy_clk or negedge rst_n) begin
if(!rst_n) begin
ch7_rdaddr_msb <= 2'h0;
end
else if(rdchannel == 3'h7 && burst_rddone && ch7_rd_vcnt == ch7_height - 16'h1 && ch7_wraddr_msb != ch7_rdaddr_msb + 2'h1) begin
ch7_rdaddr_msb <= ch7_rdaddr_msb + 2'h1;
end
end
endmodule
(3) DDR2_burst
DDR2_burst
//**************************************************************************
// *** 名称 : DDR2_burst.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2020年6月
// *** 描述 : 完成一次DDR2的突发读写
//**************************************************************************
module DDR2_burst
//============================< 参数 >======================================
#(
parameter MEM_DM_W = 4 , //DDR2 dm位宽
parameter MEM_DQS_W = 4 , //DDR2 dqs位宽
parameter MEM_BANK_W = 3 , //DDR2 bank位宽
parameter MEM_ADDR_W = 13 , //DDR2 地址位宽
parameter MEM_DQ_W = 32 , //DDR2 数据位宽,一片16两片32
//-------------------------------------------------------
parameter LOCAL_SIZE_W = 3 , //DDR2 IP核local_size位宽
parameter LOCAL_DATA_W = 64 , //DDR2 IP核数据位宽
parameter LOCAL_ADDR_W = 25 //DDR2 IP核地址位宽
)
//============================< 端口 >======================================
(
//DDR2 IP核接口 -----------------------------------------
input pll_ref_clk , //DDR2 参考时钟
input global_reset_n , //FPGA 全局复位
output phy_clk , //DDR2 工作时钟
output DDR2_rst_n , //DDR2 同步复位
//突发读写接口 ------------------------------------------
input burst_rd_req , //突发读请求
input burst_wr_req , //突发写请求
input [LOCAL_ADDR_W -3:0] burst_rd_len , //突发读长度
input [LOCAL_ADDR_W -3:0] burst_wr_len , //突发写长度
input [LOCAL_ADDR_W -1:0] burst_rd_addr , //突发读地址
input [LOCAL_ADDR_W -1:0] burst_wr_addr , //突发写地址
output [LOCAL_DATA_W -1:0] burst_rd_data , //突发读数据
input [LOCAL_DATA_W -1:0] burst_wr_data , //突发写数据
output burst_rd_ack , //突发读应答,连接FIFO
output burst_wr_ack , //突发写应答,连接FIFO
output reg burst_rd_done , //突发读完成信号
output reg burst_wr_done , //突发写完成信号
//DDR2 芯片接口 -----------------------------------------
output mem_odt , //DDR2 片上终结信号
output mem_cs_n , //DDR2 片选信号
output mem_cke , //DDR2 时钟使能信号
output [MEM_ADDR_W -1:0] mem_addr , //DDR2 地址总线
output [MEM_BANK_W -1:0] mem_ba , //DDR2 BANK信号
output mem_ras_n , //DDR2 行地址选择信号
output mem_cas_n , //DDR2 列地址选择信号
output mem_we_n , //DDR2 写使能信号
output [MEM_DM_W -1:0] mem_dm , //DDR2 数据掩膜信号
inout mem_clk , //DDR2 时钟信号
inout mem_clk_n , //DDR2 时钟反相信号
inout [MEM_DQ_W -1:0] mem_dq , //DDR2 数据总线
inout [MEM_DQS_W -1:0] mem_dqs //DDR2 数据源同步信号
);
//============================< 信号 >======================================
reg [LOCAL_ADDR_W -1:0] local_address ; //DDR2 IP核地址总线
wire local_write_req ; //DDR2 IP核写请求信号
wire local_read_req ; //DDR2 IP核读请求信号
wire local_burstbegin ; //DDR2 IP核突发起始信号
wire [LOCAL_DATA_W -1:0] local_wdata ; //DDR2 IP核写数据总线
reg [LOCAL_SIZE_W -1:0] local_size ; //DDR2 IP核突发大小
wire local_ready ; //DDR2 IP核准备好信号
wire [LOCAL_DATA_W -1:0] local_rdata ; //DDR2 IP核读数据总线
wire local_rdata_valid ; //DDR2 IP核读数据有效信号
wire reset_phy_clk_n ; //DDR2 IP核复位后同步信号
wire local_init_done ; //DDR2 IP核初始化完成信号
//-------------------------------------------------------
reg [4:0] state ; //状态机
reg [LOCAL_ADDR_W -1:0] wr_len ; //读突发长度
reg [LOCAL_ADDR_W -1:0] rd_len ; //写突发长度
reg [LOCAL_ADDR_W -1:0] wr_addr_cnt ; //写地址计数器
reg [LOCAL_ADDR_W -1:0] wr_burst_cnt ; //一次突发写内的数据计数
reg [LOCAL_ADDR_W -1:0] rd_addr_cnt ; //读地址计数器
reg [LOCAL_ADDR_W -1:0] rd_data_cnt ; //读数据计数器
//============================< 参数 >======================================
localparam WR_SIZE = 2 ; //总线写突发
localparam RD_SIZE = 2 ; //总线读突发
//------------------------------------------------------
localparam IDLE = 5'b00001 ; //空闲状态
localparam ARBIT = 5'b00010 ; //仲裁状态
localparam WR = 5'b00100 ; //写状态
localparam RD_ADDR = 5'b01000 ; //读状态
localparam RD_WAIT = 5'b10000 ; //读等待状态
//==========================================================================
//== DDR2 IP核,PLL 100Mhz,DDR2 166.7Mhz,Full Rate
//==========================================================================
DDR2 u_DDR2
(
.pll_ref_clk (pll_ref_clk ), //DDR2 参考时钟
.global_reset_n (global_reset_n ), //全局复位信号
.soft_reset_n (1'b1 ), //软复位信号
.local_address (local_address ), //DDR2 IP核地址总线
.local_write_req (local_write_req ), //DDR2 IP核写请求信号
.local_read_req (local_read_req ), //DDR2 IP核读请求信号
.local_burstbegin (local_burstbegin ), //DDR2 IP核突发起始信号
.local_wdata (local_wdata ), //DDR2 IP核写数据总线
.local_be (8'b1111_1111 ), //DDR2 IP核字节使能信号
.local_size (local_size ), //DDR2 IP核突发大小
.local_ready (local_ready ), //DDR2 IP核准备好信号
.local_rdata (local_rdata ), //DDR2 IP核读数据总线
.local_rdata_valid (local_rdata_valid ), //DDR2 IP核读数据有效信号
.local_refresh_ack ( ), //DDR2 IP核自刷新应答信号
.local_init_done (local_init_done ), //DDR2 IP核初始化完成信号
//---------------------------------------------------
.mem_odt (mem_odt ), //DDR2片上终结信号
.mem_cs_n (mem_cs_n ), //DDR2片选信号
.mem_cke (mem_cke ), //DDR2时钟使能信号
.mem_addr (mem_addr ), //DDR2地址总线
.mem_ba (mem_ba ), //DDR2组地址信号
.mem_ras_n (mem_ras_n ), //DDR2行地址选择信
.mem_cas_n (mem_cas_n ), //DDR2列地址选择信
.mem_we_n (mem_we_n ), //DDR2写使能信号
.mem_dm (mem_dm ), //DDR2数据掩膜信号
.mem_clk (mem_clk ), //DDR2时钟信号
.mem_clk_n (mem_clk_n ), //DDR2时钟反相信号
.mem_dq (mem_dq ), //DDR2数据总线
.mem_dqs (mem_dqs ), //DDR2数据源同步信号
.phy_clk (phy_clk ), //DDR2 IP核工作时钟
.reset_phy_clk_n (reset_phy_clk_n ), //DDR2 IP核同步后的复位信号
.reset_request_n ( ), //DDR2 IP核复位请求信号
.aux_full_rate_clk ( ), //DDR2 IP核全速率时钟
.aux_half_rate_clk ( ) //DDR2 IP核半速率时钟
);
//本模块复位信号
assign DDR2_rst_n = reset_phy_clk_n & local_init_done;
//==========================================================================
//== 状态机
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
state <= IDLE;
burst_wr_done <= 1'b0;
burst_rd_done <= 1'b0;
end
else begin
case(state)
IDLE: begin
burst_wr_done <= 1'b0;
burst_rd_done <= 1'b0;
state <= ARBIT;
end
ARBIT: begin
if(burst_wr_req) begin
state <= WR;
end
else if(burst_rd_req) begin
state <= RD_ADDR;
end
end
WR: begin
if(wr_addr_cnt + wr_burst_cnt >= wr_len - 1 && local_ready) begin
state <= IDLE;
burst_wr_done <= 1'b1;
end
end
RD_ADDR:begin
if(rd_addr_cnt >= rd_len - RD_SIZE && local_ready) begin
state <= RD_WAIT;
end
end
RD_WAIT:begin
if(rd_data_cnt >= rd_len - 1) begin
state <= IDLE;
burst_rd_done <= 1'b1;
end
end
default:
state <= IDLE;
endcase
end
end
//------------------------------------------ 状态机名称,测试用
reg [55:0] state_name; //1个字符8位宽
always @(*) begin
case(state)
IDLE : state_name = "IDLE";
ARBIT : state_name = "ARBIT";
WR : state_name = "WR";
RD_ADDR : state_name = "RD_ADDR";
RD_WAIT : state_name = "RD_WAIT";
default : state_name = "IDLE";
endcase
end
//==========================================================================
//== 在进入读状态前锁存读突发长度
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
wr_len <= 'h0;
end
else if(state == ARBIT && burst_wr_req) begin
wr_len <= burst_wr_len;
end
end
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
rd_len <= 'h0;
end
else if(state == ARBIT && burst_rd_req) begin
rd_len <= burst_rd_len;
end
end
//==========================================================================
//== 写突发的数据计数:0101010101
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
wr_burst_cnt <= 'h0;
end
else if(state == WR && local_ready) begin
if(wr_burst_cnt >= WR_SIZE - 1)
wr_burst_cnt <= 'h0;
else
wr_burst_cnt <= wr_burst_cnt + 'h1;
end
end
//==========================================================================
//== 每凑齐2个数据则地址+2
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
wr_addr_cnt <= 'h0;
end
else if(state == WR && local_ready) begin
if(wr_addr_cnt + wr_burst_cnt >= wr_len - 1)
wr_addr_cnt <= 'h0;
else if(wr_burst_cnt >= WR_SIZE - 1)
wr_addr_cnt <= wr_addr_cnt + WR_SIZE;
end
end
//==========================================================================
//== 每给出读指令时读地址+2
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
rd_addr_cnt <= 'h0;
end
else if(state == RD_ADDR && local_ready) begin
if(rd_addr_cnt >= rd_len - RD_SIZE)
rd_addr_cnt <= 'h0;
else
rd_addr_cnt <= rd_addr_cnt + RD_SIZE;
end
end
//==========================================================================
//== 每读出一个数据地址递+1
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
rd_data_cnt <= 'h0;
end
else if(local_rdata_valid) begin
if(rd_data_cnt >= rd_len - 1)
rd_data_cnt <= 'h0;
else
rd_data_cnt <= rd_data_cnt + 'h1;
end
end
//==========================================================================
//== 锁存local_size并在最后一次读写时如果不足突发大小则更改local_size为不足的大小
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
local_size <= 'h0;
end
else if(state == ARBIT && burst_wr_req) begin
local_size <= (burst_wr_len >= WR_SIZE) ? WR_SIZE : burst_wr_len;
end
else if(state == ARBIT && burst_rd_req) begin
local_size <= (burst_rd_len >= RD_SIZE) ? RD_SIZE : burst_rd_len;
end
else if(state == WR && wr_burst_cnt == WR_SIZE - 1 && wr_addr_cnt + {WR_SIZE,1'b0} > wr_len && local_ready) begin
local_size <= wr_len - wr_addr_cnt - WR_SIZE;
end
else if(state == RD_ADDR && rd_addr_cnt + {RD_SIZE,1'b0} > rd_len && local_ready) begin
local_size <= rd_len - rd_addr_cnt - RD_SIZE;
end
end
//==========================================================================
//== 锁存local_address,并且在完成一次突发读写时递增读写地址
//==========================================================================
always @ (posedge phy_clk or negedge DDR2_rst_n) begin
if(!DDR2_rst_n) begin
local_address <= 'h0;
end
else if(state == ARBIT && burst_wr_req) begin
local_address <= burst_wr_addr;
end
else if(state == ARBIT && burst_rd_req) begin
local_address <= burst_rd_addr;
end
else if(state == WR && (wr_burst_cnt == WR_SIZE - 1) && local_ready) begin
local_address <= local_address + WR_SIZE;
end
else if(state == RD_ADDR && local_ready) begin
local_address <= local_address + RD_SIZE;
end
end
//==========================================================================
//== 其他信号
//==========================================================================
//burstbegin信号,随便怎么写都行,直接赋值1'b1也能跑
assign local_burstbegin = (state == WR || state == RD_ADDR) ? 1'b1 : 1'b0;
//写数据
assign local_wdata = burst_wr_data;
//写应答,即写FIFO的读使能
assign burst_wr_ack = (state == WR && local_ready) ? 1'b1 : 1'b0;
//读数据
assign burst_rd_data = local_rdata;
//读应答,即读FIFO的写使能
assign burst_rd_ack = local_rdata_valid;
//写请求
assign local_write_req = (state == WR) ? 1'b1 : 1'b0;
//读请求
assign local_read_req = (state == RD_ADDR) ? 1'b1 : 1'b0;
endmodule
(4) DDR2_param
DDR2_param
//**************************************************************************
// *** 名称 : DDR2_param.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2020年6月
// *** 描述 : DDR2参数,PLL 100Mhz,DDR2 166.7Mhz,Full Rate
//**************************************************************************
`define MEM_ADDR_W 13 //DDR2 地址位宽
`define MEM_BANK_W 3 //DDR2 bank位宽
`define MEM_DM_W 4 //DDR2 dm位宽
`define MEM_DQ_W 32 //DDR2 数据位宽,一片16两片32
`define MEM_DQS_W 4 //DDR2 DQS位宽
`define LOCAL_DATA_W 64 //DDR2 IP核全速率数据位宽
`define LOCAL_ADDR_W 25 //DDR2 IP核全速率地址位宽
`define LOCAL_SIZE_W 3 //DDR2 IP核全速率local_size位宽
`define LOCAL_BE_W 8 //DDR2 IP核全速率local_be位宽
`define BURST_W 16 //burst长度位宽,burst_len + BURST_SIZE
3、VGA_driver
VGA_driver
//**************************************************************************
// *** 名称 : VGA_driver.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2019-06-26
// *** 描述 : VGA驱动模块
//**************************************************************************
module VGA_driver
//========================< 参数 >==========================================
// 640x480 @60Hz 25Mhz
#(
parameter H_TOTAL = 800 , //行扫描周期
parameter H_ADDR = 640 , //行有效数据
parameter H_SYNC = 96 , //行同步
parameter H_BACK = 48 , //行显示后沿
parameter V_TOTAL = 525 , //场扫描周期
parameter V_ADDR = 480 , //场有效数据
parameter V_SYNC = 2 , //场同步
parameter V_BACK = 33 //场显示后沿
)
//========================< 端口 >==========================================
(
//system --------------------------------------------------------
input wire clk , //时钟
input wire rst_n , //复位,低电平有效
//VGA_display ---------------------------------------------------
output wire ch0_VGA_req , //请求图像数据
output wire ch1_VGA_req , //请求图像数据
output wire ch2_VGA_req , //请求图像数据
output wire ch3_VGA_req , //请求图像数据
output wire ch4_VGA_req , //请求图像数据
output wire ch5_VGA_req , //请求图像数据
output wire ch6_VGA_req , //请求图像数据
output wire ch7_VGA_req , //请求图像数据
input wire [15:0] ch0_VGA_din , //得到图像数据
input wire [15:0] ch1_VGA_din , //得到图像数据
input wire [15:0] ch2_VGA_din , //得到图像数据
input wire [15:0] ch3_VGA_din , //得到图像数据
input wire [15:0] ch4_VGA_din , //得到图像数据
input wire [15:0] ch5_VGA_din , //得到图像数据
input wire [15:0] ch6_VGA_din , //得到图像数据
input wire [15:0] ch7_VGA_din , //得到图像数据
//VGA output ----------------------------------------------------
output wire VGA_clk , //VGA接口时钟信号
output wire VGA_hsync , //VGA接口行信号
output wire VGA_vsync , //VGA接口场信号
output wire [15:0] VGA_data //VGA接口数据信号
);
//========================< 颜色 >==========================================
localparam BLACK = 16'h0000 ; //黑
localparam WHITE = 16'hffff ; //白
localparam RED = 16'hf800 ; //红
localparam ORANGE = 16'hfd60 ; //橙
localparam YELLOW = 16'hffe0 ; //黄
localparam GREEN = 16'h07e0 ; //绿
localparam CYAN = 16'h07ff ; //青
localparam BLUE = 16'h001f ; //蓝
localparam PURPLE = 16'h801f ; //紫
//========================< 信号 >==========================================
reg [15:0] cnt_h ;
wire add_cnt_h ;
wire end_cnt_h ;
reg [15:0] cnt_v ;
wire add_cnt_v ;
wire end_cnt_v ;
//---------------------------------------------------------------
reg ch0_VGA_de_r1 ;
reg ch1_VGA_de_r1 ;
reg ch2_VGA_de_r1 ;
reg ch3_VGA_de_r1 ;
reg ch4_VGA_de_r1 ;
reg ch5_VGA_de_r1 ;
reg ch6_VGA_de_r1 ;
reg ch7_VGA_de_r1 ;
reg ch0_VGA_de_r2 ;
reg ch1_VGA_de_r2 ;
reg ch2_VGA_de_r2 ;
reg ch3_VGA_de_r2 ;
reg ch4_VGA_de_r2 ;
reg ch5_VGA_de_r2 ;
reg ch6_VGA_de_r2 ;
reg ch7_VGA_de_r2 ;
//==========================================================================
//== 行、场计数
//==========================================================================
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt_h <= 0;
else if(add_cnt_h) begin
if(end_cnt_h)
cnt_h <= 0;
else
cnt_h <= cnt_h + 1;
end
end
assign add_cnt_h = 1;
assign end_cnt_h = add_cnt_h && cnt_h==H_TOTAL-1;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt_v <= 0;
else if(add_cnt_v) begin
if(end_cnt_v)
cnt_v <= 0;
else
cnt_v <= cnt_v + 1;
end
end
assign add_cnt_v = end_cnt_h;
assign end_cnt_v = add_cnt_v && cnt_v==V_TOTAL-1;
//==========================================================================
//== 数据请求,比数据提前一拍
//==========================================================================
assign ch0_VGA_req = (cnt_h >= H_SYNC + H_BACK ) && (cnt_h < H_SYNC + H_BACK + H_ADDR*1/4) &&
(cnt_v >= V_SYNC + V_BACK ) && (cnt_v < V_SYNC + V_BACK + V_ADDR*1/2);
assign ch1_VGA_req = (cnt_h >= H_SYNC + H_BACK + H_ADDR*1/4) && (cnt_h < H_SYNC + H_BACK + H_ADDR*2/4) &&
(cnt_v >= V_SYNC + V_BACK ) && (cnt_v < V_SYNC + V_BACK + V_ADDR*1/2);
assign ch2_VGA_req = (cnt_h >= H_SYNC + H_BACK + H_ADDR*2/4) && (cnt_h < H_SYNC + H_BACK + H_ADDR*3/4) &&
(cnt_v >= V_SYNC + V_BACK ) && (cnt_v < V_SYNC + V_BACK + V_ADDR*1/2);
assign ch3_VGA_req = (cnt_h >= H_SYNC + H_BACK + H_ADDR*3/4) && (cnt_h < H_SYNC + H_BACK + H_ADDR*4/4) &&
(cnt_v >= V_SYNC + V_BACK ) && (cnt_v < V_SYNC + V_BACK + V_ADDR*1/2);
assign ch4_VGA_req = (cnt_h >= H_SYNC + H_BACK ) && (cnt_h < H_SYNC + H_BACK + H_ADDR*1/4) &&
(cnt_v >= V_SYNC + V_BACK + V_ADDR*1/2) && (cnt_v < V_SYNC + V_BACK + V_ADDR*2/2);
assign ch5_VGA_req = (cnt_h >= H_SYNC + H_BACK + H_ADDR*1/4) && (cnt_h < H_SYNC + H_BACK + H_ADDR*2/4) &&
(cnt_v >= V_SYNC + V_BACK + V_ADDR*1/2) && (cnt_v < V_SYNC + V_BACK + V_ADDR*2/2);
assign ch6_VGA_req = (cnt_h >= H_SYNC + H_BACK + H_ADDR*2/4) && (cnt_h < H_SYNC + H_BACK + H_ADDR*3/4) &&
(cnt_v >= V_SYNC + V_BACK + V_ADDR*1/2) && (cnt_v < V_SYNC + V_BACK + V_ADDR*2/2);
assign ch7_VGA_req = (cnt_h >= H_SYNC + H_BACK + H_ADDR*3/4) && (cnt_h < H_SYNC + H_BACK + H_ADDR*4/4) &&
(cnt_v >= V_SYNC + V_BACK + V_ADDR*1/2) && (cnt_v < V_SYNC + V_BACK + V_ADDR*2/2);
//==========================================================================
//== 数据使能,打1拍有细条纹,打2拍则没有
//==========================================================================
always @(posedge clk) begin
ch0_VGA_de_r1 <= ch0_VGA_req;
ch1_VGA_de_r1 <= ch1_VGA_req;
ch2_VGA_de_r1 <= ch2_VGA_req;
ch3_VGA_de_r1 <= ch3_VGA_req;
ch4_VGA_de_r1 <= ch4_VGA_req;
ch5_VGA_de_r1 <= ch5_VGA_req;
ch6_VGA_de_r1 <= ch6_VGA_req;
ch7_VGA_de_r1 <= ch7_VGA_req;
ch0_VGA_de_r2 <= ch0_VGA_de_r1;
ch1_VGA_de_r2 <= ch1_VGA_de_r1;
ch2_VGA_de_r2 <= ch2_VGA_de_r1;
ch3_VGA_de_r2 <= ch3_VGA_de_r1;
ch4_VGA_de_r2 <= ch4_VGA_de_r1;
ch5_VGA_de_r2 <= ch5_VGA_de_r1;
ch6_VGA_de_r2 <= ch6_VGA_de_r1;
ch7_VGA_de_r2 <= ch7_VGA_de_r1;
end
//==========================================================================
//== VGA端口输出
//==========================================================================
//时钟
assign VGA_clk = clk;
//行场同步
assign VGA_hsync = (cnt_h <= H_SYNC - 1) ? 0 : 1;
assign VGA_vsync = (cnt_v <= V_SYNC - 1) ? 0 : 1;
//数据
assign VGA_data = ch0_VGA_de_r2 ? ch0_VGA_din : // WHITE : //
ch1_VGA_de_r2 ? ch1_VGA_din : // RED : //
ch2_VGA_de_r2 ? ch2_VGA_din : // ORANGE : //
ch3_VGA_de_r2 ? ch3_VGA_din : // YELLOW : //
ch4_VGA_de_r2 ? ch4_VGA_din : // GREEN : //
ch5_VGA_de_r2 ? ch5_VGA_din : // CYAN : //
ch6_VGA_de_r2 ? ch6_VGA_din : // BLUE : //
ch7_VGA_de_r2 ? ch7_VGA_din : // PURPLE : //
16'b0;
endmodule
4、效果展示


学好 FPGA,然后离开 FPGA,也许这是我最后一篇 FPGA 博客了吧。
再见各位,ASIC 上继续奔跑吧!

浙公网安备 33010602011771号