📄 ddr_data.v
字号:
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Copyright (c) 2001 by Lattice Semiconductor Corporation
// --------------------------------------------------------------------
//
// Permission:
//
// Lattice Semiconductor grants permission to use this code for use
// in synthesis for any Lattice programmable logic product. Other
// use of this code, including the selling or duplication of any
// portion is strictly prohibited.
//
// Disclaimer:
//
// This VHDL or Verilog source code is intended as a design reference
// which illustrates how these types of functions can be implemented.
// It is the user's responsibility to verify their design for
// consistency and functionality through the use of formal
// verification methods. Lattice Semiconductor provides no warranty
// regarding the use or functionality of this code.
//
// --------------------------------------------------------------------
//
// Lattice Semiconductor Corporation
// 5555 NE Moore Court
// Hillsboro, OR 97214
// U.S.A
//
// TEL: 1-800-Lattice (USA and Canada)
// 408-826-6000 (other locations)
//
// web: http://www.latticesemi.com/
// email: techsupport@latticesemi.com
//
// --------------------------------------------------------------------
//
// This is the data path module of the SDR SDRAM controller reference
// design.
//
// --------------------------------------------------------------------
//
// Revision History :
// --------------------------------------------------------------------
// Ver :| Author :| Mod. Date :| Changes Made:
// V0.1 :| Nagaraj Chekka :| 07/23/03 :| Pre-Release
// --------------------------------------------------------------------
`timescale 1ns / 1ps
module ddr_data(
clk,
clk2x,
reset_n,
sys_dataout,
sys_dataout_en,
sys_datain,
sys_dmsel,
cstate,
wren,
sys_rdyn,
dqin,
dqout,
dqout_en,
dqsout,
dqsout_en,
dqm_out
);
`include "ddr_par.v"
//---- INPUTS
input clk; // Clkx from HPPLL
input clk2x; // Clk2x from HPPLL
input reset_n; // System reset
input [3:0] cstate; // Control state machine output
input wren; // Write enable signal
input [DSIZE-1:0] sys_datain; // System data in
input [DSIZE/8-1:0] sys_dmsel; // System data mask select.
input [DSIZE/2-1:0] dqin; // DDR data in (read data)
//---- OUTPUTS
output [DSIZE/2-1:0] dqout_en; // DDR output enables
output [DSIZE/2-1:0] dqout; // DDR output (write data)
output [DSIZE/16-1:0] dqsout_en; // DDR output enables
output [DSIZE/16-1:0] dqsout; // DDR output strobe
output sys_rdyn; // Ready signal to the system
output [DSIZE-1:0] sys_dataout /*synthesis dout="" */ ;
output [DSIZE-1:0] sys_dataout_en /*synthesis syn_preserve=1 */ /*synthesis dout="" */ ;
output [DSIZE/16-1:0] dqm_out; // Data mask output to DDR
//---- REGISTERS
reg [DSIZE/2-1:0] dqout_en /*synthesis syn_preserve=1 */ /*synthesis dout="" */ ;
reg [DSIZE/2-1:0] dqout /*synthesis dout="" */ ;
reg [DSIZE/16-1:0] dqsout_en /*synthesis syn_preserve=1 */ /*synthesis dout="" */ ;
reg [DSIZE/16-1:0] dqsout /*synthesis dout="" */ ;
reg sys_rdyn;
reg [DSIZE-1:0] sys_dataout_en /*synthesis syn_preserve=1 */ /*synthesis dout="" */;
reg [DSIZE/16-1:0] dqm_out /*synthesis dout="" */ ; // DDR SDRAM Data Mask signals
//--- Internal Registers
// Read path registers
reg [DSIZE/2-1:0] dqin_2x_sync_reg /*synthesis din="" */;
reg [DSIZE/2-1:0] dqin_x_reg;
reg [DSIZE/2-1:0] dqin_xn_reg;
reg [DSIZE/2-1:0] dqin_xnx_reg;
reg [DSIZE/2-1:0] dqin_reg_l /*synthesis dout="" */ ;
reg [DSIZE/2-1:0] dqin_reg_h /*synthesis dout="" */ ;
// Write path registers
reg [DSIZE/2+DSIZE/16-1:0] dqout_and_dqsout_en /*synthesis syn_preserve=1 */;
reg [DSIZE/2-1:0] dqout_reg;
reg [DSIZE/16-1:0] dqm_outreg;
reg [DSIZE/2-1:0] datain_regl /*synthesis din="" */;
reg [DSIZE/16-1:0] dmsel_regl /*synthesis din="" */;
reg [DSIZE-1:0] datain_nx ;
reg [DSIZE/8-1:0] dmsel_nx ;
reg dqsout_reg;
reg select_lower_half;
reg write_rdy_d1;
reg write_rdy_d2;
reg write_rdy_d3;
reg read_rdy;
reg read_rdy_d;
reg write_rdy;
reg wren_d2x;
reg wren_dx;
reg [DSIZE/16-1:0] dqsout_en_nx;
//--- WIRES
wire [DSIZE-1:0] sys_dataout;
//====================================================================
// Read Cycle Data Path
//====================================================================
// Latching the incoming DDR data
always @(posedge clk2x or negedge reset_n)begin
if (reset_n == 1'b0)
dqin_2x_sync_reg <= {DSIZE/2{1'b0}};
else
dqin_2x_sync_reg <= dqin;
end
// +ve edge clk
always @(posedge clk or negedge reset_n) begin
if (reset_n == 1'b0) begin
dqin_x_reg <= {DSIZE/2{1'b0}};
dqin_xnx_reg <= {DSIZE/2{1'b0}};
end
else begin
dqin_x_reg <= dqin_2x_sync_reg;
// dqin_xnx_reg will be used only for
// CAS latency = 2.5.
if (MR_CAS_Latency == Latency_25)
dqin_xnx_reg <= dqin_xn_reg;
end
end
// -ve edge clk
always @(negedge clk or negedge reset_n) begin
if (reset_n == 1'b0)
dqin_xn_reg <= {DSIZE/2{1'b0}};
else
dqin_xn_reg <= dqin_2x_sync_reg;
end
// Tranfering the data +ve clk
always @(posedge clk or negedge reset_n) begin
if (reset_n == 1'b0) begin
dqin_reg_l <= {DSIZE/2{1'b0}};
dqin_reg_h <= {DSIZE/2{1'b0}};
end else begin
if (MR_CAS_Latency == Latency_25) begin
dqin_reg_h <= dqin_x_reg;
dqin_reg_l <= dqin_xnx_reg;
end else begin
dqin_reg_h <= dqin_xn_reg;
dqin_reg_l <= dqin_x_reg;
end
end
end
assign sys_dataout = {dqin_reg_h, dqin_reg_l};
//====================================================================
// Write Cycle Data Path
//====================================================================
// Generation of dqout_en and dqsout_en for DDRRAM
// Assert the DDR output and DDR strobe output enables during
// the c_WRITEA, c_wdata and c_tDAL states
always @(posedge clk or negedge reset_n) begin
if (reset_n == 1'b0) begin
dqout_and_dqsout_en <= {DSIZE/2+DSIZE/16 {1'b0}};
end else begin
case (cstate)
c_WRITEA,c_wdata,c_tDAL : begin
// For XPGA
// dqout_and_dqsout_en <= {DSIZE/2+DSIZE/16 {1'b1}};
// For ORCA
dqout_and_dqsout_en <= {DSIZE/2+DSIZE/16 {1'b0}};
end
default: begin
// For XPGA
// dqout_and_dqsout_en <= {DSIZE/2+DSIZE/16 {1'b0}};
// For ORCA
dqout_and_dqsout_en <= {DSIZE/2+DSIZE/16 {1'b1}};
end
endcase
end
end
// Both dq_out, and dqout_en should be clocked by the
// same clock and the same edge (+ve clk2x). This is required
// otherwise PAR tool will not place output flops in PIC.
always @(posedge clk2x or negedge reset_n) begin
if (reset_n == 1'b0) begin
dqout_en <= {DSIZE/2 {1'b0}};
end else begin
dqout_en <= dqout_and_dqsout_en[DSIZE/2-1:0];
end
end
always @(negedge clk or negedge reset_n) begin
if (reset_n == 1'b0) begin
dqsout_en_nx <= {DSIZE/16 {1'b0}};
end else begin
dqsout_en_nx <= dqout_and_dqsout_en[DSIZE/2+DSIZE/16-1: DSIZE/2];
end
end
always @(negedge clk2x or negedge reset_n) begin
if (reset_n == 1'b0) begin
dqsout_en <= {DSIZE/16 {1'b0}};
end else begin
dqsout_en <= dqsout_en_nx;
end
end
// Generation of dqsout
always @(posedge clk2x or negedge reset_n) begin
if (reset_n == 1'b0) begin
wren_dx <= 1'b0;
end else begin
wren_dx <= wren_d2x ? ~wren_dx : 1'b0;
end
end
// Note that dqsout and dqsout_en are clocked
// with the same clock and the same edge (-ve clk2x)
always @(negedge clk2x or negedge reset_n) begin
if (reset_n == 1'b0) begin
dqsout_reg <= 1'b0;
dqsout <= {DSIZE/16{1'b0}};
end else begin
dqsout_reg <= wren_dx;
dqsout <= dqsout_reg;
end
end
// Generation of dqout
// Latch the system data on +ve clk
always @(negedge clk or negedge reset_n) begin
if (reset_n == 1'b0) begin
datain_nx <= {DSIZE{1'b0}};
dmsel_nx <= {DSIZE/8{1'b0}};
end else begin
datain_nx <= sys_datain[DSIZE-1:0];
dmsel_nx <= sys_dmsel[DSIZE/8-1:0];
end
end
// dqout_reg has two clocks (of clk2x) from sys_datain and datain_nx.
// Similarly for dqm_out.
// This is essential to meet the desired frequency.
always @(posedge clk2x or negedge reset_n) begin
if (reset_n == 1'b0) begin
wren_d2x <= 1'b0;
select_lower_half <= 1'b0;
dqout_reg <= {DSIZE/2 {1'b0}};
dqm_outreg <= {DSIZE/16 {1'b0}};
dqout <= {DSIZE/2 {1'b0}};
dqm_out <= {DSIZE/16{1'b0}};
end else begin
wren_d2x <= wren;
select_lower_half <= wren_d2x ? ~select_lower_half : 1'b0;
dqout_reg <= select_lower_half ? datain_nx[DSIZE-1:DSIZE/2] : sys_datain[DSIZE/2-1:0];
dqm_outreg <= select_lower_half ? dmsel_nx[DSIZE/8-1:DSIZE/16]: sys_dmsel[DSIZE/16-1:0];
dqout <= dqout_reg;
dqm_out <= dqm_outreg;
end
end
//====================================================================
// Generation of sys_rdyn. When sys_rdyn goes low
// data transfer takes place. Applies to read and write
//====================================================================
always @(posedge clk or negedge reset_n) begin
if (reset_n == 1'b0) begin
sys_rdyn <= 1'b1;
write_rdy_d1 <= 1'b0;
write_rdy_d2 <= 1'b0;
write_rdy_d3 <= 1'b0;
read_rdy <= 1'b0;
read_rdy_d <= 1'b0;
end else begin
// Generate for read and write cycles, during data transfer
// This will be useful to directly attach to processors
// Also during refresh time, if master requests read/write cycles.
write_rdy_d1 <= write_rdy;
write_rdy_d2 <= write_rdy_d1;
write_rdy_d3 <= write_rdy_d2;
read_rdy <= (cstate == c_rdata) ? 1'b1 : 1'b0;
read_rdy_d <= (read_rdy || (cstate == c_rdata) ) ? 1'b1: 1'b0;
if (NUM_CLK_WRITE == 1) // For burst length 2
sys_rdyn <= !(write_rdy | read_rdy);
if (NUM_CLK_WRITE == 2) // For burst length 4
sys_rdyn <= !(write_rdy | write_rdy_d1 | read_rdy);
if (NUM_CLK_WRITE == 4) // For burst length 8
sys_rdyn <= !(write_rdy | write_rdy_d1 | write_rdy_d2 | write_rdy_d3 | read_rdy);
end
end
// Generation of sys_dataout_en
always @(negedge clk or negedge reset_n) begin
if (reset_n == 1'b0) begin
sys_dataout_en <= {DSIZE{1'b0}};
end else begin
sys_dataout_en <= read_rdy_d ? {DSIZE {1'b0}} : {DSIZE {1'b1}};
end
end
// Generation of write_rdy (combinational signal)
always @ (cstate ) begin
case (cstate)
c_WRITEA: begin
write_rdy = 1'b1;
end
default: begin
write_rdy = 1'b0;
end
endcase
end
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -