1736 lines
41 KiB
Verilog
1736 lines
41 KiB
Verilog
/////////////////////////////////////////////////////////////////////
|
|
//// ////
|
|
//// WISHBONE Memory Controller Main Timing Block ////
|
|
//// ////
|
|
//// ////
|
|
//// Author: Rudolf Usselmann ////
|
|
//// rudi@asics.ws ////
|
|
//// ////
|
|
//// ////
|
|
//// Downloaded from: http://www.opencores.org/cores/mem_ctrl/ ////
|
|
//// ////
|
|
/////////////////////////////////////////////////////////////////////
|
|
//// ////
|
|
//// Copyright (C) 2000-2002 Rudolf Usselmann ////
|
|
//// www.asics.ws ////
|
|
//// rudi@asics.ws ////
|
|
//// ////
|
|
//// This source file may be used and distributed without ////
|
|
//// restriction provided that this copyright statement is not ////
|
|
//// removed from the file and that any derivative work contains ////
|
|
//// the original copyright notice and the associated disclaimer.////
|
|
//// ////
|
|
//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
|
|
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
|
|
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
|
|
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
|
|
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ////
|
|
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ////
|
|
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ////
|
|
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ////
|
|
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ////
|
|
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ////
|
|
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ////
|
|
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ////
|
|
//// POSSIBILITY OF SUCH DAMAGE. ////
|
|
//// ////
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
// CVS Log
|
|
//
|
|
// $Id: mc_timing.v,v 1.8 2002/01/21 13:08:52 rudi Exp $
|
|
//
|
|
// $Date: 2002/01/21 13:08:52 $
|
|
// $Revision: 1.8 $
|
|
// $Author: rudi $
|
|
// $Locker: $
|
|
// $State: Exp $
|
|
//
|
|
// Change History:
|
|
// $Log: mc_timing.v,v $
|
|
// Revision 1.8 2002/01/21 13:08:52 rudi
|
|
//
|
|
// Fixed several minor bugs, cleaned up the code further ...
|
|
//
|
|
// Revision 1.7 2001/12/21 05:09:30 rudi
|
|
//
|
|
// - Fixed combinatorial loops in synthesis
|
|
// - Fixed byte select bug
|
|
//
|
|
// Revision 1.6 2001/12/11 02:47:19 rudi
|
|
//
|
|
// - Made some changes not to expect clock during reset ...
|
|
//
|
|
// Revision 1.5 2001/11/29 02:16:28 rudi
|
|
//
|
|
//
|
|
// - More Synthesis cleanup, mostly for speed
|
|
// - Several bug fixes
|
|
// - Changed code to avoid auto-precharge and
|
|
// burst-terminate combinations (apparently illegal ?)
|
|
// Now we will do a manual precharge ...
|
|
//
|
|
// Revision 1.4 2001/09/24 00:38:21 rudi
|
|
//
|
|
// Changed Reset to be active high and async.
|
|
//
|
|
// Revision 1.3 2001/09/02 02:28:28 rudi
|
|
//
|
|
// Many fixes for minor bugs that showed up in gate level simulations.
|
|
//
|
|
// Revision 1.2 2001/08/10 08:16:21 rudi
|
|
//
|
|
// - Changed IO names to be more clear.
|
|
// - Uniquifyed define names to be core specific.
|
|
// - Removed "Refresh Early" configuration
|
|
//
|
|
// Revision 1.1 2001/07/29 07:34:41 rudi
|
|
//
|
|
//
|
|
// 1) Changed Directory Structure
|
|
// 2) Fixed several minor bugs
|
|
//
|
|
// Revision 1.4 2001/06/14 01:57:37 rudi
|
|
//
|
|
//
|
|
// Fixed a potential bug in a corner case situation where the TMS register
|
|
// does not propegate properly during initialisation.
|
|
//
|
|
// Revision 1.3 2001/06/12 15:19:49 rudi
|
|
//
|
|
//
|
|
// Minor changes after running lint, and a small bug fix reading csr and ba_mask registers.
|
|
//
|
|
// Revision 1.2 2001/06/03 11:37:17 rudi
|
|
//
|
|
//
|
|
// 1) Fixed Chip Select Mask Register
|
|
// - Power On Value is now all ones
|
|
// - Comparison Logic is now correct
|
|
//
|
|
// 2) All resets are now asynchronous
|
|
//
|
|
// 3) Converted Power On Delay to an configurable item
|
|
//
|
|
// 4) Added reset to Chip Select Output Registers
|
|
//
|
|
// 5) Forcing all outputs to Hi-Z state during reset
|
|
//
|
|
// Revision 1.1.1.1 2001/05/13 09:39:44 rudi
|
|
// Created Directory Structure
|
|
//
|
|
//
|
|
//
|
|
//
|
|
|
|
`include "mc_defines.v"
|
|
|
|
module mc_timing(clk, rst,
|
|
|
|
// Wishbone Interface
|
|
wb_cyc_i, wb_stb_i, wb_we_i,
|
|
wb_read_go, wb_write_go, wb_first, wb_wait, mem_ack,
|
|
err,
|
|
|
|
// Suspend/Resume Interface
|
|
susp_req, resume_req, suspended, susp_sel,
|
|
|
|
// Memory Interface
|
|
mc_clk, data_oe, oe_, we_, cas_, ras_, cke_,
|
|
cs_en, wb_cycle, wr_cycle,
|
|
mc_br, mc_bg, mc_adsc, mc_adv,
|
|
mc_c_oe, mc_ack,
|
|
not_mem_cyc,
|
|
|
|
// Register File Interface
|
|
csc, tms, cs, lmr_req, lmr_ack, cs_le_d, cs_le,
|
|
|
|
// Address Select Signals
|
|
cmd_a10, row_sel, next_adr, page_size,
|
|
|
|
// OBCT Signals
|
|
bank_set, bank_clr, bank_clr_all, bank_open, any_bank_open, row_same,
|
|
|
|
// Data path Controller Signals
|
|
dv, pack_le0, pack_le1, pack_le2, par_err,
|
|
|
|
// Refresh Counter Signals
|
|
rfr_req, rfr_ack,
|
|
|
|
// Initialize Request & Ack
|
|
init_req, init_ack
|
|
);
|
|
|
|
input clk;
|
|
input rst;
|
|
|
|
// Wishbone Interface
|
|
input wb_cyc_i, wb_stb_i, wb_we_i;
|
|
input wb_read_go;
|
|
input wb_write_go;
|
|
input wb_first;
|
|
input wb_wait;
|
|
output mem_ack;
|
|
output err;
|
|
|
|
// Suspend/Resume Interface
|
|
input susp_req;
|
|
input resume_req;
|
|
output suspended;
|
|
output susp_sel;
|
|
|
|
// Memory Interface
|
|
input mc_clk;
|
|
output data_oe;
|
|
output oe_;
|
|
output we_;
|
|
output cas_;
|
|
output ras_;
|
|
output cke_;
|
|
output cs_en;
|
|
output wb_cycle;
|
|
output wr_cycle;
|
|
input mc_br;
|
|
output mc_bg;
|
|
output mc_adsc;
|
|
output mc_adv;
|
|
output mc_c_oe;
|
|
input mc_ack;
|
|
input not_mem_cyc;
|
|
|
|
// Register File Interface
|
|
input [31:0] csc;
|
|
input [31:0] tms;
|
|
input [7:0] cs;
|
|
input lmr_req;
|
|
output lmr_ack;
|
|
output cs_le;
|
|
output cs_le_d;
|
|
|
|
// Address Select Signals
|
|
input [10:0] page_size;
|
|
output cmd_a10;
|
|
output row_sel;
|
|
output next_adr;
|
|
|
|
// OBCT Signals
|
|
output bank_set;
|
|
output bank_clr;
|
|
output bank_clr_all;
|
|
input bank_open;
|
|
input any_bank_open;
|
|
input row_same;
|
|
|
|
// Data path Controller Signals
|
|
output dv;
|
|
output pack_le0, pack_le1, pack_le2; // Pack Latch Enable
|
|
input par_err;
|
|
|
|
// Refresh Counter Signals
|
|
input rfr_req;
|
|
output rfr_ack;
|
|
|
|
// Initialize Request & Ack
|
|
input init_req;
|
|
output init_ack;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Defines & Parameters
|
|
//
|
|
|
|
// Number of states: 66
|
|
parameter [65:0] // synopsys enum state
|
|
// 6666666555555555544444444443333333333222222222211111111110000000000
|
|
// 6543210987654321098765432109876543210987654321098765432109876543210
|
|
POR = 66'b000000000000000000000000000000000000000000000000000000000000000001,
|
|
IDLE = 66'b000000000000000000000000000000000000000000000000000000000000000010,
|
|
IDLE_T = 66'b000000000000000000000000000000000000000000000000000000000000000100,
|
|
IDLE_T2 = 66'b000000000000000000000000000000000000000000000000000000000000001000,
|
|
PRECHARGE = 66'b000000000000000000000000000000000000000000000000000000000000010000,
|
|
PRECHARGE_W = 66'b000000000000000000000000000000000000000000000000000000000000100000,
|
|
ACTIVATE = 66'b000000000000000000000000000000000000000000000000000000000001000000,
|
|
ACTIVATE_W = 66'b000000000000000000000000000000000000000000000000000000000010000000,
|
|
SD_RD_WR = 66'b000000000000000000000000000000000000000000000000000000000100000000,
|
|
SD_RD = 66'b000000000000000000000000000000000000000000000000000000001000000000,
|
|
SD_RD_W = 66'b000000000000000000000000000000000000000000000000000000010000000000,
|
|
SD_RD_LOOP = 66'b000000000000000000000000000000000000000000000000000000100000000000,
|
|
SD_RD_W2 = 66'b000000000000000000000000000000000000000000000000000001000000000000,
|
|
SD_WR = 66'b000000000000000000000000000000000000000000000000000010000000000000,
|
|
SD_WR_W = 66'b000000000000000000000000000000000000000000000000000100000000000000,
|
|
BT = 66'b000000000000000000000000000000000000000000000000001000000000000000,
|
|
BT_W = 66'b000000000000000000000000000000000000000000000000010000000000000000,
|
|
REFR = 66'b000000000000000000000000000000000000000000000000100000000000000000,
|
|
LMR0 = 66'b000000000000000000000000000000000000000000000001000000000000000000,
|
|
LMR1 = 66'b000000000000000000000000000000000000000000000010000000000000000000,
|
|
LMR2 = 66'b000000000000000000000000000000000000000000000100000000000000000000,
|
|
// 6666666555555555544444444443333333333222222222211111111110000000000
|
|
// 6543210987654321098765432109876543210987654321098765432109876543210
|
|
INIT0 = 66'b000000000000000000000000000000000000000000001000000000000000000000,
|
|
INIT = 66'b000000000000000000000000000000000000000000010000000000000000000000,
|
|
INIT_W = 66'b000000000000000000000000000000000000000000100000000000000000000000,
|
|
INIT_REFR1 = 66'b000000000000000000000000000000000000000001000000000000000000000000,
|
|
INIT_REFR1_W = 66'b000000000000000000000000000000000000000010000000000000000000000000,
|
|
// 6666666555555555544444444443333333333222222222211111111110000000000
|
|
// 6543210987654321098765432109876543210987654321098765432109876543210
|
|
INIT_LMR = 66'b000000000000000000000000000000000000000100000000000000000000000000,
|
|
SUSP1 = 66'b000000000000000000000000000000000000001000000000000000000000000000,
|
|
SUSP2 = 66'b000000000000000000000000000000000000010000000000000000000000000000,
|
|
SUSP3 = 66'b000000000000000000000000000000000000100000000000000000000000000000,
|
|
SUSP4 = 66'b000000000000000000000000000000000001000000000000000000000000000000,
|
|
RESUME1 = 66'b000000000000000000000000000000000010000000000000000000000000000000,
|
|
RESUME2 = 66'b000000000000000000000000000000000100000000000000000000000000000000,
|
|
BG0 = 66'b000000000000000000000000000000001000000000000000000000000000000000,
|
|
BG1 = 66'b000000000000000000000000000000010000000000000000000000000000000000,
|
|
BG2 = 66'b000000000000000000000000000000100000000000000000000000000000000000,
|
|
ACS_RD = 66'b000000000000000000000000000001000000000000000000000000000000000000,
|
|
ACS_RD1 = 66'b000000000000000000000000000010000000000000000000000000000000000000,
|
|
ACS_RD2A = 66'b000000000000000000000000000100000000000000000000000000000000000000,
|
|
ACS_RD2 = 66'b000000000000000000000000001000000000000000000000000000000000000000,
|
|
ACS_RD3 = 66'b000000000000000000000000010000000000000000000000000000000000000000,
|
|
ACS_RD_8_1 = 66'b000000000000000000000000100000000000000000000000000000000000000000,
|
|
ACS_RD_8_2 = 66'b000000000000000000000001000000000000000000000000000000000000000000,
|
|
ACS_RD_8_3 = 66'b000000000000000000000010000000000000000000000000000000000000000000,
|
|
ACS_RD_8_4 = 66'b000000000000000000000100000000000000000000000000000000000000000000,
|
|
ACS_RD_8_5 = 66'b000000000000000000001000000000000000000000000000000000000000000000,
|
|
ACS_RD_8_6 = 66'b000000000000000000010000000000000000000000000000000000000000000000,
|
|
ACS_WR = 66'b000000000000000000100000000000000000000000000000000000000000000000,
|
|
ACS_WR1 = 66'b000000000000000001000000000000000000000000000000000000000000000000,
|
|
ACS_WR2 = 66'b000000000000000010000000000000000000000000000000000000000000000000,
|
|
ACS_WR3 = 66'b000000000000000100000000000000000000000000000000000000000000000000,
|
|
ACS_WR4 = 66'b000000000000001000000000000000000000000000000000000000000000000000,
|
|
SRAM_RD = 66'b000000000000010000000000000000000000000000000000000000000000000000,
|
|
SRAM_RD0 = 66'b000000000000100000000000000000000000000000000000000000000000000000,
|
|
SRAM_RD1 = 66'b000000000001000000000000000000000000000000000000000000000000000000,
|
|
SRAM_RD2 = 66'b000000000010000000000000000000000000000000000000000000000000000000,
|
|
SRAM_RD3 = 66'b000000000100000000000000000000000000000000000000000000000000000000,
|
|
SRAM_RD4 = 66'b000000001000000000000000000000000000000000000000000000000000000000,
|
|
SRAM_WR = 66'b000000010000000000000000000000000000000000000000000000000000000000,
|
|
SRAM_WR0 = 66'b000000100000000000000000000000000000000000000000000000000000000000,
|
|
SCS_RD = 66'b000001000000000000000000000000000000000000000000000000000000000000,
|
|
SCS_RD1 = 66'b000010000000000000000000000000000000000000000000000000000000000000,
|
|
SCS_RD2 = 66'b000100000000000000000000000000000000000000000000000000000000000000,
|
|
SCS_WR = 66'b001000000000000000000000000000000000000000000000000000000000000000,
|
|
SCS_WR1 = 66'b010000000000000000000000000000000000000000000000000000000000000000,
|
|
SCS_ERR = 66'b100000000000000000000000000000000000000000000000000000000000000000;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Local Registers & Wires
|
|
//
|
|
|
|
reg [65:0] /* synopsys enum state */ state, next_state;
|
|
// synopsys state_vector state
|
|
|
|
reg mc_bg;
|
|
|
|
wire [2:0] mem_type;
|
|
wire [1:0] bus_width;
|
|
wire kro;
|
|
|
|
wire cs_a;
|
|
reg [3:0] cmd;
|
|
|
|
wire mem_ack;
|
|
wire mem_ack_s;
|
|
reg mem_ack_d;
|
|
reg err_d;
|
|
wire err;
|
|
reg cmd_a10;
|
|
reg lmr_ack;
|
|
reg lmr_ack_d;
|
|
reg row_sel;
|
|
reg oe_;
|
|
reg oe_d;
|
|
reg data_oe;
|
|
reg data_oe_d;
|
|
reg cke_d;
|
|
reg cke_;
|
|
reg init_ack;
|
|
reg dv;
|
|
reg rfr_ack_d;
|
|
reg mc_adsc;
|
|
reg mc_adv;
|
|
|
|
reg bank_set;
|
|
reg bank_clr;
|
|
reg bank_clr_all;
|
|
|
|
reg wr_set, wr_clr;
|
|
reg wr_cycle;
|
|
|
|
reg cmd_asserted;
|
|
reg cmd_asserted2;
|
|
|
|
reg [10:0] burst_val;
|
|
reg [10:0] burst_cnt;
|
|
wire burst_act;
|
|
reg burst_act_rd;
|
|
wire single_write;
|
|
|
|
reg cs_le_d;
|
|
reg cs_le;
|
|
reg cs_le_r;
|
|
|
|
reg susp_req_r;
|
|
reg resume_req_r;
|
|
reg suspended;
|
|
reg suspended_d;
|
|
reg susp_sel_set, susp_sel_clr, susp_sel_r;
|
|
|
|
reg [3:0] cmd_del;
|
|
reg [3:0] cmd_r;
|
|
reg data_oe_r;
|
|
reg data_oe_r2;
|
|
reg cke_r;
|
|
reg cke_rd;
|
|
reg cke_o_del;
|
|
reg cke_o_r1;
|
|
reg cke_o_r2;
|
|
reg wb_cycle_set, wb_cycle;
|
|
reg [3:0] ack_cnt;
|
|
wire ack_cnt_is_0;
|
|
reg cnt, cnt_next;
|
|
reg [7:0] timer;
|
|
reg tmr_ld_trp, tmr_ld_trcd, tmr_ld_tcl, tmr_ld_trfc;
|
|
reg tmr_ld_twr, tmr_ld_txsr;
|
|
reg tmr2_ld_tscsto;
|
|
reg tmr_ld_trdv;
|
|
reg tmr_ld_trdz;
|
|
reg tmr_ld_twr2;
|
|
wire timer_is_zero;
|
|
reg tmr_done;
|
|
reg tmr2_ld_trdv, tmr2_ld_trdz;
|
|
reg tmr2_ld_twpw, tmr2_ld_twd, tmr2_ld_twwd;
|
|
reg tmr2_ld_tsrdv;
|
|
reg [8:0] timer2;
|
|
reg tmr2_done;
|
|
wire timer2_is_zero;
|
|
reg [3:0] ir_cnt;
|
|
reg ir_cnt_ld;
|
|
reg ir_cnt_dec;
|
|
reg ir_cnt_done;
|
|
reg rfr_ack_r;
|
|
reg burst_cnt_ld;
|
|
reg burst_fp;
|
|
reg wb_wait_r, wb_wait_r2;
|
|
reg lookup_ready1, lookup_ready2;
|
|
reg burst_cnt_ld_4;
|
|
reg dv_r;
|
|
reg mc_adv_r1, mc_adv_r;
|
|
|
|
reg next_adr;
|
|
reg pack_le0, pack_le1, pack_le2;
|
|
reg pack_le0_d, pack_le1_d, pack_le2_d;
|
|
wire bw8, bw16;
|
|
|
|
reg mc_c_oe_d;
|
|
reg mc_c_oe;
|
|
|
|
reg mc_le;
|
|
reg mem_ack_r;
|
|
|
|
reg rsts, rsts1;
|
|
reg no_wb_cycle;
|
|
|
|
wire bc_dec;
|
|
reg ap_en; // Auto Precharge Enable
|
|
reg cmd_a10_r;
|
|
reg wb_stb_first;
|
|
reg tmr_ld_tavav;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Aliases
|
|
//
|
|
assign mem_type = csc[3:1];
|
|
assign bus_width = csc[5:4];
|
|
assign kro = csc[10];
|
|
assign single_write = tms[9] | (tms[2:0] == 3'h0);
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Misc Logic
|
|
//
|
|
reg cs_le_r1;
|
|
|
|
always @(posedge clk)
|
|
lmr_ack <= #1 lmr_ack_d;
|
|
|
|
assign rfr_ack = rfr_ack_r;
|
|
|
|
always @(posedge clk)
|
|
cs_le_r <= #1 cs_le_r1;
|
|
|
|
always @(posedge clk)
|
|
cs_le_r1 <= #1 cs_le;
|
|
|
|
always @(posedge clk)
|
|
cs_le <= #1 cs_le_d;
|
|
|
|
always @(posedge mc_clk or posedge rst)
|
|
if(rst) rsts1 <= #1 1'b1;
|
|
else rsts1 <= #1 1'b0;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) rsts <= #1 1'b1;
|
|
else rsts <= #1 rsts1;
|
|
|
|
// Control Signals Output Enable
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) mc_c_oe <= #1 1'b0;
|
|
else mc_c_oe <= #1 mc_c_oe_d;
|
|
|
|
always @(posedge clk or posedge rsts)
|
|
if(rsts) mc_le <= #1 1'b0;
|
|
else mc_le <= #1 ~mc_le;
|
|
|
|
always @(posedge clk)
|
|
pack_le0 <= #1 pack_le0_d;
|
|
|
|
always @(posedge clk)
|
|
pack_le1 <= #1 pack_le1_d;
|
|
|
|
always @(posedge clk)
|
|
pack_le2 <= #1 pack_le2_d;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) mc_adv_r1 <= #1 1'b0;
|
|
else
|
|
if(!mc_le) mc_adv_r1 <= #1 mc_adv;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) mc_adv_r <= #1 1'b0;
|
|
else
|
|
if(!mc_le) mc_adv_r <= #1 mc_adv_r1;
|
|
|
|
// Bus Width decoder
|
|
assign bw8 = (bus_width == `MC_BW_8);
|
|
assign bw16 = (bus_width == `MC_BW_16);
|
|
|
|
// Any Chip Select
|
|
assign cs_a = |cs;
|
|
|
|
// Memory to Wishbone Ack
|
|
assign mem_ack = (mem_ack_d | mem_ack_s) & (wb_read_go | wb_write_go);
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) mem_ack_r <= #1 1'b0;
|
|
else mem_ack_r <= #1 mem_ack;
|
|
|
|
assign err = err_d;
|
|
|
|
// SDRAM Command, either delayed (for writes) or straight through
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) cmd_r <= #1 `MC_CMD_NOP;
|
|
else cmd_r <= #1 cmd;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) cmd_del <= #1 `MC_CMD_NOP;
|
|
else cmd_del <= #1 cmd_r;
|
|
|
|
assign {cs_en, ras_, cas_, we_} = wr_cycle ? cmd_del : cmd;
|
|
|
|
// Track Timing of Asserting a command
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) cmd_asserted <= #1 1'b0;
|
|
else
|
|
if(!mc_le) cmd_asserted <= #1 cmd[3];
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) cmd_asserted2 <= #1 1'b0;
|
|
else
|
|
if(!mc_le) cmd_asserted2 <= #1 cmd_asserted;
|
|
|
|
// Output Enable
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) oe_ <= #1 1'b1;
|
|
else oe_ <= #1 ~oe_d;
|
|
|
|
// Memory Bus Data lines Output Enable
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) data_oe_r <= #1 1'b0;
|
|
else data_oe_r <= #1 data_oe_d;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) data_oe_r2 <= #1 1'b0;
|
|
else data_oe_r2 <= #1 data_oe_r;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) data_oe <= #1 1'b0;
|
|
else data_oe <= #1 wr_cycle ? data_oe_r2 : data_oe_d;
|
|
|
|
// Clock Enable
|
|
always @(posedge clk)
|
|
cke_r <= #1 cke_d;
|
|
|
|
always @(posedge clk)
|
|
cke_ <= #1 cke_r & cke_rd;
|
|
|
|
// CKE output delay line to time DV for reads
|
|
always @(posedge clk)
|
|
cke_o_r1 <= #1 cke_;
|
|
|
|
always @(posedge clk)
|
|
cke_o_r2 <= #1 cke_o_r1;
|
|
|
|
always @(posedge clk)
|
|
cke_o_del <= #1 cke_o_r2;
|
|
|
|
// Delayed version of the wb_wait input
|
|
always @(posedge clk)
|
|
wb_wait_r2 <= #1 wb_wait;
|
|
|
|
always @(posedge clk)
|
|
wb_wait_r <= #1 wb_wait_r2;
|
|
|
|
// Indicates when the row_same and bank_open lookups are done
|
|
reg lookup_ready1a;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) lookup_ready1 <= #1 1'b0;
|
|
else lookup_ready1 <= #1 cs_le & wb_cyc_i & wb_stb_i;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) lookup_ready2 <= #1 1'b0;
|
|
else lookup_ready2 <= #1 lookup_ready1 & wb_cyc_i & wb_stb_i;
|
|
|
|
// Keep Track if it is a SDRAM write cycle
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) wr_cycle <= #1 1'b0;
|
|
else
|
|
if(wr_set) wr_cycle <= #1 1'b1;
|
|
else
|
|
if(wr_clr) wr_cycle <= #1 1'b0;
|
|
|
|
// Track when a cycle is *still* active
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) wb_cycle <= #1 1'b0;
|
|
else
|
|
if(wb_cycle_set) wb_cycle <= #1 1'b1;
|
|
else
|
|
if(!wb_cyc_i | not_mem_cyc) wb_cycle <= #1 1'b0;
|
|
|
|
// Thses two signals are used to signal that no wishbone cycle is in
|
|
// progress. Need to register them to avoid a very long combinatorial
|
|
// path ....
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) no_wb_cycle <= #1 1'b0;
|
|
else no_wb_cycle <= #1 !wb_read_go & !wb_write_go;
|
|
|
|
// Track ack's for read cycles
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) ack_cnt <= #1 4'h0;
|
|
else
|
|
if(no_wb_cycle) ack_cnt <= #1 4'h0;
|
|
else
|
|
if(dv & !mem_ack_s) ack_cnt <= #1 ack_cnt + 4'h1;
|
|
else
|
|
if(!dv & mem_ack_s) ack_cnt <= #1 ack_cnt - 4'h1;
|
|
|
|
assign ack_cnt_is_0 = (ack_cnt==4'h0);
|
|
|
|
assign mem_ack_s = (ack_cnt != 4'h0) & !wb_wait & !mem_ack_r & wb_read_go & !(wb_we_i & wb_stb_i);
|
|
|
|
// Internal Cycle Tracker
|
|
always @(posedge clk)
|
|
cnt <= #1 cnt_next;
|
|
|
|
// Suspend/resume Logic
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) susp_req_r <= #1 1'b0;
|
|
else susp_req_r <= #1 susp_req;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) resume_req_r <= #1 1'b0;
|
|
else resume_req_r <= #1 resume_req;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) suspended <= #1 1'b0;
|
|
else suspended <= #1 suspended_d;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) rfr_ack_r <= #1 1'b0;
|
|
else rfr_ack_r <= #1 rfr_ack_d;
|
|
|
|
// Suspend Select Logic
|
|
assign susp_sel = susp_sel_r;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) susp_sel_r <= #1 1'b0;
|
|
else
|
|
if(susp_sel_set) susp_sel_r <= #1 1'b1;
|
|
else
|
|
if(susp_sel_clr) susp_sel_r <= #1 1'b0;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Timing Logic
|
|
//
|
|
wire [3:0] twrp;
|
|
wire twd_is_zero;
|
|
wire [31:0] tms_x;
|
|
|
|
// FIX_ME
|
|
// Hard wire worst case or make it programmable ???
|
|
assign tms_x = (rfr_ack_d | rfr_ack_r | susp_sel | !mc_c_oe) ? 32'hffff_ffff : tms;
|
|
|
|
always @(posedge clk)
|
|
if(tmr2_ld_tscsto) timer2 <= #1 tms_x[24:16];
|
|
else
|
|
if(tmr2_ld_tsrdv) timer2 <= #1 9'd4; // SSRAM RD->1st DATA VALID
|
|
else
|
|
if(tmr2_ld_twpw) timer2 <= #1 { 5'h0, tms_x[15:12]};
|
|
else
|
|
if(tmr2_ld_twd) timer2 <= #1 { 4'h0, tms_x[19:16],1'b0};
|
|
else
|
|
if(tmr2_ld_twwd) timer2 <= #1 { 3'h0, tms_x[25:20]};
|
|
else
|
|
if(tmr2_ld_trdz) timer2 <= #1 { 4'h0, tms_x[11:8], 1'b1};
|
|
else
|
|
if(tmr2_ld_trdv) timer2 <= #1 { tms_x[7:0], 1'b1};
|
|
else
|
|
if(!timer2_is_zero) timer2 <= #1 timer2 - 9'b1;
|
|
|
|
assign twd_is_zero = (tms_x[19:16] == 4'h0);
|
|
|
|
assign timer2_is_zero = (timer2 == 9'h0);
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) tmr2_done <= #1 1'b0;
|
|
else tmr2_done <= #1 timer2_is_zero & !tmr2_ld_trdv & !tmr2_ld_trdz &
|
|
!tmr2_ld_twpw & !tmr2_ld_twd & !tmr2_ld_twwd & !tmr2_ld_tscsto;
|
|
|
|
assign twrp = {2'h0,tms_x[16:15]} + tms_x[23:20];
|
|
|
|
// SDRAM Memories timing tracker
|
|
always @(posedge clk or posedge rst)
|
|
`ifdef MC_POR_DELAY
|
|
if(rst) timer <= #1 `MC_POR_DELAY_VAL ;
|
|
else
|
|
`endif
|
|
if(tmr_ld_twr2) timer <= #1 { 4'h0, tms_x[15:12] };
|
|
else
|
|
if(tmr_ld_trdz) timer <= #1 { 4'h0, tms_x[11:8] };
|
|
else
|
|
if(tmr_ld_trdv) timer <= #1 tms_x[7:0];
|
|
else
|
|
if(tmr_ld_twr) timer <= #1 { 4'h0, twrp};
|
|
else
|
|
if(tmr_ld_trp) timer <= #1 { 4'h0, tms_x[23:20]};
|
|
else
|
|
if(tmr_ld_trcd) timer <= #1 { 5'h0, tms_x[19:17]};
|
|
else
|
|
if(tmr_ld_tcl) timer <= #1 { 6'h0, tms_x[05:04]};
|
|
else
|
|
if(tmr_ld_trfc) timer <= #1 { 4'h0, tms_x[27:24]};
|
|
else
|
|
if(tmr_ld_tavav) timer <= #1 8'h3;
|
|
else
|
|
if(tmr_ld_txsr) timer <= #1 8'h7;
|
|
else
|
|
if(!timer_is_zero & !mc_le) timer <= #1 timer - 8'b1;
|
|
|
|
assign timer_is_zero = (timer == 8'h0);
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) tmr_done <= #1 1'b0;
|
|
else tmr_done <= #1 timer_is_zero;
|
|
|
|
// Init Refresh Cycles Counter
|
|
always @(posedge clk)
|
|
if(ir_cnt_ld) ir_cnt <= #1 `MC_INIT_RFRC_CNT;
|
|
else
|
|
if(ir_cnt_dec) ir_cnt <= #1 ir_cnt - 4'b1;
|
|
|
|
always @(posedge clk)
|
|
ir_cnt_done <= #1 (ir_cnt == 4'h0);
|
|
|
|
// Burst Counter
|
|
always @(tms_x or page_size)
|
|
case(tms_x[2:0]) // synopsys full_case parallel_case
|
|
3'h0: burst_val = 11'h1;
|
|
3'h1: burst_val = 11'h2;
|
|
3'h2: burst_val = 11'h4;
|
|
3'h3: burst_val = 11'h8;
|
|
3'h7: burst_val = page_size;
|
|
endcase
|
|
|
|
assign bc_dec = wr_cycle ? mem_ack_d : dv;
|
|
|
|
always @(posedge clk)
|
|
if(burst_cnt_ld_4) burst_cnt <= #1 11'h4; // for SSRAM only
|
|
else
|
|
if(burst_cnt_ld) burst_cnt <= #1 burst_val;
|
|
else
|
|
if(bc_dec) burst_cnt <= #1 burst_cnt - 11'h1;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) burst_fp <= #1 1'b0;
|
|
else
|
|
if(burst_cnt_ld) burst_fp <= #1 (tms_x[2:0] == 3'h7);
|
|
|
|
// Auto Precharge Enable
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) ap_en <= #1 1'b0;
|
|
else
|
|
if(burst_cnt_ld) ap_en <= #1 (tms_x[2:0] == 3'h0) & !kro;
|
|
|
|
assign burst_act = |burst_cnt & ( |tms_x[2:0] );
|
|
|
|
always @(posedge clk)
|
|
burst_act_rd <= #1 |burst_cnt;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) dv_r <= #1 1'b0;
|
|
else dv_r <= #1 dv;
|
|
|
|
always @(posedge clk) // Auto Precharge Holding Register
|
|
cmd_a10_r <= #1 cmd_a10;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Main State Machine
|
|
//
|
|
reg wb_write_go_r;
|
|
|
|
always @(posedge clk)
|
|
wb_write_go_r <= #1 wb_write_go;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
if(rst) wb_stb_first <= #1 1'b0;
|
|
else
|
|
if(mem_ack) wb_stb_first <= #1 1'b0;
|
|
else
|
|
if(wb_first & wb_stb_i) wb_stb_first <= #1 1'b1;
|
|
|
|
always @(posedge clk or posedge rst)
|
|
`ifdef MC_POR_DELAY
|
|
if(rst) state <= #1 POR;
|
|
`else
|
|
if(rst) state <= #1 IDLE;
|
|
`endif
|
|
else state <= #1 next_state;
|
|
|
|
always @(state or cs_a or cs_le or cs_le_r or
|
|
twd_is_zero or wb_stb_i or wb_write_go_r or
|
|
wb_first or wb_read_go or wb_write_go or wb_wait or mem_ack_r or wb_we_i or
|
|
ack_cnt_is_0 or wb_wait_r or cnt or wb_cycle or wr_cycle or
|
|
mem_type or kro or lookup_ready2 or row_same or cmd_a10_r or
|
|
bank_open or single_write or
|
|
cmd_asserted or tmr_done or tmr2_done or ir_cnt_done or cmd_asserted2 or
|
|
burst_act or burst_act_rd or burst_fp or cke_ or cke_r or cke_o_del or
|
|
rfr_req or lmr_req or init_req or rfr_ack_r or susp_req_r or resume_req_r or
|
|
mc_br or bw8 or bw16 or dv_r or mc_adv_r or mc_ack or wb_stb_first or ap_en
|
|
)
|
|
begin
|
|
next_state = state; // Default keep current state
|
|
cnt_next = 1'b0;
|
|
|
|
cmd = `MC_CMD_NOP;
|
|
cmd_a10 = ap_en;
|
|
oe_d = 1'b0;
|
|
data_oe_d = 1'b0;
|
|
cke_d = 1'b1;
|
|
cke_rd = 1'b1;
|
|
mc_adsc = 1'b0;
|
|
mc_adv = 1'b0;
|
|
|
|
bank_set = 1'b0;
|
|
bank_clr = 1'b0;
|
|
bank_clr_all = 1'b0;
|
|
|
|
burst_cnt_ld = 1'b0;
|
|
burst_cnt_ld_4 = 1'b0;
|
|
tmr_ld_trp = 1'b0;
|
|
tmr_ld_trcd = 1'b0;
|
|
tmr_ld_tcl = 1'b0;
|
|
tmr_ld_trfc = 1'b0;
|
|
tmr_ld_twr = 1'b0;
|
|
tmr_ld_txsr = 1'b0;
|
|
tmr_ld_trdv = 1'b0;
|
|
tmr_ld_trdz = 1'b0;
|
|
tmr_ld_twr2 = 1'b0;
|
|
tmr_ld_tavav = 1'b0;
|
|
|
|
tmr2_ld_trdv = 1'b0;
|
|
tmr2_ld_trdz = 1'b0;
|
|
|
|
tmr2_ld_twpw = 1'b0;
|
|
tmr2_ld_twd = 1'b0;
|
|
tmr2_ld_twwd = 1'b0;
|
|
tmr2_ld_tsrdv = 1'b0;
|
|
tmr2_ld_tscsto = 1'b0;
|
|
|
|
mem_ack_d = 1'b0;
|
|
err_d = 1'b0;
|
|
rfr_ack_d = 1'b0;
|
|
lmr_ack_d = 1'b0;
|
|
init_ack = 1'b0;
|
|
|
|
ir_cnt_dec = 1'b0;
|
|
ir_cnt_ld = 1'b0;
|
|
|
|
row_sel = 1'b0;
|
|
cs_le_d = 1'b0;
|
|
wr_clr = 1'b0;
|
|
wr_set = 1'b0;
|
|
wb_cycle_set = 1'b0;
|
|
dv = 1'b0;
|
|
|
|
suspended_d = 1'b0;
|
|
susp_sel_set = 1'b0;
|
|
susp_sel_clr = 1'b0;
|
|
mc_bg = 1'b0;
|
|
|
|
next_adr = 1'b0;
|
|
pack_le0_d = 1'b0;
|
|
pack_le1_d = 1'b0;
|
|
pack_le2_d = 1'b0;
|
|
|
|
mc_c_oe_d = 1'b1;
|
|
|
|
case(state) // synopsys full_case parallel_case
|
|
`ifdef MC_POR_DELAY
|
|
POR:
|
|
begin
|
|
if(tmr_done) next_state = IDLE;
|
|
end
|
|
`endif
|
|
IDLE:
|
|
begin
|
|
//cs_le_d = wb_stb_first | lmr_req;
|
|
cs_le_d = wb_stb_first;
|
|
|
|
burst_cnt_ld = 1'b1;
|
|
wr_clr = 1'b1;
|
|
|
|
if(mem_type == `MC_MEM_TYPE_SCS) tmr2_ld_tscsto = 1'b1;
|
|
if(mem_type == `MC_MEM_TYPE_SRAM) tmr2_ld_tsrdv = 1'b1;
|
|
|
|
if(rfr_req)
|
|
begin
|
|
rfr_ack_d = 1'b1;
|
|
next_state = PRECHARGE;
|
|
end
|
|
else
|
|
if(init_req)
|
|
begin
|
|
cs_le_d = 1'b1;
|
|
next_state = INIT0;
|
|
end
|
|
else
|
|
if(lmr_req & lookup_ready2)
|
|
begin
|
|
lmr_ack_d = 1'b1;
|
|
cs_le_d = 1'b1;
|
|
next_state = LMR0;
|
|
end
|
|
else
|
|
if(susp_req_r & !wb_cycle)
|
|
begin
|
|
cs_le_d = 1'b1;
|
|
susp_sel_set = 1'b1;
|
|
next_state = SUSP1;
|
|
end
|
|
else
|
|
if(cs_a & (wb_read_go | wb_write_go) & lookup_ready2)
|
|
begin
|
|
wb_cycle_set = 1'b1;
|
|
case(mem_type) // synopsys full_case parallel_case
|
|
`MC_MEM_TYPE_SDRAM: // SDRAM
|
|
if((lookup_ready2) & !wb_wait)
|
|
begin
|
|
if(wb_write_go | (wb_we_i & wb_stb_i)) wr_set = 1'b1;
|
|
if(kro & bank_open & row_same) next_state = SD_RD_WR;
|
|
else
|
|
if(kro & bank_open) next_state = PRECHARGE;
|
|
else next_state = ACTIVATE;
|
|
end
|
|
`MC_MEM_TYPE_ACS:
|
|
begin // Async Chip Select
|
|
if(!wb_wait)
|
|
begin
|
|
cs_le_d = 1'b1;
|
|
if(wb_write_go)
|
|
begin
|
|
data_oe_d = 1'b1;
|
|
next_state = ACS_WR;
|
|
end
|
|
else next_state = ACS_RD;
|
|
end
|
|
end
|
|
`MC_MEM_TYPE_SCS:
|
|
begin // Sync Chip Select
|
|
if(!wb_wait)
|
|
begin
|
|
cs_le_d = 1'b1;
|
|
if(wb_write_go)
|
|
begin
|
|
cmd = `MC_CMD_XWR;
|
|
data_oe_d = 1'b1;
|
|
tmr_ld_twr2 = 1'b1;
|
|
next_state = SCS_WR;
|
|
end
|
|
else
|
|
begin
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
tmr_ld_trdv = 1'b1;
|
|
next_state = SCS_RD;
|
|
end
|
|
end
|
|
end
|
|
`MC_MEM_TYPE_SRAM:
|
|
begin // SRAM
|
|
if(!wb_wait)
|
|
begin
|
|
cs_le_d = 1'b1;
|
|
if(wb_write_go)
|
|
begin
|
|
data_oe_d = 1'b1;
|
|
mem_ack_d = 1'b1;
|
|
next_state = SRAM_WR;
|
|
end
|
|
else
|
|
begin
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
mc_adsc = 1'b1;
|
|
next_state = SRAM_RD;
|
|
end
|
|
end
|
|
end
|
|
endcase
|
|
end
|
|
else
|
|
if(mc_br)
|
|
begin
|
|
if(!cmd_asserted2)
|
|
begin
|
|
next_state = BG0;
|
|
mc_c_oe_d = 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
IDLE_T:
|
|
begin
|
|
cmd_a10 = cmd_a10_r; // Hold Auto Precharge 'til cycle finishes
|
|
if(tmr_done & wb_cycle & !wb_wait) cs_le_d = 1'b1;
|
|
if(tmr_done) next_state = IDLE;
|
|
end
|
|
|
|
IDLE_T2:
|
|
begin
|
|
if(tmr2_done & (!wb_wait | !wb_cycle) )
|
|
begin
|
|
cs_le_d = wb_cycle;
|
|
if(cs_le_r | !wb_cycle) next_state = IDLE;
|
|
end
|
|
end
|
|
|
|
/////////////////////////////////////////
|
|
// SCS STATES ....
|
|
/////////////////////////////////////////
|
|
SCS_RD:
|
|
begin
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
tmr_ld_trdv = 1'b1;
|
|
if(mc_ack) next_state = SCS_RD1;
|
|
else
|
|
if(tmr2_done) next_state = SCS_ERR;
|
|
end
|
|
|
|
SCS_RD1:
|
|
begin
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
if(tmr_done)
|
|
begin
|
|
mem_ack_d = 1'b1;
|
|
tmr_ld_trdz = 1'b1;
|
|
next_state = SCS_RD2;
|
|
end
|
|
end
|
|
|
|
SCS_RD2:
|
|
begin
|
|
tmr_ld_trdz = 1'b1;
|
|
next_state = IDLE_T;
|
|
end
|
|
|
|
SCS_WR:
|
|
begin
|
|
tmr_ld_twr2 = 1'b1;
|
|
cmd = `MC_CMD_XWR;
|
|
data_oe_d = 1'b1;
|
|
if(mc_ack) next_state = SCS_WR1;
|
|
else
|
|
if(tmr2_done) next_state = SCS_ERR;
|
|
end
|
|
|
|
SCS_WR1:
|
|
begin
|
|
data_oe_d = 1'b1;
|
|
if(tmr_done)
|
|
begin
|
|
mem_ack_d = 1'b1;
|
|
next_state = IDLE_T;
|
|
end
|
|
else cmd = `MC_CMD_XWR;
|
|
end
|
|
|
|
SCS_ERR:
|
|
begin
|
|
mem_ack_d = 1'b1;
|
|
err_d = 1'b1;
|
|
next_state = IDLE_T2;
|
|
end
|
|
|
|
/////////////////////////////////////////
|
|
// SSRAM STATES ....
|
|
/////////////////////////////////////////
|
|
SRAM_RD:
|
|
begin
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
mc_adsc = 1'b1;
|
|
tmr2_ld_tsrdv = 1'b1;
|
|
burst_cnt_ld_4 = 1'b1;
|
|
if(cmd_asserted) next_state = SRAM_RD0;
|
|
end
|
|
|
|
SRAM_RD0:
|
|
begin
|
|
mc_adv = 1'b1;
|
|
oe_d = 1'b1;
|
|
if(tmr2_done)
|
|
begin
|
|
mc_adv = !wb_wait;
|
|
next_state = SRAM_RD1;
|
|
end
|
|
end
|
|
|
|
SRAM_RD1:
|
|
begin
|
|
if(mc_adv_r) dv = ~dv_r;
|
|
mc_adv = !wb_wait;
|
|
|
|
if(!burst_act | !wb_read_go) next_state = SRAM_RD2;
|
|
else oe_d = 1'b1;
|
|
end
|
|
|
|
SRAM_RD2:
|
|
begin
|
|
if(ack_cnt_is_0 & wb_read_go) next_state = SRAM_RD3;
|
|
else
|
|
if(!wb_read_go)
|
|
begin
|
|
mc_adsc = 1'b1;
|
|
next_state = SRAM_RD4;
|
|
end
|
|
end
|
|
|
|
SRAM_RD3:
|
|
begin
|
|
if(!wb_read_go)
|
|
begin
|
|
mc_adsc = 1'b1;
|
|
next_state = SRAM_RD4;
|
|
end
|
|
else
|
|
if(!wb_wait)
|
|
begin
|
|
cs_le_d = 1'b1;
|
|
next_state = SRAM_RD;
|
|
end
|
|
end
|
|
|
|
SRAM_RD4: // DESELECT
|
|
begin
|
|
if(wb_cycle) cs_le_d = 1'b1; // For RMW
|
|
mc_adsc = 1'b1;
|
|
next_state = IDLE;
|
|
end
|
|
|
|
SRAM_WR:
|
|
begin
|
|
cmd = `MC_CMD_XWR;
|
|
mc_adsc = 1'b1;
|
|
data_oe_d = 1'b1;
|
|
if(cmd_asserted)
|
|
begin
|
|
if(wb_wait) next_state = SRAM_WR0;
|
|
else
|
|
if(!wb_write_go)
|
|
begin
|
|
mc_adsc = 1'b1;
|
|
next_state = SRAM_RD4;
|
|
end
|
|
else
|
|
begin
|
|
data_oe_d = 1'b1;
|
|
mem_ack_d = ~mem_ack_r;
|
|
end
|
|
end
|
|
end
|
|
|
|
SRAM_WR0:
|
|
begin
|
|
if(wb_wait) next_state = SRAM_WR0;
|
|
else
|
|
if(!wb_write_go)
|
|
begin
|
|
mc_adsc = 1'b1;
|
|
next_state = SRAM_RD4;
|
|
end
|
|
else
|
|
begin
|
|
data_oe_d = 1'b1;
|
|
next_state = SRAM_WR;
|
|
end
|
|
end
|
|
|
|
/////////////////////////////////////////
|
|
// Async Devices STATES ....
|
|
/////////////////////////////////////////
|
|
ACS_RD:
|
|
begin
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
tmr2_ld_trdv = 1'b1;
|
|
next_state = ACS_RD1;
|
|
end
|
|
|
|
ACS_RD1:
|
|
begin // 32 bit, 8 bit - first; 16 bit - first
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
if(tmr2_done)
|
|
begin
|
|
if(bw8 | bw16) next_adr = 1'b1;
|
|
if(bw8) next_state = ACS_RD_8_1;
|
|
else
|
|
if(bw16) next_state = ACS_RD_8_5;
|
|
else next_state = ACS_RD2A;
|
|
end
|
|
end
|
|
|
|
ACS_RD_8_1:
|
|
begin // 8 bit 2nd byte
|
|
pack_le0_d = 1'b1;
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
tmr2_ld_trdv = 1'b1;
|
|
next_state = ACS_RD_8_2;
|
|
end
|
|
|
|
ACS_RD_8_2:
|
|
begin
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
if(tmr2_done)
|
|
begin
|
|
next_adr = 1'b1;
|
|
next_state = ACS_RD_8_3;
|
|
end
|
|
end
|
|
|
|
ACS_RD_8_3:
|
|
begin // 8 bit 3rd byte
|
|
pack_le1_d = 1'b1;
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
tmr2_ld_trdv = 1'b1;
|
|
next_state = ACS_RD_8_4;
|
|
end
|
|
|
|
ACS_RD_8_4:
|
|
begin
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
if(tmr2_done)
|
|
begin
|
|
next_adr = 1'b1;
|
|
next_state = ACS_RD_8_5;
|
|
end
|
|
end
|
|
|
|
ACS_RD_8_5:
|
|
begin // 8 bit 4th byte; 16 bit 2nd word
|
|
if(bw8) pack_le2_d = 1'b1;
|
|
if(bw16) pack_le0_d = 1'b1;
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
tmr2_ld_trdv = 1'b1;
|
|
next_state = ACS_RD_8_6;
|
|
end
|
|
|
|
ACS_RD_8_6:
|
|
begin
|
|
cmd = `MC_CMD_XRD;
|
|
oe_d = 1'b1;
|
|
if(tmr2_done)
|
|
begin
|
|
next_state = ACS_RD2;
|
|
end
|
|
end
|
|
|
|
ACS_RD2A:
|
|
begin
|
|
oe_d = 1'b1;
|
|
cmd = `MC_CMD_XRD;
|
|
next_state = ACS_RD2;
|
|
end
|
|
|
|
ACS_RD2:
|
|
begin
|
|
cmd = `MC_CMD_XRD;
|
|
next_state = ACS_RD3;
|
|
end
|
|
|
|
ACS_RD3:
|
|
begin
|
|
mem_ack_d = 1'b1;
|
|
tmr2_ld_trdz = 1'b1;
|
|
next_state = IDLE_T2;
|
|
end
|
|
|
|
ACS_WR:
|
|
begin
|
|
tmr2_ld_twpw = 1'b1;
|
|
cmd = `MC_CMD_XWR;
|
|
data_oe_d = 1'b1;
|
|
next_state = ACS_WR1;
|
|
end
|
|
|
|
ACS_WR1:
|
|
begin
|
|
if(!cmd_asserted) tmr2_ld_twpw = 1'b1;
|
|
cmd = `MC_CMD_XWR;
|
|
data_oe_d = 1'b1;
|
|
if(tmr2_done)
|
|
begin
|
|
tmr2_ld_twd = 1'b1;
|
|
next_state = ACS_WR2;
|
|
end
|
|
end
|
|
|
|
ACS_WR2:
|
|
begin
|
|
if(twd_is_zero) next_state = ACS_WR3;
|
|
else
|
|
begin
|
|
cmd = `MC_CMD_XRD;
|
|
data_oe_d = 1'b1;
|
|
next_state = ACS_WR3;
|
|
end
|
|
end
|
|
|
|
ACS_WR3:
|
|
begin
|
|
if(tmr2_done) next_state = ACS_WR4;
|
|
else cmd = `MC_CMD_XRD;
|
|
end
|
|
|
|
ACS_WR4:
|
|
begin
|
|
tmr2_ld_twwd = 1'b1;
|
|
mem_ack_d = 1'b1;
|
|
next_state = IDLE_T2;
|
|
end
|
|
|
|
/////////////////////////////////////////
|
|
// SDRAM STATES ....
|
|
/////////////////////////////////////////
|
|
|
|
PRECHARGE:
|
|
begin
|
|
cmd = `MC_CMD_PC;
|
|
if(rfr_ack_r)
|
|
begin
|
|
rfr_ack_d = 1'b1;
|
|
cmd_a10 = `MC_ALL_BANKS;
|
|
bank_clr_all = 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
bank_clr = 1'b1;
|
|
cmd_a10 = `MC_SINGLE_BANK;
|
|
end
|
|
tmr_ld_trp = 1'b1;
|
|
if(cmd_asserted) next_state = PRECHARGE_W;
|
|
end
|
|
|
|
PRECHARGE_W:
|
|
begin
|
|
rfr_ack_d = rfr_ack_r;
|
|
if(tmr_done)
|
|
begin
|
|
if(rfr_ack_r) next_state = REFR;
|
|
else next_state = ACTIVATE;
|
|
end
|
|
end
|
|
|
|
ACTIVATE:
|
|
begin
|
|
if(!wb_wait_r)
|
|
begin
|
|
row_sel = 1'b1;
|
|
tmr_ld_trcd = 1'b1;
|
|
cmd = `MC_CMD_ACT;
|
|
end
|
|
if(cmd_asserted) next_state = ACTIVATE_W;
|
|
end
|
|
|
|
ACTIVATE_W:
|
|
begin
|
|
row_sel = 1'b1;
|
|
if(wb_write_go | (wb_we_i & wb_stb_i)) wr_set = 1'b1;
|
|
|
|
if(kro) bank_set = 1'b1;
|
|
|
|
if(tmr_done)
|
|
begin
|
|
if(wb_write_go)
|
|
begin
|
|
mem_ack_d = ~mem_ack_r;
|
|
cmd_a10 = ap_en | (single_write & !kro);
|
|
next_state = SD_WR;
|
|
end
|
|
else
|
|
if(!wb_wait_r) next_state = SD_RD;
|
|
end
|
|
end
|
|
|
|
SD_RD_WR:
|
|
begin
|
|
if(wb_write_go | (wb_we_i & wb_stb_i)) wr_set = 1'b1;
|
|
|
|
if(wb_write_go & !wb_wait)
|
|
begin // Write
|
|
data_oe_d = 1'b1;
|
|
mem_ack_d = ~mem_ack_r;
|
|
cmd_a10 = ap_en | (single_write & !kro);
|
|
next_state = SD_WR;
|
|
end
|
|
else
|
|
if(!wb_wait)
|
|
begin // Read
|
|
if(kro)
|
|
begin
|
|
if(!wb_wait_r) next_state = SD_RD;
|
|
end
|
|
else next_state = SD_RD;
|
|
end
|
|
end
|
|
|
|
SD_WR: // Write Command
|
|
begin // Does the first single write
|
|
data_oe_d = 1'b1;
|
|
tmr_ld_twr = 1'b1;
|
|
cnt_next = ~cnt;
|
|
cmd = `MC_CMD_WR;
|
|
|
|
cmd_a10 = ap_en | (single_write & !kro);
|
|
|
|
if(!cnt & wb_cycle & burst_act) cke_d = ~wb_wait;
|
|
else cke_d = cke_r;
|
|
|
|
if(cmd_asserted)
|
|
begin
|
|
mem_ack_d = !mem_ack_r & wb_write_go & !wb_wait & wb_cycle & burst_act;
|
|
|
|
if(wb_cycle & !burst_act) next_state = IDLE_T;
|
|
else
|
|
if(wb_write_go) next_state = SD_WR_W;
|
|
else
|
|
if(burst_act & !single_write) next_state = BT;
|
|
else
|
|
if(!ap_en) next_state = BT_W;
|
|
else next_state = IDLE_T;
|
|
end
|
|
|
|
end
|
|
|
|
SD_WR_W:
|
|
begin // Does additional Writes or Times them
|
|
tmr_ld_twr = 1'b1;
|
|
cnt_next = ~cnt;
|
|
|
|
if(single_write & wb_cycle)
|
|
begin
|
|
cmd = `MC_CMD_WR;
|
|
end
|
|
cmd_a10 = ap_en | (single_write & !kro);
|
|
|
|
data_oe_d = 1'b1;
|
|
mem_ack_d = !mem_ack_r & wb_write_go & !wb_wait & wr_cycle & burst_act;
|
|
|
|
if(!cnt) cke_d = ~wb_wait;
|
|
else cke_d = cke_r;
|
|
|
|
if( (single_write & cke_r) | (!single_write & !cnt & !wb_wait) | (!single_write & cnt & cke_r) )
|
|
begin
|
|
if(single_write & !wb_cycle) next_state = IDLE_T;
|
|
else
|
|
if(burst_act & !single_write & !wb_write_go_r)
|
|
begin
|
|
cmd = `MC_CMD_BT;
|
|
next_state = BT;
|
|
end
|
|
else
|
|
if(!burst_act & !ap_en) next_state = BT_W;
|
|
else
|
|
if(!burst_act) next_state = IDLE_T;
|
|
else
|
|
if(!wb_write_go_r & wb_read_go) next_state = IDLE_T; // Added for WMR
|
|
end
|
|
end
|
|
|
|
SD_RD: // Read Command
|
|
begin
|
|
cmd = `MC_CMD_RD;
|
|
cmd_a10 = ap_en;
|
|
tmr_ld_tcl = 1'b1;
|
|
if(cmd_asserted) next_state = SD_RD_W;
|
|
end
|
|
|
|
SD_RD_W:
|
|
begin
|
|
if(tmr_done) next_state = SD_RD_LOOP;
|
|
end
|
|
|
|
SD_RD_LOOP:
|
|
begin
|
|
cnt_next = ~cnt;
|
|
|
|
if(cnt & !(burst_act & !wb_cycle) & burst_act ) cke_rd = !wb_wait;
|
|
else cke_rd = cke_;
|
|
|
|
if(wb_cycle & !cnt & burst_act_rd & cke_o_del) dv = 1'b1;
|
|
|
|
if(wb_cycle & wb_write_go) next_state = BT;
|
|
else
|
|
if(burst_act & !wb_cycle) next_state = BT;
|
|
else
|
|
if(!burst_act) next_state = SD_RD_W2;
|
|
end
|
|
|
|
SD_RD_W2:
|
|
begin
|
|
if(wb_write_go | ack_cnt_is_0)
|
|
begin
|
|
if(!ap_en & !kro) next_state = BT_W;
|
|
else
|
|
if(!wb_wait & !mem_ack_r) next_state = IDLE_T;
|
|
end
|
|
end
|
|
|
|
BT:
|
|
begin
|
|
cmd = `MC_CMD_BT;
|
|
tmr_ld_trp = 1'b1;
|
|
if(cmd_asserted) next_state = BT_W;
|
|
end
|
|
|
|
BT_W:
|
|
begin
|
|
cmd_a10 = cmd_a10_r; // Hold Auto Precharge 'til cycle finishes
|
|
|
|
if(kro & tmr_done)
|
|
begin
|
|
if(kro & !wb_wait & (wb_read_go | wb_write_go) ) cs_le_d = 1'b1;
|
|
next_state = IDLE;
|
|
end
|
|
else
|
|
if(!kro & tmr_done) // Must do a PRECHARGE after Burst Terminate
|
|
begin
|
|
bank_clr = 1'b1;
|
|
cmd = `MC_CMD_PC;
|
|
cmd_a10 = `MC_SINGLE_BANK;
|
|
tmr_ld_trp = 1'b1;
|
|
if(cmd_asserted) next_state = IDLE_T;
|
|
end
|
|
end
|
|
|
|
REFR: // Refresh Cycle
|
|
begin
|
|
cs_le_d = 1'b1;
|
|
cmd = `MC_CMD_ARFR;
|
|
tmr_ld_trfc = 1'b1;
|
|
rfr_ack_d = 1'b1;
|
|
if(cmd_asserted)
|
|
begin
|
|
susp_sel_clr = 1'b1;
|
|
next_state = IDLE_T;
|
|
end
|
|
end
|
|
|
|
LMR0:
|
|
begin
|
|
lmr_ack_d = 1'b1;
|
|
cmd = `MC_CMD_PC;
|
|
cmd_a10 = `MC_ALL_BANKS;
|
|
bank_clr_all = 1'b1;
|
|
tmr_ld_trp = 1'b1;
|
|
if(cmd_asserted) next_state = LMR1;
|
|
end
|
|
|
|
LMR1:
|
|
begin
|
|
lmr_ack_d = 1'b1;
|
|
if(tmr_done) next_state = LMR2;
|
|
end
|
|
|
|
LMR2:
|
|
begin
|
|
bank_clr_all = 1'b1;
|
|
cmd = `MC_CMD_LMR;
|
|
tmr_ld_trfc = 1'b1;
|
|
lmr_ack_d = 1'b1;
|
|
if(cmd_asserted) next_state = IDLE_T;
|
|
end
|
|
|
|
INIT0:
|
|
begin
|
|
cs_le_d = 1'b1;
|
|
next_state = INIT;
|
|
end
|
|
|
|
INIT: // Initialize SDRAMS
|
|
begin // PRECHARGE
|
|
init_ack = 1'b1;
|
|
cmd = `MC_CMD_PC;
|
|
cmd_a10 = `MC_ALL_BANKS;
|
|
bank_clr_all = 1'b1;
|
|
tmr_ld_trp = 1'b1;
|
|
ir_cnt_ld = 1'b1;
|
|
if(cmd_asserted) next_state = INIT_W;
|
|
end
|
|
|
|
INIT_W:
|
|
begin
|
|
init_ack = 1'b1;
|
|
if(tmr_done) next_state = INIT_REFR1;
|
|
end
|
|
|
|
INIT_REFR1: // Init Refresh Cycle 1
|
|
begin
|
|
init_ack = 1'b1;
|
|
cmd = `MC_CMD_ARFR;
|
|
tmr_ld_trfc = 1'b1;
|
|
if(cmd_asserted)
|
|
begin
|
|
ir_cnt_dec = 1'b1;
|
|
next_state = INIT_REFR1_W;
|
|
end
|
|
end
|
|
|
|
INIT_REFR1_W:
|
|
begin
|
|
init_ack = 1'b1;
|
|
if(tmr_done)
|
|
begin
|
|
if(ir_cnt_done) next_state = INIT_LMR;
|
|
else next_state = INIT_REFR1;
|
|
end
|
|
end
|
|
|
|
INIT_LMR:
|
|
begin
|
|
init_ack = 1'b1;
|
|
cmd = `MC_CMD_LMR;
|
|
bank_clr_all = 1'b1;
|
|
tmr_ld_trfc = 1'b1;
|
|
if(cmd_asserted) next_state = IDLE_T;
|
|
end
|
|
|
|
/////////////////////////////////////////
|
|
// Bus Arbitration STATES ....
|
|
/////////////////////////////////////////
|
|
BG0:
|
|
begin // Bus Grant
|
|
mc_bg = 1'b1;
|
|
mc_c_oe_d = 1'b0;
|
|
next_state = BG1;
|
|
end
|
|
BG1:
|
|
begin // Bus Grant
|
|
mc_bg = 1'b1;
|
|
cs_le_d = 1'b1;
|
|
mc_c_oe_d = 1'b0;
|
|
next_state = BG2;
|
|
end
|
|
BG2:
|
|
begin // Bus Grant
|
|
cs_le_d = 1'b1;
|
|
mc_bg = !wb_read_go & !wb_write_go &
|
|
!rfr_req & !init_req & !lmr_req &
|
|
!susp_req_r;
|
|
tmr_ld_tavav = 1'b1;
|
|
mc_c_oe_d = mc_br;
|
|
if(!mc_br) next_state = IDLE_T;
|
|
end
|
|
|
|
/////////////////////////////////////////
|
|
// SUSPEND/RESUME STATES ....
|
|
/////////////////////////////////////////
|
|
SUSP1:
|
|
begin // Precharge All
|
|
cmd = `MC_CMD_PC;
|
|
cmd_a10 = `MC_ALL_BANKS;
|
|
bank_clr_all = 1'b1;
|
|
tmr_ld_trp = 1'b1;
|
|
if(cmd_asserted) next_state = SUSP2;
|
|
end
|
|
|
|
SUSP2:
|
|
begin
|
|
if(tmr_done) next_state = SUSP3;
|
|
end
|
|
|
|
SUSP3:
|
|
begin // Enter Self refresh Mode
|
|
cke_d = 1'b0;
|
|
cmd = `MC_CMD_ARFR;
|
|
rfr_ack_d = 1'b1;
|
|
if(cmd_asserted)
|
|
begin
|
|
next_state = SUSP4;
|
|
end
|
|
end
|
|
|
|
SUSP4:
|
|
begin // Now we are suspended
|
|
cke_rd = 1'b0;
|
|
suspended_d = 1'b1;
|
|
tmr_ld_txsr = 1'b1;
|
|
if(resume_req_r) next_state = RESUME1;
|
|
end
|
|
|
|
RESUME1:
|
|
begin
|
|
suspended_d = 1'b1;
|
|
tmr_ld_txsr = 1'b1;
|
|
next_state = RESUME2;
|
|
end
|
|
|
|
RESUME2:
|
|
begin
|
|
suspended_d = 1'b1;
|
|
if(tmr_done) next_state = REFR;
|
|
end
|
|
|
|
// synopsys translate_off
|
|
default:
|
|
$display("MC_TIMING SM: Entered non existing state ... (%t)",$time);
|
|
// synopsys translate_on
|
|
|
|
endcase
|
|
end
|
|
|
|
endmodule
|