⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 yadmc_sdram16.v

📁 基于FPGA的SDRAM控制器Verilog代码
💻 V
📖 第 1 页 / 共 2 页
字号:
/* * Yet Another Dynamic Memory Controller * Copyright (C) 2008 Sebastien Bourdeauducq - http://lekernel.net * This file is part of Milkymist. * * Milkymist is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2, 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. *//* * This is for using 16-bit wide SDR SDRAM with YADMC, * with sequential bursts of length 8. * If using DDR or other bus widths, adapt/replace this file. * Also, some parameters are hardcoded for MT48LC16M16A2 at CL2. * Review this file before using with other configurations. */module yadmc_sdram16 #(	parameter sdram_depth = 25,	parameter sdram_columndepth = 9,	parameter cache_depth = 10,		/*	 * Cache line depth is always 2 for 16-bit SDRAM:	 * burst length is 8, which means 16 bytes are transferred per burst.	 * with a cache word size of 4 bytes, this yields 4 cache words per burst.	 * Thus the depth of 2 (to make FSMs simpler, we use cache line length = burst length).	 */	parameter cache_linedepth = 2,		parameter sdram_rowdepth = sdram_depth-1-sdram_columndepth-2 /* -2 for the banks */) (	input sdram_clk,	input sdram_rst,		/* Command port */	input command_evict,	input command_refill,	output reg command_ack,	input [sdram_depth-cache_linedepth-2-1:0] evict_adr,  /* unregistered */	input [sdram_depth-cache_linedepth-2-1:0] refill_adr, /* unregistered */		/* Cache interface */	output [cache_depth+cache_linedepth-1:0] cache_adr,	output [31:0] cache_dat_o,	output reg [3:0] cache_we,	input [31:0] cache_dat_i,		/* SDRAM interface */	output reg sdram_cke,	output reg sdram_cs_n,	output reg sdram_we_n,	output reg sdram_cas_n,	output reg sdram_ras_n,	output reg [1:0] sdram_dqm,	output reg [12:0] sdram_adr,	output reg [1:0] sdram_ba,	inout [15:0] sdram_dq);/* Generate address parts *//* * The address is split as follows to help reduce the probability of row switches : * row address, then column address, then bank number. * * The three LSBs (cache_linedepth+1) of the column address are always 0, since we always use the same burst ordering. * The MSBs are from the address input, decoded as above. */wire [sdram_rowdepth-1:0] evict_row = evict_adr[sdram_depth-cache_linedepth-2-1:sdram_columndepth+2-3];wire [sdram_columndepth-1:0] evict_column = {evict_adr[sdram_columndepth+2-1-3:2], {(cache_linedepth+1){1'b0}}};wire [1:0] evict_bank = evict_adr[1:0];wire [sdram_rowdepth-1:0] refill_row = refill_adr[sdram_depth-cache_linedepth-2-1:sdram_columndepth+2-3];wire [sdram_columndepth-1:0] refill_column = {refill_adr[sdram_columndepth+2-1-3:2], {(cache_linedepth+1){1'b0}}};wire [1:0] refill_bank = refill_adr[1:0];/* Register all I/Os to keep Murphy away *//* Control signals */reg sdram_cke_r;reg sdram_cs_n_r;reg sdram_we_n_r;reg sdram_cas_n_r;reg sdram_ras_n_r;reg sdram_dqm_r;reg [1:0] sdram_ba_r;always @(posedge sdram_clk) begin	sdram_cke <= sdram_cke_r;	sdram_cs_n <= sdram_cs_n_r;	sdram_we_n <= sdram_we_n_r;	sdram_cas_n <= sdram_cas_n_r;	sdram_ras_n <= sdram_ras_n_r;	sdram_dqm <= {2{sdram_dqm_r}};	sdram_ba <= sdram_ba_r;end/* Data */reg [15:0] dq;assign sdram_dq = dq;reg sdram_dq_drive;wire [15:0] sdram_dq_out;reg [15:0] sdram_dq_in;always @(posedge sdram_clk) begin	if(sdram_dq_drive)		dq <= sdram_dq_out;	else		dq <= 16'hzzzz;	sdram_dq_in <= sdram_dq;end/* Address lines */reg adr_load_mode;reg adr_load_evictrow;reg adr_load_evictcolumn;reg adr_load_refillrow;reg adr_load_refillcolumn;reg adr_load_A10;always @(posedge sdram_clk) begin	/*	 * Mode register encoding :	 * See p. 18 of the Micron datasheet.	 * A12..A10 reserved, should be 000	 * A9       burst access, 0 = burst enabled	 * A8 ..A7  reserved, should be 00	 * A6 ..A4  CAS latency, 10 = CL2	 * A3       burst type, 0 = sequential	 * A2 ..A0  burst length, 011 = 8	 */	sdram_adr <=		 ({13{adr_load_mode  }}       & 13'b000_0_00_10_0_011)		|({13{adr_load_evictrow   }}  & {{(13-sdram_rowdepth){1'b0}}, evict_row})		|({13{adr_load_evictcolumn}}  & {{(13-sdram_columndepth){1'b0}}, evict_column})		|({13{adr_load_refillrow   }} & {{(13-sdram_rowdepth){1'b0}}, refill_row})		|({13{adr_load_refillcolumn}} & {{(13-sdram_columndepth){1'b0}}, refill_column})		|({13{adr_load_A10   }}       & 13'd1024);end/* * Various timing counters. * Check that the delays are appropriate for the particular SDRAM chip * you're using. *//* The number of clocks before we can use the SDRAM after power-up *//* This should be 100us */reg [13:0] init_counter;reg reload_init_counter;wire init_done = (init_counter == 14'b0);always @(posedge sdram_clk) begin	if(reload_init_counter)		init_counter <= 14'd12500;	else if(~init_done)		init_counter <= init_counter - 4'b1;end/* The number of clocks we must wait following a PRECHARGE ALL command */reg [2:0] prechargeall_counter;reg reload_prechargeall_counter;wire prechargeall_done = (prechargeall_counter == 3'b0);always @(posedge sdram_clk) begin	if(reload_prechargeall_counter)		prechargeall_counter <= 3'd4;	else if(~prechargeall_done)		prechargeall_counter <= prechargeall_counter - 3'b1;end/* The number of clocks we must wait following a PRECHARGE command */reg [2:0] precharge_counter;reg reload_precharge_counter;wire precharge_done = (precharge_counter == 3'b0);always @(posedge sdram_clk) begin	if(reload_precharge_counter)		precharge_counter <= 3'd4;	else if(~precharge_done)		precharge_counter <= precharge_counter - 3'b1;end/* The number of clocks we must wait following an AUTO REFRESH command */reg [3:0] autorefresh_counter;reg reload_autorefresh_counter;wire autorefresh_done = (autorefresh_counter == 4'b0);always @(posedge sdram_clk) begin	if(reload_autorefresh_counter)		autorefresh_counter <= 4'd9;	else if(~autorefresh_done)		autorefresh_counter <= autorefresh_counter - 4'b1;end/* The number of clocks we must wait following an ACTIVATE command. * This is the (in)famous CAS latency. */reg [2:0] activate_counter;reg reload_activate_counter;wire activate_done = (activate_counter == 3'b0);always @(posedge sdram_clk) begin	if(reload_activate_counter)		activate_counter <= 3'd2;	else if(~activate_done)		activate_counter <= activate_counter - 3'b1;end/* The number of clocks we have left before we must refresh one row in the SDRAM array. */reg [11:0] refresh_counter;reg reload_refresh_counter;wire needs_refresh = (refresh_counter == 12'b0);always @(posedge sdram_clk) begin	if(reload_refresh_counter)		/*		 * The period between *each* AUTO REFRESH command, in clock cycles.		 * Must be the refresh period divided by the number of cycles required		 * to refresh the entire array.		 * Typically 64ms divided by the number of rows, but check your SDRAM datasheet.		 */		refresh_counter <= 12'd740;	else if(~needs_refresh)		refresh_counter <= refresh_counter - 12'b1;end/* Keep track of the open row for each bank */reg active0;reg [sdram_rowdepth-1:0] openrow0;reg active1;reg [sdram_rowdepth-1:0] openrow1;reg active2;reg [sdram_rowdepth-1:0] openrow2;reg active3;reg [sdram_rowdepth-1:0] openrow3;reg [sdram_rowdepth-1:0] track_row;reg [1:0] track_bank;reg track_open;reg track_close;reg track_closeall;always @(posedge sdram_clk) begin	if(track_closeall) begin		active0 <= 1'b0;		active1 <= 1'b0;		active2 <= 1'b0;		active3 <= 1'b0;	end else begin		if(track_close) begin			case(track_bank)				2'b00: active0 <= 1'b0;				2'b01: active1 <= 1'b0;				2'b10: active2 <= 1'b0;				2'b11: active3 <= 1'b0;			endcase		end else if(track_open) begin			case(track_bank)				2'b00: begin					active0 <= 1'b1;					openrow0 <= track_row;				end				2'b01: begin					active1 <= 1'b1;					openrow1 <= track_row;				end				2'b10: begin					active2 <= 1'b1;					openrow2 <= track_row;				end				2'b11: begin					active3 <= 1'b1;					openrow3 <= track_row;				end			endcase		end	endendreg load_track_with_evict;reg load_track_with_refill;always @(posedge sdram_clk) begin	if(load_track_with_evict) begin		track_row <= evict_row;		track_bank <= evict_bank;	end	if(load_track_with_refill) begin		track_row <= refill_row;		track_bank <= refill_bank;	endend/* Check if we need to activate another row. * We add registers to improve timing (this is the critical path). */wire evict_needs_rowswitch =	 ((evict_bank == 2'b00) & ((openrow0 != evict_row) | ~active0))	|((evict_bank == 2'b01) & ((openrow1 != evict_row) | ~active1))	|((evict_bank == 2'b10) & ((openrow2 != evict_row) | ~active2))	|((evict_bank == 2'b11) & ((openrow3 != evict_row) | ~active3));reg evict_needs_rowswitch_r;always @(posedge sdram_clk) evict_needs_rowswitch_r <= evict_needs_rowswitch;wire refill_needs_rowswitch =	 ((refill_bank == 2'b00) & ((openrow0 != refill_row) | ~active0))	|((refill_bank == 2'b01) & ((openrow1 != refill_row) | ~active1))	|((refill_bank == 2'b10) & ((openrow2 != refill_row) | ~active2))	|((refill_bank == 2'b11) & ((openrow3 != refill_row) | ~active3));reg refill_needs_rowswitch_r;always @(posedge sdram_clk) refill_needs_rowswitch_r <= refill_needs_rowswitch;/* Burst counter */reg [3:0] burst_counter;reg reload_burst_counter;wire burst_finished = burst_counter[3];wire burst_last = burst_counter[0] & burst_counter[1] & burst_counter[2];reg [3:0] next_burst_counter;always @(reload_burst_counter or burst_finished or burst_counter) begin	if(reload_burst_counter)		next_burst_counter <= 4'b0000;	else if(~burst_finished)		next_burst_counter <= burst_counter + 1'b1;	else		next_burst_counter <= burst_counter;endalways @(posedge sdram_clk) burst_counter <= next_burst_counter;/* Generate cache addresses */reg load_cache_msb_evict;reg load_cache_msb_refill;reg [cache_depth-1:0] cache_adr_msb;always @(posedge sdram_clk) begin	if(load_cache_msb_evict) begin		$display("Reads from the cache begin at address %h", evict_adr[cache_depth-1:0]);		cache_adr_msb <= evict_adr[cache_depth-1:0];	end else if(load_cache_msb_refill) begin		$display("Writes to the cache begin at address %h", refill_adr[cache_depth-1:0]);		cache_adr_msb <= refill_adr[cache_depth-1:0];	endendassign cache_adr = {cache_adr_msb, next_burst_counter[2:1]};/* Cache data */assign cache_dat_o = {sdram_dq_in, sdram_dq_in};assign sdram_dq_out = burst_counter[0] ? cache_dat_i[15:0] : cache_dat_i[31:16];/* FSM that runs everything */always @(posedge sdram_clk) begin	if(command_evict) begin		$display("EVICT  addr %b", evict_adr);		$display("REFILL addr %b", refill_adr);	end	if(command_refill) $display("REFILL addr %b", refill_adr);	if(command_ack)    $display("ACK    addr %b", refill_adr);endreg command_evict_pending;reg command_refill_pending;always @(posedge sdram_clk) begin	if(sdram_rst | command_ack) begin		command_evict_pending <= 1'b0;		command_refill_pending <= 1'b0;	end else begin		if(command_evict) command_evict_pending <= 1'b1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -