OpenCores
URL https://opencores.org/ocsvn/m1_core/m1_core/trunk

Subversion Repositories m1_core

[/] [m1_core/] [trunk/] [hdl/] [rtl/] [wb_ddr_ctrl/] [ddr_ctrl.v] - Rev 54

Compare with Previous | Blame | View Log

//----------------------------------------------------------------------------
// Pipelined, asyncronous DDR Controller
//
// (c) Joerg Bornschein (<jb@capsec.org>)
//----------------------------------------------------------------------------
`include "ddr_include.v"
 
module ddr_ctrl 
#(
	parameter phase_shift  = 0,
	parameter clk_multiply = 12,
	parameter clk_divide   = 5,
	parameter wait200_init = 26
) (
	input                   clk, 
	input                   reset,
	// Temporary DCM control input
	input  [2:0]            rot,     // XXX
	//  DDR ports
	output                  ddr_clk,
	output                  ddr_clk_n,
	input                   ddr_clk_fb,
	output                  ddr_ras_n,
	output                  ddr_cas_n,
	output                  ddr_we_n,
	output                  ddr_cke,
	output                  ddr_cs_n,
	output [  `A_RNG]       ddr_a,
	output [ `BA_RNG]       ddr_ba,
	inout  [ `DQ_RNG]       ddr_dq,
	inout  [`DQS_RNG]       ddr_dqs,
	output [ `DM_RNG]       ddr_dm,
	// FML (FastMemoryLink)
	output reg              fml_done,
	input  [`FML_ADR_RNG]   fml_adr,
	input                   fml_rd,
	input                   fml_wr,
	input  [`FML_DAT_RNG]   fml_wdat,
	input  [`FML_BE_RNG]    fml_wbe,
	input                   fml_wnext,
	output                  fml_rempty,
	input                   fml_rnext,
	output [`FML_DAT_RNG]   fml_rdat
);
 
wire [ `DQ_RNG]       ddr_dq_i,  ddr_dq_o;
wire [`DQS_RNG]       ddr_dqs_i, ddr_dqs_o;
wire                  ddr_dqs_oe;
 
//----------------------------------------------------------------------------
// clock generator
//----------------------------------------------------------------------------
wire clk_locked;
wire write_clk, write_clk90;
wire read_clk;
 
wire reset_int = reset | ~clk_locked;
 
ddr_clkgen #(
	.phase_shift(  phase_shift  ),
	.clk_multiply( clk_multiply ),
	.clk_divide(   clk_divide   )
) clkgen (
	.clk(             clk            ),
	.reset(           reset          ),
	.locked(          clk_locked     ),
	// ddr-clk 
	.write_clk(       write_clk      ),
	.write_clk90(     write_clk90    ),
	// ddr-read-clk
	.ddr_clk_fb(      ddr_clk_fb     ),
	.read_clk(        read_clk       ),
	// phase shift control
	.rot(             rot            )      // XXX
);
 
//----------------------------------------------------------------------------
// async_fifos (cmd, wdata, rdata)
//----------------------------------------------------------------------------
wire                  cba_fifo_full;
reg  [`CBA_RNG]       cba_fifo_din;
reg                   cba_fifo_we;
 
wire                  wfifo_full;
wire  [`WFIFO_RNG]    wfifo_din;
wire                  wfifo_we;
 
wire [`RFIFO_RNG]     rfifo_dout;
wire                  rfifo_empty;
wire                  rfifo_next;
 
assign wfifo_din  = { ~fml_wbe, fml_wdat };
assign wfifo_we   = fml_wnext;
 
assign fml_rdat   = rfifo_dout;
assign fml_rempty = rfifo_empty;
assign rfifo_next = fml_rnext;
 
//----------------------------------------------------------------------------
// High-speed cmd, write and read datapath
//----------------------------------------------------------------------------
ddr_wpath wpath0 (
	.clk(         write_clk    ),
	.clk90(       write_clk90  ),
	.reset(       reset_int    ),
	// CBA async fifo
	.cba_clk(     clk           ),
	.cba_din(     cba_fifo_din  ),
	.cba_wr(      cba_fifo_we   ),
	.cba_full(    cba_fifo_full ),
	// WDATA async fifo
	.wdata_clk(   clk           ),
	.wdata_din(   wfifo_din     ),
	.wdata_wr(    wfifo_we      ),
	.wdata_full(  wfifo_full    ),
	//
	.sample(     sample      ), 
	// DDR
	.ddr_clk(     ddr_clk    ),
	.ddr_clk_n(   ddr_clk_n  ),
	.ddr_ras_n(   ddr_ras_n  ),
	.ddr_cas_n(   ddr_cas_n  ),
	.ddr_we_n(    ddr_we_n   ),
	.ddr_a(       ddr_a      ),
	.ddr_ba(      ddr_ba     ),
	.ddr_dm(      ddr_dm     ),
	.ddr_dq(      ddr_dq_o   ),
	.ddr_dqs(     ddr_dqs_o  ),
	.ddr_dqs_oe(  ddr_dqs_oe )
);
 
ddr_rpath rpath0 (
	.clk(         read_clk   ),
	.reset(       reset_int  ),
	// 
	.sample(      sample     ),
	//
	.rfifo_clk(   clk        ),
	.rfifo_empty( rfifo_empty),
	.rfifo_dout(  rfifo_dout ),
	.rfifo_next(  rfifo_next ),
	// DDR
	.ddr_dq(      ddr_dq_i   ),
	.ddr_dqs(     ddr_dqs_i  )
);
 
//----------------------------------------------------------------------------
// 7.8 us pulse generator
//----------------------------------------------------------------------------
wire pulse78;
reg  ar_req;
reg  ar_done;
 
ddr_pulse78 pulse79_gen (
	.clk(     clk        ),
	.reset(   reset_int  ),
	.pulse78( pulse78    )
);
 
//----------------------------------------------------------------------------
// Auto Refresh request generator
//----------------------------------------------------------------------------
always @(posedge clk)
	if (reset_int)
		ar_req <= 0;
	else
		ar_req <= pulse78 | (ar_req & ~ar_done);
 
// operations we might want to submit
wire [`CBA_RNG] ar_pre_cba;
wire [`CBA_RNG] ar_ar_cba;
 
assign ar_pre_cba   = { `DDR_CMD_PRE, 2'b00, 13'b1111111111111 };
assign ar_ar_cba    = { `DDR_CMD_AR,  2'b00, 13'b0000000000000 };
 
//----------------------------------------------------------------------------
// Init & management
//----------------------------------------------------------------------------
wire                 init_req;
reg                  init_ack;
wire [`CBA_RNG]      init_cba;
wire                 init_done;
wire                 wait200;
 
ddr_init #(
	.wait200_init( wait200_init )
) init (
	.clk(         clk         ),
	.reset(       reset_int   ),
	.pulse78(     pulse78     ),
	.wait200(     wait200     ),
	.init_done(   init_done   ),
	//
	.mngt_req(    init_req    ),
	.mngt_ack(    init_ack    ),
	.mngt_cba(    init_cba    )
);
 
//----------------------------------------------------------------------------
// Active Bank Information 
//----------------------------------------------------------------------------
reg [`ROW_RNG] ba_row [3:0];
reg [3:0]      ba_active;
 
//----------------------------------------------------------------------------
// FML decoding
//----------------------------------------------------------------------------
wire [`FML_ADR_BA_RNG]    fml_ba  = fml_adr[`FML_ADR_BA_RNG];
wire [`FML_ADR_ROW_RNG]   fml_row = fml_adr[`FML_ADR_ROW_RNG];
wire [`FML_ADR_COL_RNG]   fml_col = fml_adr[`FML_ADR_COL_RNG];
 
wire [`FML_ADR_ROW_RNG]   fml_cur_row;   // current active row in sel. bank
assign fml_cur_row    = ba_row[fml_ba];
 
wire   fml_row_active;  // is row in selected ba really active?
assign fml_row_active = ba_active[fml_ba]; 
 
 
/*
wire   fml_row_active = (fml_ba == 0) ? ba0_active :     // is row in selected
                        (fml_ba == 1) ? ba1_active :     // bank really active?
                        (fml_ba == 2) ? ba2_active :
                                        ba3_active ;
*/
 
// request operation iff correct bank is active
wire fml_req       = fml_rd | fml_wr;
wire fml_row_match = (fml_row == fml_cur_row) & fml_row_active;
wire fml_pre_req   = fml_req & ~fml_row_match & fml_row_active;
wire fml_act_req   = fml_req & ~fml_row_active;
wire fml_read_req  = fml_rd  &  fml_row_match & ~fml_done;
wire fml_write_req = fml_wr  &  fml_row_match & ~fml_done;
 
// actual operations we might want to submit
wire [`CBA_RNG] fml_pre_cba;
wire [`CBA_RNG] fml_act_cba;
wire [`CBA_RNG] fml_read_cba;
wire [`CBA_RNG] fml_write_cba;
 
assign fml_pre_cba   = { `DDR_CMD_PRE,   fml_ba, 13'b0  };
assign fml_act_cba   = { `DDR_CMD_ACT,   fml_ba, fml_row };
assign fml_read_cba  = { `DDR_CMD_READ,  fml_ba, {3'b000}, fml_col, {3'b000} };
assign fml_write_cba = { `DDR_CMD_WRITE, fml_ba, {3'b000}, fml_col, {3'b000} };
 
//----------------------------------------------------------------------------
// Schedule and issue commands
//----------------------------------------------------------------------------
 
parameter s_init      = 0;
parameter s_idle      = 1;
parameter s_ar        = 2;
parameter s_reading   = 3;
 
reg [1:0] state;
 
always @(posedge clk)
begin
	if (reset_int) begin
		state        <= s_init;
		ba_active    <= 0;
		ba_row[0]    <= 0;
		ba_row[1]    <= 0;
		ba_row[2]    <= 0;
		ba_row[3]    <= 0;
 
		fml_done     <= 0;
		init_ack     <= 0;
		cba_fifo_we  <= 0;
		ar_done      <= 0;
	end else begin
		fml_done     <= 0;
		init_ack     <= 0;
		cba_fifo_we  <= 0;
		ar_done      <= 0;
 
		case (state)
			s_init: begin
				if (init_done)
					state <= s_idle;
 
				if (init_req & ~cba_fifo_full) begin
					cba_fifo_we       <= 1;
					cba_fifo_din      <= init_cba;
					init_ack          <= 1;
				end
			end
			s_idle: begin
				if (fml_read_req & ~cba_fifo_full) begin
					cba_fifo_we       <= 1;
					cba_fifo_din      <= fml_read_cba;
					fml_done          <= 1;
				end else if (fml_write_req & ~cba_fifo_full) begin
					cba_fifo_we       <= 1;
					cba_fifo_din      <= fml_write_cba;
					fml_done          <= 1;
				end else if (ar_req & ~cba_fifo_full) begin
					cba_fifo_we       <= 1;
					cba_fifo_din      <= ar_pre_cba;
					ar_done           <= 1;
					ba_active         <= 'b0;
					state             <= s_ar;
				end else if (fml_pre_req & ~cba_fifo_full) begin
					cba_fifo_we       <= 1;
					cba_fifo_din      <= fml_pre_cba;
					ba_active[fml_ba] <= 0;
				end else if (fml_act_req & ~cba_fifo_full) begin
					cba_fifo_we       <= 1;
					cba_fifo_din      <= fml_act_cba;
					ba_active[fml_ba] <= 1;
					ba_row[fml_ba]    <= fml_row;
				end
			end
			s_ar: begin
				if (~cba_fifo_full) begin
					cba_fifo_we       <= 1;
					cba_fifo_din      <= ar_ar_cba;
					state             <= s_idle;
				end
			end
		endcase
	end
end
 
//----------------------------------------------------------------------------
// Demux dqs and dq
//----------------------------------------------------------------------------
assign ddr_cke   = ~wait200;     // bring up CKE as soon 200us wait is finished
 
assign ddr_dqs = ddr_dqs_oe!=1'b0 ? ddr_dqs_o : 'bz;
assign ddr_dq  = ddr_dqs_oe!=1'b0 ? ddr_dq_o  : 'bz;
 
assign ddr_dqs_i = ddr_dqs;
assign ddr_dq_i  = ddr_dq;
 
assign ddr_cs_n = 0;
 
endmodule
 
// vim: set ts=4
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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