OpenCores

Subversion Repositories ddr3_sdram

[/] [ddr3_sdram/] [trunk/] [drac_ddr3.v] - Rev 2

Compare with Previous | Blame | View Log

/* 
	DDR3 DRAM controller
	(C) Copyright 2012 Silicon On Inspiration
	www.sioi.com.au
	86 Longueville Road
	Lane Cove 2066
	New South Wales
	AUSTRALIA
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
 
`timescale 1ns / 1ps
 
module drac_ddr3
(
	input       	ckin,
	output       	ckout,
	output       	ckouthalf,
	output			reset,
 
	inout	[63:0]	ddq,
	inout	[7:0]	dqsp,
	inout	[7:0]	dqsn,
	output	[7:0]	ddm,
	output	[15:0]	da,
	output	[2:0]	dba,
	output	[2:0]	dcmd,
	output	[1:0]	dce,
	output	[1:0]	dcs,
	output	[1:0]	dckp,
	output	[1:0]	dckn,
	output	[1:0]	dodt,
 
	input			srd,
	input			swr,
	input	[33:5]	sa,
	input	[255:0]	swdat,
	input	[31:0]	smsk,
	output	[255:0]	srdat,
	output			srdy,
 
	input	[2:0]	dbg_out,
	output	[7:0]	dbg_in
);
 
reg					READ;
reg					READ2;
 
reg					ack;
 
reg			[15:0]	rDDR_Addr;
reg			[2:0]	rDDR_BankAddr;
reg			[1:0]	rDDR_CS_n;
reg			[2:0]	rDDR_Cmd;
reg			[1:0]	rDDR_CKE;
reg			[1:0]	rDDR_ODT;
 
reg			[2:0]	STATE;
reg			[2:0]	RTN;
reg			[5:0]	DLY;
 
reg			[10:0]	RFCNTR;
reg					REFRESH;
 
reg					RPULSE0;
reg					RPULSE1;
reg					RPULSE2;
reg					RPULSE3;
reg					RPULSE4;
reg					RPULSE5;
reg					RPULSE6;
reg					RPULSE7;
reg					WPULSE0;
reg			[255:0]	Q;
 
wire		[7:0]	DM;
wire		[7:0]	DM_t;
wire		[7:0]	wDDR_DM;
 
wire		[7:0]	wDDR_DQS;
wire		[63:0]	DQ_i;
wire		[63:0]	DQ_i_dly;
wire		[255:0]	wQ;
wire		[63:0]	DQ_o;
wire		[63:0]	DQ_t;
wire		[63:0]	wDDR_DQ;
 
reg			[255:0]	rWdat;
reg			[31:0]	rSmsk;
 
reg			[13:0]	rLock = 0;
reg					rClrPll = 1;
reg			[13:0]	rStart = 0;
reg					rStarted = 0;
 
reg			[63:0]	rChgDelay;
reg			[63:0]	rIncDelay;
reg			[63:0]	rCalDelay;
reg			[63:0]	rCalDelay2;
reg			[63:0]	rRstDelay;
 
// Set up clocks for DDR3.  Use circuitry based on UG382 Ch 1 pp33,34
// Generate the following clocks:
//
// ck600			600MHz clock for DQ IOSERDES2 high speed clock
// ck600_180		600MHz clock for DQS OSERDES2 high speed clock
//					DQS clocking lags DQ clocking by half of one bit time
// ck150			1/4 speed clock for IOSERDES2 parallel side and control logic
// ck75				Clock for MicroBlaze CPU
//
// Create two copies of the 600MHz clocks, providing separate copies for 
// bank 1 and bank 3.  This is necessary as each BUFPLL reaches only a
// single bank.  The other clocks are global (BUFG).
wire				ck600raw;
wire				ck600_180raw;
wire				ck150;
wire				ck150raw;
wire				ck75;
wire				ck75raw;
wire		[1:0]	ck600;
wire		[1:0]	ck600_180;
wire		[1:0]	strobe;
wire		[1:0]	strobe180;
 
// DDR3 DIMM byte lane levelling is achieved with these IODELAY2 settings:
parameter			LVL_WSLOPE = 3;
parameter			LVL_WPHASE = 6;
 
	BUFG bufg_main
	(
		.O   						(ckinb),
		.I   						(ckin)
	);
 
	PLL_BASE
	#(
		.BANDWIDTH              	("OPTIMIZED"),
		.CLK_FEEDBACK           	("CLKFBOUT"),
		.COMPENSATION           	("INTERNAL"),
		.DIVCLK_DIVIDE          	(3),
		.CLKFBOUT_MULT          	(29),
		.CLKFBOUT_PHASE         	(0.000),
		.CLKOUT0_DIVIDE         	(1),
		.CLKOUT0_PHASE          	(0.000),
		.CLKOUT0_DUTY_CYCLE     	(0.500),
		.CLKOUT1_DIVIDE         	(1),
		.CLKOUT1_PHASE          	(180.000),
		.CLKOUT1_DUTY_CYCLE     	(0.500),
		.CLKOUT2_DIVIDE         	(4),
		.CLKOUT2_PHASE          	(0.000),
		.CLKOUT2_DUTY_CYCLE     	(0.500),
		.CLKOUT3_DIVIDE         	(8),
		.CLKOUT3_PHASE          	(0.0),
		.CLKOUT3_DUTY_CYCLE     	(0.500),
		.CLKOUT4_DIVIDE         	(8),
		.CLKOUT4_PHASE          	(0.0),
		.CLKOUT4_DUTY_CYCLE     	(0.500),
		.CLKOUT5_DIVIDE         	(8),
		.CLKOUT5_PHASE          	(0.000),
		.CLKOUT5_DUTY_CYCLE     	(0.500),
		.CLKIN_PERIOD           	(16.000)
	)
	pll_base_main
	(
		.CLKFBOUT              		(pllfb0),
		.CLKOUT0               		(ck600raw),
		.CLKOUT1               		(ck600_180raw),
		.CLKOUT2               		(ck150raw),
		.CLKOUT3               		(ck75raw),
		.CLKOUT4               		(),
		.CLKOUT5               		(),
		.LOCKED                		(locked),
		.RST                   		(rClrPll),
		.CLKFBIN               		(pllfb0),
		.CLKIN                 		(ckinb)
	);
 
	BUFG bufg_150
	(
		.O   						(ck150),
		.I   						(ck150raw)
	);
 
	BUFG bufg_75
	(
		.O   						(ck75),
		.I   						(ck75raw)
	);
 
genvar i;
generate
	for (i = 0; i <= 1; i = i + 1) begin: BUFPLLS
		BUFPLL
		#(
			.DIVIDE        			(4),
			.ENABLE_SYNC			("TRUE")
		)
		bufpll_600
		(
			.IOCLK        			(ck600[i]),
			.LOCK         			(dbg_in[i]),
			.SERDESSTROBE 			(strobe[i]),
			.GCLK         			(ck150),
			.LOCKED       			(locked),
			.PLLIN        			(ck600raw)
		);
 
		BUFPLL
		#(
			.DIVIDE        			(4),
			.ENABLE_SYNC			("TRUE")
		)
		bufpll_600_18
		(
			.IOCLK        			(ck600_180[i]),
			.LOCK         			(dbg_in[2 + i]),
			.SERDESSTROBE 			(strobe180[i]),
			.GCLK         			(ck150),
			.LOCKED       			(locked),
			.PLLIN        			(ck600_180raw)
		);
    end
 
// CLOCKS, two
wire		[1:0]	ckp;
wire		[1:0]	ckn;
	for (i = 0; i <= 1; i = i + 1) begin: DDRO_CLKS
		OSERDES2
		#(
			.DATA_RATE_OQ			("SDR"),
			.DATA_RATE_OT   		("SDR"),
			.TRAIN_PATTERN  		(0),
			.DATA_WIDTH     		(4),
			.SERDES_MODE    		("NONE"),
			.OUTPUT_MODE    		("SINGLE_ENDED")
		)
		oserdes2_dckp
		(
			.D1         			(1'b0),
			.D2         			(1'b1),
			.D3         			(1'b0),
			.D4         			(1'b1),
			.T1         			(1'b0),
			.T2         			(1'b0),
			.T3         			(1'b0),
			.T4         			(1'b0),
			.SHIFTIN1   			(1'b1),
			.SHIFTIN2   			(1'b1),
			.SHIFTIN3   			(1'b1),
			.SHIFTIN4   			(1'b1),
			.SHIFTOUT1  			(),
			.SHIFTOUT2  			(),
			.SHIFTOUT3  			(),
			.SHIFTOUT4  			(),
			.TRAIN      			(1'b0),
			.OCE        			(1'b1),
			.CLK0       			(ck600_180[1]),
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.OQ         			(ckp[i]),
			.TQ         			(),
			.IOCE       			(strobe180[1]),
			.TCE        			(1'b1),
			.RST        			(reset)
		);
 
		OSERDES2
		#(
			.DATA_RATE_OQ			("SDR"),
			.DATA_RATE_OT   		("SDR"),
			.TRAIN_PATTERN  		(0),
			.DATA_WIDTH     		(4),
			.SERDES_MODE    		("NONE"),
			.OUTPUT_MODE    		("SINGLE_ENDED")
		)
		oserdes2_dckn
		(
			.D1         			(1'b1),
			.D2         			(1'b0),
			.D3         			(1'b1),
			.D4         			(1'b0),
			.T1         			(1'b0),
			.T2         			(1'b0),
			.T3         			(1'b0),
			.T4         			(1'b0),
			.SHIFTIN1   			(1'b1),
			.SHIFTIN2   			(1'b1),
			.SHIFTIN3   			(1'b1),
			.SHIFTIN4   			(1'b1),
			.SHIFTOUT1  			(),
			.SHIFTOUT2  			(),
			.SHIFTOUT3  			(),
			.SHIFTOUT4  			(),
			.TRAIN      			(1'b0),
			.OCE        			(1'b1),
			.CLK0       			(ck600_180[1]),
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.OQ         			(ckn[i]),
			.TQ         			(),
			.IOCE       			(strobe180[1]),
			.TCE        			(1'b1),
			.RST        			(reset)
		);
 
		OBUF obuft_ckp
		(
		   .O(dckp[i]),  
		   .I(ckp[i])
		);
 
		OBUF obuf_ckn
		(
		   .O(dckn[i]),  
		   .I(ckn[i])  
		);
    end
 
// Address, Bank address
// NB ISIM can't grok parameter arrays, hence the following sim/synth bifurcation
`ifdef XILINX_ISIM
`else
	parameter integer bank_a[15:0] = {0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1};
	parameter integer bank_ba[2:0] = {0, 1, 1};
`endif
 
	wire [15:0] wa;
	for (i = 0; i <= 15; i = i + 1) begin: DDRO_A
		OSERDES2
		#(
			.DATA_RATE_OQ			("SDR"),
			.DATA_RATE_OT   		("SDR"),
			.TRAIN_PATTERN  		(0),
			.DATA_WIDTH     		(4),
			.SERDES_MODE    		("NONE"),
			.OUTPUT_MODE    		("SINGLE_ENDED")
		)
		oserdes2_a
		(
			.D1         			(rDDR_Addr[i]),
			.D2         			(rDDR_Addr[i]),
			.D3         			(rDDR_Addr[i]),
			.D4         			(rDDR_Addr[i]),
			.T1         			(1'b0),
			.T2         			(1'b0),
			.T3         			(1'b0),
			.T4         			(1'b0),
			.SHIFTIN1   			(1'b1),
			.SHIFTIN2   			(1'b1),
			.SHIFTIN3   			(1'b1),
			.SHIFTIN4   			(1'b1),
			.SHIFTOUT1  			(),
			.SHIFTOUT2  			(),
			.SHIFTOUT3  			(),
			.SHIFTOUT4  			(),
			.TRAIN      			(1'b0),
			.OCE        			(1'b1),
`ifdef XILINX_ISIM
			.CLK0       			(ck600_180[0]),
`else
			.CLK0       			(ck600_180[bank_a[i]]),
`endif
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.OQ         			(wa[i]),
			.TQ         			(),
`ifdef XILINX_ISIM
			.IOCE       			(strobe180[0]),
`else
			.IOCE       			(strobe180[bank_a[i]]),
`endif
			.TCE        			(1'b1),
			.RST        			(reset)
		);
 
		OBUF obuf_a
		(
		   .O(da[i]),  
		   .I(wa[i])  
		);
    end
 
wire		[2:0]	wba;
	for (i = 0; i <= 2; i = i + 1) begin: DDRO_BA
		OSERDES2
		#(
			.DATA_RATE_OQ			("SDR"),
			.DATA_RATE_OT   		("SDR"),
			.TRAIN_PATTERN  		(0),
			.DATA_WIDTH     		(4),
			.SERDES_MODE    		("NONE"),
			.OUTPUT_MODE    		("SINGLE_ENDED")
		)
		oserdes2_ba
		(
			.D1         			(rDDR_BankAddr[i]),
			.D2         			(rDDR_BankAddr[i]),
			.D3         			(rDDR_BankAddr[i]),
			.D4         			(rDDR_BankAddr[i]),
			.T1         			(1'b0),
			.T2         			(1'b0),
			.T3         			(1'b0),
			.T4         			(1'b0),
			.SHIFTIN1   			(1'b1),
			.SHIFTIN2   			(1'b1),
			.SHIFTIN3   			(1'b1),
			.SHIFTIN4   			(1'b1),
			.SHIFTOUT1  			(),
			.SHIFTOUT2  			(),
			.SHIFTOUT3  			(),
			.SHIFTOUT4  			(),
			.TRAIN      			(1'b0),
			.OCE        			(1'b1),
`ifdef XILINX_ISIM
			.CLK0       			(ck600_180[0]),
`else
			.CLK0       			(ck600_180[bank_ba[i]]),
`endif
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.OQ         			(wba[i]),
			.TQ         			(),
`ifdef XILINX_ISIM
			.IOCE       			(strobe180[0]),
`else
			.IOCE       			(strobe180[bank_ba[i]]),
`endif
			.TCE        			(1'b1),
			.RST        			(reset)
		);
 
		OBUF obuf_ba
		(
		   .O(dba[i]),  
		   .I(wba[i])  
		);
    end
 
// command, ChipSelect
wire		[2:0]	wkmd;
	for (i = 0; i <= 2; i = i + 1) begin: DDRO_KMD
		OSERDES2
		#(
			.DATA_RATE_OQ			("SDR"),
			.DATA_RATE_OT   		("SDR"),
			.TRAIN_PATTERN  		(0),
			.DATA_WIDTH     		(4),
			.SERDES_MODE    		("NONE"),
			.OUTPUT_MODE    		("SINGLE_ENDED")
		)
		oserdes2_kmd
		(
			.D1         			(rDDR_Cmd[i]),	// Command for 1 cycle
			.D2         			(rDDR_Cmd[i]),
			.D3         			(1'b1),			// NOP thereafter
			.D4         			(1'b1),
			.T1         			(1'b0),
			.T2         			(1'b0),
			.T3         			(1'b0),
			.T4         			(1'b0),
			.SHIFTIN1   			(1'b1),
			.SHIFTIN2   			(1'b1),
			.SHIFTIN3   			(1'b1),
			.SHIFTIN4   			(1'b1),
			.SHIFTOUT1  			(),
			.SHIFTOUT2  			(),
			.SHIFTOUT3  			(),
			.SHIFTOUT4  			(),
			.TRAIN      			(1'b0),
			.OCE        			(1'b1),
			.CLK0       			(ck600_180[1]),
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.OQ         			(wkmd[i]),
			.TQ         			(),
			.IOCE       			(strobe180[1]),
			.TCE        			(1'b1),
			.RST        			(reset)
		);
 
		OBUF obuf_kmd
		(
		   .O(dcmd[i]),  
		   .I(wkmd[i])  
		);
    end
 
wire		[1:0]	wcs;
	for (i = 0; i <= 1; i = i + 1) begin: DDRO_CS
		OSERDES2
		#(
			.DATA_RATE_OQ			("SDR"),
			.DATA_RATE_OT   		("SDR"),
			.TRAIN_PATTERN  		(0),
			.DATA_WIDTH     		(4),
			.SERDES_MODE    		("NONE"),
			.OUTPUT_MODE    		("SINGLE_ENDED")
		)
		oserdes2_cs
		(
			.D1         			(rDDR_CS_n[i]),	
			.D2         			(rDDR_CS_n[i]),
			.D3         			(rDDR_CS_n[i]),		
			.D4         			(rDDR_CS_n[i]),
			.T1         			(1'b0),
			.T2         			(1'b0),
			.T3         			(1'b0),
			.T4         			(1'b0),
			.SHIFTIN1   			(1'b1),
			.SHIFTIN2   			(1'b1),
			.SHIFTIN3   			(1'b1),
			.SHIFTIN4   			(1'b1),
			.SHIFTOUT1  			(),
			.SHIFTOUT2  			(),
			.SHIFTOUT3  			(),
			.SHIFTOUT4  			(),
			.TRAIN      			(1'b0),
			.OCE        			(1'b1),
			.CLK0       			(ck600_180[1]),
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.OQ         			(wcs[i]),
			.TQ         			(),
			.IOCE       			(strobe180[1]),
			.TCE        			(1'b1),
			.RST        			(reset)
		);
 
		OBUF obuf_cs
		(
		   .O(dcs[i]),  
		   .I(wcs[i])  
		);
    end
 
// CKE, ODT
wire		[1:0]	wcke;
	for (i = 0; i <= 1; i = i + 1) begin: DDRO_CKE
		OSERDES2
		#(
			.DATA_RATE_OQ			("SDR"),
			.DATA_RATE_OT   		("SDR"),
			.TRAIN_PATTERN  		(0),
			.DATA_WIDTH     		(4),
			.SERDES_MODE    		("NONE"),
			.OUTPUT_MODE    		("SINGLE_ENDED")
		)
		oserdes2_cke
		(
			.D1         			(rDDR_CKE[i]),	
			.D2         			(rDDR_CKE[i]),
			.D3         			(rDDR_CKE[i]),		
			.D4         			(rDDR_CKE[i]),
			.T1         			(1'b0),
			.T2         			(1'b0),
			.T3         			(1'b0),
			.T4         			(1'b0),
			.SHIFTIN1   			(1'b1),
			.SHIFTIN2   			(1'b1),
			.SHIFTIN3   			(1'b1),
			.SHIFTIN4   			(1'b1),
			.SHIFTOUT1  			(),
			.SHIFTOUT2  			(),
			.SHIFTOUT3  			(),
			.SHIFTOUT4  			(),
			.TRAIN      			(1'b0),
			.OCE        			(1'b1),
			.CLK0       			(ck600_180[0]),
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.OQ         			(wcke[i]),
			.TQ         			(),
			.IOCE       			(strobe180[0]),
			.TCE        			(1'b1),
			.RST        			(reset)
		);
 
		OBUF obuf_cke
		(
		   .O(dce[i]),  
		   .I(wcke[i])  
		);
    end
 
wire		[1:0]	wodt;
	for (i = 0; i <= 1; i = i + 1) begin: DDRO_ODT
		OSERDES2
		#(
			.DATA_RATE_OQ			("SDR"),
			.DATA_RATE_OT   		("SDR"),
			.TRAIN_PATTERN  		(0),
			.DATA_WIDTH     		(4),
			.SERDES_MODE    		("NONE"),
			.OUTPUT_MODE    		("SINGLE_ENDED")
		)
		oserdes2_odt
		(
			.D1         			(rDDR_ODT[i]),	
			.D2         			(rDDR_ODT[i]),
			.D3         			(rDDR_ODT[i]),		
			.D4         			(rDDR_ODT[i]),
			.T1         			(1'b0),
			.T2         			(1'b0),
			.T3         			(1'b0),
			.T4         			(1'b0),
			.SHIFTIN1   			(1'b1),
			.SHIFTIN2   			(1'b1),
			.SHIFTIN3   			(1'b1),
			.SHIFTIN4   			(1'b1),
			.SHIFTOUT1  			(),
			.SHIFTOUT2  			(),
			.SHIFTOUT3  			(),
			.SHIFTOUT4  			(),
			.TRAIN      			(1'b0),
			.OCE        			(1'b1),
			.CLK0       			(ck600_180[1]),
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.OQ         			(wodt[i]),
			.TQ         			(),
			.IOCE       			(strobe180[1]),
			.TCE        			(1'b1),
			.RST        			(reset)
		);
 
		OBUF obuf_odt
		(
		   .O(dodt[i]),  
		   .I(wodt[i])  
		);
    end
 
// DQ STROBES, 8 differential pairs
wire		[7:0]	dqso;
wire		[7:0]	dqso_d;
wire		[7:0]	dqst;
wire		[7:0]	dqst_d;
wire		[7:0]	dqson;
wire		[7:0]	dqson_d;
wire		[7:0]	dqstn;
wire		[7:0]	dqstn_d;
wire		[7:0]	dummy;
wire		[7:0]	dummyp;
wire		[7:0]	dummyn;
	for (i = 0; i <= 7; i = i + 1) begin: DDRIO_DQS
		OSERDES2
		#(
			.DATA_RATE_OQ			("SDR"),
			.DATA_RATE_OT   		("SDR"),
			.TRAIN_PATTERN  		(0),
			.DATA_WIDTH     		(4),
			.SERDES_MODE    		("NONE"),
			.OUTPUT_MODE    		("SINGLE_ENDED")
		)
		oserdes2_dqsp
		(
			.D1         			(1'b0),
			.D2         			(1'b1),
			.D3         			(1'b0),
			.D4         			(1'b1),
			.T1         			(READ),
			.T2         			(READ),
			.T3         			(READ),
			.T4         			(READ),
			.SHIFTIN1   			(1'b1),
			.SHIFTIN2   			(1'b1),
			.SHIFTIN3   			(1'b1),
			.SHIFTIN4   			(1'b1),
			.SHIFTOUT1  			(),
			.SHIFTOUT2  			(),
			.SHIFTOUT3  			(),
			.SHIFTOUT4  			(),
			.TRAIN      			(1'b0),
			.OCE        			(1'b1),
			.CLK0       			(ck600_180[i >> 2]),
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.OQ         			(dqso[i]),
			.TQ         			(dqst[i]),
			.IOCE       			(strobe180[i >> 2]),
			.TCE        			(1'b1),
			.RST        			(reset)
		);
 
		OSERDES2
		#(
			.DATA_RATE_OQ			("SDR"),
			.DATA_RATE_OT   		("SDR"),
			.TRAIN_PATTERN  		(0),
			.DATA_WIDTH     		(4),
			.SERDES_MODE    		("NONE"),
			.OUTPUT_MODE    		("SINGLE_ENDED")
		)
		oserdes2_dqsn
		(
			.D1         			(1'b1),
			.D2         			(1'b0),
			.D3         			(1'b1),
			.D4         			(1'b0),
			.T1         			(READ),
			.T2         			(READ),
			.T3         			(READ),
			.T4         			(READ),
			.SHIFTIN1   			(1'b1),
			.SHIFTIN2   			(1'b1),
			.SHIFTIN3   			(1'b1),
			.SHIFTIN4   			(1'b1),
			.SHIFTOUT1  			(),
			.SHIFTOUT2  			(),
			.SHIFTOUT3  			(),
			.SHIFTOUT4  			(),
			.TRAIN      			(1'b0),
			.OCE        			(1'b1),
			.CLK0       			(ck600_180[i >> 2]),
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.OQ         			(dqson[i]),
			.TQ         			(dqstn[i]),
			.IOCE       			(strobe180[i >> 2]),
			.TCE        			(1'b1),
			.RST        			(reset)
		);
 
		IODELAY2
		#(
			.DATA_RATE              ("SDR"),
			.ODELAY_VALUE           (LVL_WPHASE + i * LVL_WSLOPE),
			.IDELAY_VALUE           (LVL_WPHASE + i * LVL_WSLOPE),
	       	.IDELAY_TYPE			("FIXED"),
			.DELAY_SRC              ("IO")
		)
		iodelay2_dqsp
		(
			.ODATAIN                (dqso[i]),
			.DOUT                   (dqso_d[i]),
 
			.T                      (dqst[i]),
			.TOUT                   (dqst_d[i]),
 
			.IDATAIN                (dummyp[i])									
		);
 
		IODELAY2
		#(
			.DATA_RATE              ("SDR"),
			.ODELAY_VALUE           (LVL_WPHASE + i * LVL_WSLOPE),
			.IDELAY_VALUE           (LVL_WPHASE + i * LVL_WSLOPE),
	       	.IDELAY_TYPE			("FIXED"),
			.DELAY_SRC              ("IO")
		)
		iodelay2_dqsn
		(
			.ODATAIN                (dqson[i]),
			.DOUT                   (dqson_d[i]),
 
			.T                      (dqstn[i]),
			.TOUT                   (dqstn_d[i]),
 
			.IDATAIN                (dummyn[i])						
		);
 
		IOBUF iobuf_dqsp
		(
		   .O(dummyp[i]),  
		   .IO(dqsp[i]),
		   .I(dqso_d[i]),  
		   .T(dqst_d[i])
		);
 
		IOBUF iobuf_dqsn
		(
		   .O(dummyn[i]),  
		   .IO(dqsn[i]),
		   .I(dqson_d[i]),  
		   .T(dqstn_d[i])
		);
 
	end
 
// DATA MASKS, 8
wire		[7:0]	dmo;
wire		[7:0]	dmo_d;
wire		[7:0]	dmt;
wire		[7:0]	dmt_d;   	
	for (i = 0; i <= 7; i = i + 1) begin: DDRO_DM
		OSERDES2
		#(
			.DATA_RATE_OQ			("SDR"),
			.DATA_RATE_OT   		("SDR"),
			.TRAIN_PATTERN  		(0),
			.DATA_WIDTH     		(4),
			.SERDES_MODE    		("NONE"),
			.OUTPUT_MODE    		("SINGLE_ENDED")
		)
		oserdes2_dm
		(
			.D1         			(rSmsk[i]),
			.D2         			(rSmsk[i + 8]),
			.D3         			(rSmsk[i + 16]),
			.D4         			(rSmsk[i + 24]),
			.T1         			(READ),
			.T2         			(READ),
			.T3         			(READ),
			.T4         			(READ),
			.SHIFTIN1   			(1'b1),
			.SHIFTIN2   			(1'b1),
			.SHIFTIN3   			(1'b1),
			.SHIFTIN4   			(1'b1),
			.SHIFTOUT1  			(),
			.SHIFTOUT2  			(),
			.SHIFTOUT3  			(),
			.SHIFTOUT4  			(),
			.TRAIN      			(1'b0),
			.OCE        			(1'b1),
			.CLK0       			(ck600[i >> 2]),
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.OQ         			(dmo[i]),
			.TQ         			(dmt[i]),
			.IOCE       			(strobe[i >> 2]),
			.TCE        			(1'b1),
			.RST        			(reset)
		);
 
		IODELAY2
		#(
			.DATA_RATE              ("SDR"),
			.ODELAY_VALUE           (LVL_WPHASE + i * LVL_WSLOPE),
			.IDELAY_VALUE           (LVL_WPHASE + i * LVL_WSLOPE),
	       	.IDELAY_TYPE			("FIXED"),
			.DELAY_SRC              ("IO")
		)
		iodelay2_dm
		(
			.ODATAIN                (dmo[i]),
			.DOUT                   (dmo_d[i]),
 
			.T                      (dmt[i]),
			.TOUT                   (dmt_d[i]),
 
			.IDATAIN                (dummy[i])			
		);
 
		IOBUF iobuf_dm
		(
			.O(dummy[i]),
		   	.IO(ddm[i]),
		   	.I(dmo_d[i]),  
		   	.T(dmt_d[i])
		);
    	end
 
// DQ LINES, 64
wire		[63:0]	dqo;
wire		[63:0]	dqo_d;
wire		[63:0]	dqt;
wire		[63:0]	dqt_d;   	
wire		[63:0]	dqi;
wire		[63:0]	dqi_d;   	
	for (i = 0; i <= 63; i = i + 1) begin: DDRIO_DQ
		OSERDES2
		#(
			.DATA_RATE_OQ			("SDR"),
			.DATA_RATE_OT   		("SDR"),
			.TRAIN_PATTERN  		(0),
			.DATA_WIDTH     		(4),
			.SERDES_MODE    		("NONE"),
			.OUTPUT_MODE    		("SINGLE_ENDED")
		)
		oserdes2_dq
		(
			.D1         			(rWdat[i]),
			.D2         			(rWdat[i + 64]),
			.D3         			(rWdat[i + 128]),
			.D4         			(rWdat[i + 192]),
			.T1         			(READ),
			.T2         			(READ),
			.T3         			(READ),
			.T4         			(READ),
			.SHIFTIN1   			(1'b1),
			.SHIFTIN2   			(1'b1),
			.SHIFTIN3   			(1'b1),
			.SHIFTIN4   			(1'b1),
			.SHIFTOUT1  			(),
			.SHIFTOUT2  			(),
			.SHIFTOUT3  			(),
			.SHIFTOUT4  			(),
			.TRAIN      			(1'b0),
			.OCE        			(1'b1),
			.CLK0       			(ck600[i >> 5]),
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.OQ         			(dqo[i]),
			.TQ         			(dqt[i]),
			.IOCE       			(strobe[i >> 5]),
			.TCE        			(1'b1),
			.RST        			(reset)
		);
 
		IODELAY2
		#(
			.DATA_RATE              ("SDR"),
			.IDELAY_VALUE           (0),
			.ODELAY_VALUE           (LVL_WPHASE + ((i * LVL_WSLOPE) >> 3)),
	       	.IDELAY_TYPE			("VARIABLE_FROM_ZERO"),
			.DELAY_SRC              ("IO")
		)
		iodelay2_dq
		(
			.ODATAIN                (dqo[i]),
			.DOUT                   (dqo_d[i]),
 
			.T                      (dqt[i]),
			.TOUT                   (dqt_d[i]),
 
			.IDATAIN                (dqi[i]),
			.DATAOUT                (dqi_d[i]),
 
			.CE						(rChgDelay[i]),
			.INC					(rIncDelay[i]),
			.CLK					(ck150),
			.CAL					(rCalDelay2[i]),
			.RST					(rRstDelay[i]),
			.IOCLK0					(ck600[i >> 5])
		);
 
		IOBUF iobuf_dq
		(
		   	.O(dqi[i]),  
		   	.IO(ddq[i]),
		   	.I(dqo_d[i]),  
		   	.T(dqt_d[i])
		);
 
		ISERDES2
		#(
			.BITSLIP_ENABLE 		("FALSE"),
			.DATA_RATE      		("SDR"),
			.DATA_WIDTH     		(4),
			.INTERFACE_TYPE 		("RETIMED"),
			.SERDES_MODE    		("NONE")
		)
		iserdes2_dq
		(
			.Q1         			(wQ[i]),
			.Q2         			(wQ[i + 64]),
			.Q3         			(wQ[i + 128]),
			.Q4         			(wQ[i + 192]),
			.SHIFTOUT   			(),
			.INCDEC     			(),
			.VALID      			(),
			.BITSLIP    			(),
			.CE0        			(READ),
			.CLK0       			(ck600[i >> 5]),
			.CLK1       			(1'b0),
			.CLKDIV     			(ck150),
			.D          			(dqi_d[i]),
			.IOCE       			(strobe[i >> 5]),
			.RST        			(reset),
			.SHIFTIN    			(),
			.FABRICOUT  			(),
			.CFB0       			(),
			.CFB1       			(),
			.DFB        			()
		);
	end
endgenerate
 
// DDR commands
parameter	K_LMR	= 3'h0;	// Load Mode Register (Mode Register Set)
parameter	K_RFSH	= 3'h1;	// Refresh (auto or self)
parameter	K_CLOSE	= 3'h2;	// aka PRECHARGE
parameter	K_OPEN	= 3'h3;	// aka ACTIVATE
parameter	K_WRITE	= 3'h4;
parameter	K_READ	= 3'h5;
parameter	K_ZQCAL	= 3'h6;	// ZQ calibration
parameter	K_NOP	= 3'h7;
 
// States
parameter	S_INIT	= 3'h3;
parameter	S_INIT2	= 3'h5;
parameter	S_IDLE	= 3'h0;
parameter	S_READ	= 3'h1;
parameter	S_WRITE	= 3'h2;
parameter	S_PAUSE	= 3'h4;
 
// Main DDR3 timings			spec	@150MHz	
// tRAS		RAS time			37.5 ns	6 clks	open to close
// tRC		RAS cycle			50.6 ns	8 clks	open to next open
// tRP		RAS precharge		13.1 ns	2 clks	close to open
// tRRD		RAS to RAS delay	4 clks  4 clks	
// tRCD		RAS to CAS delay	13.2 ns	2 clks	
// CL		CAS Latency			5 clks	5 clks	
// tWR		Write time			15 ns	3 clks	Write finished to close issued
// tWTR		Write to Read		4 clks	4 clks	Write finished to read issued
// tRFC		Refresh command 1Gb	110ns	17 clks	Refresh command time for 1Gb parts
// tRFC		Refresh command 2Gb	160ns	24 clks	Refresh command time for 2Gb parts
// tRFC		Refresh command 4Gb	260ns	39 clks	Refresh command time for 4Gb parts
// tREFI	Refresh interval	7.8 us	1170 clks
// tDQSS	DQS start			+-0.25 clks	Time from DDR_Clk to DQS
parameter	tRFC	= 39;
parameter	tRCD	= 3;
parameter	tRP		= 3;
 
// Provide the PLL with a good long start up reset
always @ (posedge ckinb) begin
 	if (rLock[13] == 1'b1) begin
		rClrPll <= 1'b0;
	end	else begin
		rClrPll <= 1'b1;
		rLock <= rLock + 14'b1;
	end
end
 
// Hold the rest of the system in reset until the PLL has been locked for
// a good long while
always @ (posedge ckinb) begin
 	if (rStart[13] == 1'b1) begin
		rStarted <= 1'b1;
	end	else begin
		rStarted <= 1'b0;
		if (locked) begin
			rStart <= rStart + 14'b1;
		end else begin
			rStart <= 0;
		end
	end
end
 
// Add pipeline delays as required to make it easy for PAR to meet timing
always @ (posedge ck150) begin
	Q <= wQ;
	rWdat <= swdat;
	rSmsk <= smsk;
	rCalDelay2 <= rCalDelay;
end
 
always @ (posedge reset or posedge ck150)
	if (reset) begin
		rDDR_CKE <= 2'b00;
		rDDR_CS_n <= 2'b11;
		rDDR_ODT <= 2'b00;
		rDDR_Cmd <= K_NOP;
 
		STATE <= S_INIT;
		DLY <= 0;
		RTN <= 0;
		RFCNTR <= 0;
		REFRESH <= 0;
 
		ack <= 0;
 
		RPULSE0 <= 0;
		WPULSE0 <= 0;
		rChgDelay <= 64'd0;
		rIncDelay <= 64'd0;
		rCalDelay <= 64'd0;
		rRstDelay <= 64'd0;
	end	else begin
	 	if (RFCNTR[10:7] == 4'b1001) begin	// 1153/150Mhz  ~7.7us
			RFCNTR <= 0;
			REFRESH <= 1;
		end	else
			RFCNTR <= RFCNTR + 11'b1;
 
		RPULSE1 <= RPULSE0;
		RPULSE2 <= RPULSE1;
		RPULSE3 <= RPULSE2;
		RPULSE4 <= RPULSE3;
		RPULSE5 <= RPULSE4;
		RPULSE6 <= RPULSE5;
		RPULSE7 <= RPULSE6;
 
		case (dbg_out[2:0])
			3'd0: begin
				ack <= WPULSE0 | RPULSE4;
			end
 
			3'd1: begin
				ack <= WPULSE0 | RPULSE5;
			end
 
			3'd2: begin
				ack <= WPULSE0 | RPULSE6;
			end
 
			3'd3: begin
				ack <= WPULSE0 | RPULSE7;
			end
 
			3'd4: begin
				ack <= WPULSE0 | RPULSE4;
			end
 
			3'd5: begin
				ack <= WPULSE0 | RPULSE5;
			end
 
			3'd6: begin
				ack <= WPULSE0 | RPULSE6;
			end
 
			3'd7: begin
				ack <= WPULSE0 | RPULSE7;
			end
		endcase
 
		case (STATE)
			S_INIT: begin
				rDDR_CKE <= 2'b11;
				READ <= 0;
				rDDR_BankAddr <= sa[15:13];
				rDDR_Addr <= sa[31:16];
				if (swr) begin
					rDDR_CS_n <= sa[32] ? 2'b01 : 2'b10;
					STATE <= S_INIT2;
					rDDR_Cmd <= sa[10:8];
					WPULSE0 <= 1;
				end
			end
 
			S_INIT2: begin
				RTN <= sa[33] ? S_INIT : S_IDLE;
				rDDR_Cmd <= K_NOP;
				STATE <= S_PAUSE;
				DLY <= 20;
				WPULSE0 <= 0;
			end
 
			S_IDLE: begin
				READ <= 0;
				rDDR_ODT <= 2'b00;
				if (swr) begin
					rDDR_Cmd <= K_OPEN;
					STATE <= S_PAUSE;
					RTN <= S_WRITE;
					DLY <= tRCD - 1;
					rDDR_Addr <= sa[31:16];
					rDDR_BankAddr <= sa[15:13];
					rDDR_CS_n <= sa[32] ? 2'b01 : 2'b10;
				end	else if (srd) begin
					rDDR_Cmd <= K_OPEN;
					STATE <= S_PAUSE;
					RTN <= S_READ;
					DLY <= tRCD - 1;
					rDDR_Addr <= sa[31:16];
					rDDR_BankAddr <= sa[15:13];
					rDDR_CS_n <= sa[32] ? 2'b01 : 2'b10;
				end	else if (REFRESH) begin
					rDDR_Cmd <= K_RFSH;
					STATE <= S_PAUSE;
					RTN <= S_IDLE;
					DLY <= tRFC - 1;
					REFRESH <= 0;
					rDDR_CS_n <= 2'b00;
				end	else begin
					rDDR_Cmd <= K_NOP;
					rDDR_CS_n <= 2'b00;
				end
			end
 
// Address bits
// ============
//	MB	pg	Lwd	sa	Row	Col	Bnk	CS
// [X]	-	-	- 	-	-	-	-
// [X]	-	-	- 	-	-	-	-
// 	2	-	0	- 	-	-	-	-
// 	3	-  	1  [L] 	-	0	-	-
// 	4	-  	2  [L] 	-	1	-	-
// 	5	-	-	5 	-	2	-	-
// 	6	-	-	6 	-	3	-	-
// 	7	-	-	7 	-	4	-	-
// 	8	-	-	8 	-	5	-	- 	
// 	9	-	-	9 	-	6	-	- 	
// 	10	-	-	10	-	7	-	-	
// 	11	-	-	11	-	8	-	-	
// 	12	-	-	12	-	9	-	-	
// 	13	-	-	13	-  [P]	0	-
// 	14	-	-	14	-	-	1	-
// 	15	-	-	15	-	-	2	-
// 	16	-	-	16	0 	-	-	-
// 	17	-	-	17	1 	-	-	-
// 	18	-	-	18	2 	-	-	-
// 	19	-	-	19	3 	-	-	-
// 	20	-	-	20	4 	-	-	-
// 	21	-	-	21	5 	-	-	-
// 	22	-	-	22	6 	-	-	-
// 	23	-	-	23	7 	-	-	-		
// 	24	-	-	24	8 	-	-	-		
// 	25	-	-	25	9 	-	-	-		
// 	26	-	-	26	10	-	-	-
// 	27	-	-	27	11	-	-	-
// 	28	-	-	28	12	-	-	-
// 	29	-	-	29	13	-	-	-
//	[H] 0	-	30	14	-	-	-
//	[H] 1	-	31	15	-	-	-
// 	 -	2	-	32	-	-	-	0
//	 -	3	-	33	-	-	-   Extra address bit for DRAM init register space 		
 
			S_WRITE: begin
				rDDR_Cmd <= K_WRITE;
				STATE <= S_PAUSE;
				RTN <= S_IDLE;
				DLY <= 14; // CWL + 2xfer + tWR + tRP
				rDDR_Addr[10:0] <= {1'b1, sa[12:5], 2'b00};	// NB two LSBs ignored by DDR3 during WRITE
				rDDR_Addr[12] <= dbg_out[2];
				rDDR_BankAddr <= sa[15:13];
				rDDR_ODT <= sa[16] ? 2'b10 : 2'b01; // Use ODT only in one rank, otherwise 40R || 40R -> 20R
				WPULSE0 <= 1;
				if (sa[33]) begin
					rChgDelay <= rWdat[63:0];
					rIncDelay <= rWdat[127:64];
					rCalDelay <= rWdat[191:128];
					rRstDelay <= rWdat[255:192];
				end else begin
					rChgDelay <= 64'd0;
					rIncDelay <= 64'd0;
					rCalDelay <= 64'd0;
					rRstDelay <= 64'd0;
				end
			end
 
			S_READ: begin
				rDDR_Cmd <= K_READ;
				STATE <= S_PAUSE;
				RTN <= S_IDLE;
				DLY <= 10; // CL + 2xfer + 1 + tRP
				rDDR_Addr[10:0] <= {1'b1, sa[12:5], 2'b00};
				rDDR_Addr[12] <= dbg_out[2];
				rDDR_BankAddr <= sa[15:13];
				READ <= 1;
				RPULSE0 <= 1;
			end
 
			S_PAUSE: begin
				rDDR_Cmd <= K_NOP;
				DLY <= DLY - 6'b000001;
				if (DLY == 6'b000001)
					STATE <= RTN;
				else
					STATE <= S_PAUSE;
				RPULSE0 <= 0;
				WPULSE0 <= 0;
				rChgDelay <= 64'd0;
				rIncDelay <= 64'd0;
				rCalDelay <= 64'd0;
				rRstDelay <= 64'd0;
			end
		endcase
	end
 
assign srdat			= Q;
assign srdy			   	= ack;
 
assign ckouthalf	   	= ck75;
assign ckout		   	= ck150;
 
assign reset			= ~rStarted;
assign dbg_in[4]		= locked;
assign dbg_in[7:5]		= rDDR_Cmd;
 
endmodule
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2017 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.