URL
https://opencores.org/ocsvn/wbddr3/wbddr3/trunk
Subversion Repositories wbddr3
[/] [wbddr3/] [trunk/] [rtl/] [wbddrsdram.v] - Rev 9
Go to most recent revision | Compare with Previous | Blame | View Log
//////////////////////////////////////////////////////////////////////////////// // // Filename: wbddrsdram.v // // Project: OpenArty, an entirely open SoC based upon the Arty platform // // Purpose: // /* Stall logic: 1. First clock sets r_* variables. 2. Second clock sets need_* variables. If need_open, need_close, or need_refresh are true, that should also set the o_wb_stall variable. Well also move r_* info to s_* (think s=stall) 3. If stalled, the next command comes from s_*. Otherwise, from r_*. 4. Bus FIFO fills from s_* // // For every transaction, one of 4 possibilities: 1. Wait for refresh to complete 2. Wait for precharge and activate to complete 3. Wait for activate to complete 4. Issue RW cmd 5. Wait for bus transaction to complete 6. ACK */ // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2015-2016, Gisselquist Technology, LLC // // This program is free software (firmware): you can redistribute it and/or // modify it under the terms of the GNU 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 MERCHANTIBILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with this program. (It's in the $(ROOT)/doc directory, run make with no // target there if the PDF file isn't present.) If not, see // <http://www.gnu.org/licenses/> for a copy. // // License: GPL, v3, as defined and found on www.gnu.org, // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // // Possible commands to the DDR3 memory. These consist of settings for the // bits: o_wb_cs_n, o_wb_ras_n, o_wb_cas_n, and o_wb_we_n, respectively. `define DDR_MRSET 4'b0000 `define DDR_REFRESH 4'b0001 `define DDR_PRECHARGE 4'b0010 `define DDR_ACTIVATE 4'b0011 `define DDR_WRITE 4'b0100 `define DDR_READ 4'b0101 `define DDR_ZQS 4'b0110 `define DDR_NOOP 4'b0111 //`define DDR_DESELECT 4'b1??? // // In this controller, 24-bit commands tend to be passed around. These // 'commands' are bit fields. Here we specify the bits associated with // the bit fields. `define DDR_RSTDONE 24 // End the reset sequence? `define DDR_RSTTIMER 23 // Does this reset command take multiple clocks? `define DDR_RSTBIT 22 // Value to place on reset_n `define DDR_CKEBIT 21 // Should this reset command set CKE? // // Refresh command bit fields `define DDR_NEEDREFRESH 23 `define DDR_RFTIMER 22 `define DDR_RFBEGIN 21 // `define DDR_CMDLEN 21 `define DDR_CSBIT 20 `define DDR_RASBIT 19 `define DDR_CASBIT 18 `define DDR_WEBIT 17 `define DDR_NOPTIMER 16 // Steal this from BA bits `define DDR_BABITS 3 // BABITS are really from 18:16, they are 3 bits `define DDR_ADDR_BITS 14 // `define BUSREG 7 `define BUSNOW 8 module wbddrsdram(i_clk, i_reset, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, o_wb_ack, o_wb_stall, o_wb_data, o_ddr_reset_n, o_ddr_cke, o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n, o_ddr_dqs, o_ddr_dm, o_ddr_odt, o_ddr_bus_oe, o_ddr_addr, o_ddr_ba, o_ddr_data, i_ddr_data, o_cmd_accepted); parameter CKREFI4 = 13'd6240, // 4 * 7.8us at 200 MHz clock CKRFC = 320, CKXPR = CKRFC+5+2; // Clocks per tXPR timeout input i_clk, i_reset; // Wishbone inputs input i_wb_cyc, i_wb_stb, i_wb_we; input [25:0] i_wb_addr; input [31:0] i_wb_data; // Wishbone outputs output reg o_wb_ack; output reg o_wb_stall; output reg [31:0] o_wb_data; // DDR3 RAM Controller output wire o_ddr_reset_n, o_ddr_cke; // Control outputs output reg o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n,o_ddr_we_n; // DQS outputs:set to 3'b010 when data is active, 3'b100 (i.e. 2'bzz) ow output wire o_ddr_dqs; output reg o_ddr_dm, o_ddr_odt, o_ddr_bus_oe; // Address outputs output reg [13:0] o_ddr_addr; output reg [2:0] o_ddr_ba; // And the data inputs and outputs output reg [31:0] o_ddr_data; input [31:0] i_ddr_data; // And just for the test bench output reg o_cmd_accepted; always @(posedge i_clk) o_cmd_accepted <= (i_wb_stb)&&(~o_wb_stall); reg drive_dqs; // The pending transaction reg [31:0] r_data; reg r_pending, r_we; reg [25:0] r_addr; reg [13:0] r_row; reg [2:0] r_bank; reg [9:0] r_col; reg [1:0] r_sub; reg r_move; // It was accepted, and can move to next stage // The pending transaction, one further into the pipeline. This is // the stage where the read/write command is actually given to the // interface if we haven't stalled. reg [31:0] s_data; reg s_pending, s_we, s_match; reg [25:0] s_addr; reg [13:0] s_row, s_nxt_row; reg [2:0] s_bank, s_nxt_bank; reg [9:0] s_col; reg [1:0] s_sub; // Can the pending transaction be satisfied with the current (ongoing) // transaction? reg m_move, m_match, m_pending, m_we; reg [25:0] m_addr; reg [13:0] m_row; reg [2:0] m_bank; reg [9:0] m_col; reg [1:0] m_sub; // Can we preload the next bank? reg [13:0] r_nxt_row; reg [2:0] r_nxt_bank; reg need_close_bank, need_close_this_bank, last_close_bank, maybe_close_next_bank, last_maybe_close, need_open_bank, last_open_bank, maybe_open_next_bank, last_maybe_open, valid_bank, last_valid_bank; reg [(`DDR_CMDLEN-1):0] close_bank_cmd, activate_bank_cmd, maybe_close_cmd, maybe_open_cmd, rw_cmd; reg [1:0] rw_sub; reg rw_we; wire w_this_closing_bank, w_this_opening_bank, w_this_maybe_close, w_this_maybe_open, w_this_rw_move; reg last_closing_bank, last_opening_bank; // // tWTR = 7.5 // tRRD = 7.5 // tREFI= 7.8 // tFAW = 45 // tRTP = 7.5 // tCKE = 5.625 // tRFC = 160 // tRP = 13.5 // tRAS = 36 // tRCD = 13.5 // // RESET: // 1. Hold o_reset_n = 1'b0; for 200 us, or 40,000 clocks (65536 perhaps?) // Hold cke low during this time as well // The clock should be free running into the chip during this time // Leave command in NOOP state: {cs,ras,cas,we} = 4'h7; // ODT must be held low // 2. Hold cke low for another 500us, or 100,000 clocks // 3. Raise CKE, continue outputting a NOOP for // tXPR, tDLLk, and tZQInit // 4. Load MRS2, wait tMRD // 4. Load MRS3, wait tMRD // 4. Load MRS1, wait tMOD // Before using the SDRAM, we'll need to program at least 3 of the mode // registers, if not all 4. // tMOD clocks are required to program the mode registers, during which // time the RAM must be idle. // // NOOP: CS low, RAS, CAS, and WE high // // Reset logic should be simple, and is given as follows: // note that it depends upon a ROM memory, reset_mem, and an address into that // memory: reset_address. Each memory location provides either a "command" to // the DDR3 SDRAM, or a timer to wait until the next command. Further, the // timer commands indicate whether or not the command during the timer is to // be set to idle, or whether the command is instead left as it was. reg reset_override, reset_ztimer, maintenance_override; reg [4:0] reset_address; reg [(`DDR_CMDLEN-1):0] reset_cmd, cmd, refresh_cmd, maintenance_cmd; reg [24:0] reset_instruction; reg [16:0] reset_timer; initial reset_override = 1'b1; initial reset_address = 5'h0; always @(posedge i_clk) if (i_reset) begin reset_override <= 1'b1; reset_cmd <= { `DDR_NOOP, reset_instruction[16:0]}; end else if (reset_ztimer) begin if (reset_instruction[`DDR_RSTDONE]) reset_override <= 1'b0; reset_cmd <= reset_instruction[20:0]; end always @(posedge i_clk) if (i_reset) o_ddr_cke <= 1'b0; else if ((reset_override)&&(reset_ztimer)) o_ddr_cke <= reset_instruction[`DDR_CKEBIT]; initial reset_ztimer = 1'b0; // Is the timer zero? initial reset_timer = 17'h02; always @(posedge i_clk) if (i_reset) begin reset_ztimer <= 1'b0; reset_timer <= 17'd2; end else if (!reset_ztimer) begin reset_ztimer <= (reset_timer == 17'h01); reset_timer <= reset_timer - 17'h01; end else if (reset_instruction[`DDR_RSTTIMER]) begin reset_ztimer <= 1'b0; reset_timer <= reset_instruction[16:0]; end wire [16:0] w_ckXPR = CKXPR, w_ckRST = 4, w_ckRP = 3, w_ckRFC = CKRFC; always @(posedge i_clk) if (i_reset) reset_instruction <= { 4'h4, `DDR_NOOP, 17'd40_000 }; else if (reset_ztimer) case(reset_address) // RSTDONE, TIMER, CKE, ?? // 1. Reset asserted (active low) for 200 us. (@200MHz) 5'h0: reset_instruction <= { 4'h4, `DDR_NOOP, 17'd40_000 }; // 2. Reset de-asserted, wait 500 us before asserting CKE 5'h1: reset_instruction <= { 4'h6, `DDR_NOOP, 17'd100_000 }; // 3. Assert CKE, wait minimum of Reset CKE Exit time 5'h2: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckXPR }; // 4. Look MR2. (1CK, no TIMER) 5'h3: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h2, 3'h0, 2'b00, 1'b0, 1'b0, 1'b1, 3'b0, 3'b0 }; // MRS2 // 3. Wait 4 clocks (tMRD) 5'h4: reset_instruction <= { 4'h7, `DDR_NOOP, 17'h02 }; // 5. Set MR1 5'h5: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h1, 1'h0, // Reserved for Future Use (RFU) 1'b0, // Qoff - output buffer enabled 1'b1, // TDQS ... enabled 1'b0, // RFU 1'b0, // High order bit, Rtt_Nom (3'b011) 1'b0, // RFU // 1'b0, // Disable write-leveling 1'b1, // Mid order bit of Rtt_Nom 1'b0, // High order bit of Output Drvr Impedence Ctrl 2'b0, // Additive latency = 0 1'b1, // Low order bit of Rtt_Nom 1'b1, // DIC set to 2'b01 1'b1 }; // MRS1, DLL enable // 7. Wait another 4 clocks 5'h6: reset_instruction <= { 4'h7, `DDR_NOOP, 17'h02 }; // 8. Send MRS0 5'h7: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h0, 1'b0, // Reserved for future use 1'b0, // PPD control, (slow exit(DLL off)) 3'b1, // Write recovery for auto precharge 1'b0, // DLL Reset (No) // 1'b0, // TM mode normal 3'b01, // High 3-bits, CAS latency (=4'b0010 = 4'd5) 1'b0, // Read burst type = nibble sequential 1'b0, // Low bit of cas latency 2'b0 }; // Burst length = 8 (Fixed) // 9. Wait tMOD, is max(12 clocks, 15ns) 5'h8: reset_instruction <= { 4'h7, `DDR_NOOP, 17'h0a }; // 10. Issue a ZQCL command to start ZQ calibration, A10 is high 5'h9: reset_instruction <= { 4'h3, `DDR_ZQS, 6'h0, 1'b1, 10'h0}; //11.Wait for both tDLLK and tZQinit completed, both are 512 cks 5'ha: reset_instruction <= { 4'h7, `DDR_NOOP, 17'd512 }; // 12. Precharge all command 5'hb: reset_instruction <= { 4'h3, `DDR_PRECHARGE, 6'h0, 1'b1, 10'h0 }; // 13. Wait for the precharge to complete 5'hc: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRP }; // 14. A single Auto Refresh commands 5'hd: reset_instruction <= { 4'h3, `DDR_REFRESH, 17'h00 }; // 15. Wait for the auto refresh to complete 5'he: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRFC }; // Two Auto Refresh commands default: reset_instruction <={4'hb, `DDR_NOOP, 17'd00_000 }; endcase // reset_instruction <= reset_mem[reset_address]; initial reset_address = 5'h0; always @(posedge i_clk) if (i_reset) reset_address <= 5'h1; else if ((reset_ztimer)&&(reset_override)) reset_address <= reset_address + 5'h1; // // initial reset_mem = // 0. !DONE, TIMER,RESET_N=0, CKE=0, CMD = NOOP, TIMER = 200us ( 40,000) // 1. !DONE, TIMER,RESET_N=1, CKE=0, CMD = NOOP, TIMER = 500us (100,000) // 2. !DONE, TIMER,RESET_N=1, CKE=1, CMD = NOOP, TIMER = (Look me up) // 3. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = MODE, MRS // 4. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = NOOP, TIMER = tMRS // 5. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = MODE, MRS3 // 6. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = NOOP, TIMER = tMRS // 7. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = MODE, MRS1 // 8. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = NOOP, TIMER = tMRS // 9. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = MODE, MRS1 // 10. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = NOOP, TIMER = tMOD // 11. !DONE,!TIMER,RESET_N=1, CKE=1, (Pre-charge all) // 12. !DONE,!TIMER,RESET_N=1, CKE=1, (wait) // 13. !DONE,!TIMER,RESET_N=1, CKE=1, (Auto-refresh) // 14. !DONE,!TIMER,RESET_N=1, CKE=1, (Auto-refresh) // 15. !DONE,!TIMER,RESET_N=1, CKE=1, (wait) // // // Let's keep track of any open banks. There are 8 of them to keep track of. // // A precharge requires 3 clocks at 200MHz to complete, 2 clocks at 100MHz. // // // reg need_refresh; wire w_precharge_all; reg banks_are_closing, all_banks_closed; reg [3:0] bank_status [0:7]; reg [13:0] bank_address [0:7]; always @(posedge i_clk) begin bank_status[0] <= { bank_status[0][2:0], bank_status[0][0] }; bank_status[1] <= { bank_status[1][2:0], bank_status[1][0] }; bank_status[2] <= { bank_status[2][2:0], bank_status[2][0] }; bank_status[3] <= { bank_status[3][2:0], bank_status[3][0] }; bank_status[4] <= { bank_status[4][2:0], bank_status[4][0] }; bank_status[5] <= { bank_status[5][2:0], bank_status[5][0] }; bank_status[6] <= { bank_status[6][2:0], bank_status[6][0] }; bank_status[7] <= { bank_status[7][2:0], bank_status[7][0] }; all_banks_closed <= (bank_status[0][2:0] == 3'b00) &&(bank_status[1][2:0] == 3'b00) &&(bank_status[2][2:0] == 3'b00) &&(bank_status[3][2:0] == 3'b00) &&(bank_status[4][2:0] == 3'b00) &&(bank_status[5][2:0] == 3'b00) &&(bank_status[6][2:0] == 3'b00) &&(bank_status[7][2:0] == 3'b00); if (reset_override) begin bank_status[0][0] <= 1'b0; bank_status[1][0] <= 1'b0; bank_status[2][0] <= 1'b0; bank_status[3][0] <= 1'b0; bank_status[4][0] <= 1'b0; bank_status[5][0] <= 1'b0; bank_status[6][0] <= 1'b0; bank_status[7][0] <= 1'b0; banks_are_closing <= 1'b1; end else if ((need_refresh)||(w_precharge_all)) begin bank_status[0][0] <= 1'b0; bank_status[1][0] <= 1'b0; bank_status[2][0] <= 1'b0; bank_status[3][0] <= 1'b0; bank_status[4][0] <= 1'b0; bank_status[5][0] <= 1'b0; bank_status[6][0] <= 1'b0; bank_status[7][0] <= 1'b0; banks_are_closing <= 1'b1; end else if (need_close_bank) begin bank_status[close_bank_cmd[16:14]] <= { bank_status[close_bank_cmd[16:14]][2:0], 1'b0 }; // bank_status[close_bank_cmd[16:14]][0] <= 1'b0; end else if (need_open_bank) begin bank_status[activate_bank_cmd[16:14]] <= { bank_status[activate_bank_cmd[16:14]][2:0], 1'b1 }; // bank_status[activate_bank_cmd[16:14]][0] <= 1'b1; all_banks_closed <= 1'b0; banks_are_closing <= 1'b0; end else if ((valid_bank)&&(!r_move)) ; else if (maybe_close_next_bank) begin bank_status[maybe_close_cmd[16:14]] <= { bank_status[maybe_close_cmd[16:14]][2:0], 1'b0 }; end else if (maybe_open_next_bank) begin bank_status[maybe_open_cmd[16:14]] <= { bank_status[maybe_open_cmd[16:14]][2:0], 1'b1 }; // bank_status[activate_bank_cmd[16:14]][0] <= 1'b1; all_banks_closed <= 1'b0; banks_are_closing <= 1'b0; end end always @(posedge i_clk) // if (cmd[22:19] == `DDR_ACTIVATE) if (w_this_opening_bank) bank_address[activate_bank_cmd[16:14]] <= activate_bank_cmd[13:0]; else if (!w_this_maybe_open) bank_address[maybe_open_cmd[16:14]] <= maybe_open_cmd[13:0]; // // // Okay, let's investigate when we need to do a refresh. Our plan will be to // do 4 refreshes every tREFI*4 seconds. tREFI = 7.8us, but its a parameter // in the number of clocks so that we can handle both 100MHz and 200MHz clocks. // // Note that 160ns are needed between refresh commands (JEDEC, p172), or // 320 clocks @200MHz, or equivalently 160 clocks @100MHz. Thus to issue 4 // of these refresh cycles will require 4*320=1280 clocks@200 MHz. After this // time, no more refreshes will be needed for 6240 clocks. // // Let's think this through: // REFRESH_COST = (n*(320)+24)/(n*1560) // // // reg refresh_ztimer; reg [16:0] refresh_counter; reg [3:0] refresh_addr; reg [23:0] refresh_instruction; always @(posedge i_clk) if (reset_override) refresh_addr <= 4'hf; else if (refresh_ztimer) refresh_addr <= refresh_addr + 1; else if (refresh_instruction[`DDR_RFBEGIN]) refresh_addr <= 4'h0; always @(posedge i_clk) if (reset_override) begin refresh_ztimer <= 1'b1; refresh_counter <= 17'd0; end else if (!refresh_ztimer) begin refresh_ztimer <= (refresh_counter == 17'h1); refresh_counter <= (refresh_counter - 17'h1); end else if (refresh_instruction[`DDR_RFTIMER]) begin refresh_ztimer <= 1'b0; refresh_counter <= refresh_instruction[16:0]; end wire [16:0] w_ckREFIn, w_ckREFRst; assign w_ckREFIn[ 12: 0] = CKREFI4-5*CKRFC-2-10; assign w_ckREFIn[ 16:13] = 4'h0; assign w_ckREFRst[12: 0] = CKRFC-2-12; assign w_ckREFRst[16:13] = 4'h0; always @(posedge i_clk) if (reset_override) refresh_instruction <= { 3'h0, `DDR_NOOP, w_ckREFIn }; else if (refresh_ztimer) refresh_cmd <= refresh_instruction[20:0]; always @(posedge i_clk) if (reset_override) need_refresh <= 1'b0; else if (refresh_ztimer) need_refresh <= refresh_instruction[`DDR_NEEDREFRESH]; always @(posedge i_clk) if (refresh_ztimer) case(refresh_addr)//NEED-RFC, HAVE-TIMER, 4'h0: refresh_instruction <= { 3'h2, `DDR_NOOP, w_ckREFIn }; // 17'd10 = time to complete write, plus write recovery time // minus two (cause we can't count zero or one) // = WL+4+tWR-2 = 10 // = 5+4+3-2 = 10 4'h1: refresh_instruction <= { 3'h6, `DDR_NOOP, 17'd10 }; 4'h2: refresh_instruction <= { 3'h4, `DDR_PRECHARGE, 17'h0400 }; 4'h3: refresh_instruction <= { 3'h6, `DDR_NOOP, 17'd2 }; 4'h4: refresh_instruction <= { 3'h4, `DDR_REFRESH, 17'h00 }; 4'h5: refresh_instruction <= { 3'h6, `DDR_NOOP, w_ckRFC }; 4'h6: refresh_instruction <= { 3'h4, `DDR_REFRESH, 17'h00 }; 4'h7: refresh_instruction <= { 3'h6, `DDR_NOOP, w_ckRFC }; 4'h8: refresh_instruction <= { 3'h4, `DDR_REFRESH, 17'h00 }; 4'h9: refresh_instruction <= { 3'h6, `DDR_NOOP, w_ckRFC }; 4'ha: refresh_instruction <= { 3'h4, `DDR_REFRESH, 17'h00 }; 4'hb: refresh_instruction <= { 3'h6, `DDR_NOOP, w_ckRFC }; 4'hc: refresh_instruction <= { 3'h2, `DDR_NOOP, w_ckREFRst }; default: refresh_instruction <= { 3'h1, `DDR_NOOP, 17'h00 }; endcase // // // Let's track: when will our bus be active? When will we be reading or // writing? // // reg [`BUSNOW:0] bus_active, bus_read, bus_new; reg [1:0] bus_subaddr [`BUSNOW:0]; initial bus_active = 0; always @(posedge i_clk) begin bus_active[`BUSNOW:0] <= { bus_active[(`BUSNOW-1):0], 1'b0 }; bus_read[`BUSNOW:0] <= { bus_read[(`BUSNOW-1):0], 1'b0 }; // Drive the d-bus? // Is this a new command? i.e., the start of a transaction? bus_new[`BUSNOW:0] <= { bus_new[(`BUSNOW-1):0], 1'b0 }; //bus_mask[8:0] <= { bus_mask[7:0], 1'b1 }; // Write this value? bus_subaddr[8] <= bus_subaddr[7]; bus_subaddr[7] <= bus_subaddr[6]; bus_subaddr[6] <= bus_subaddr[5]; bus_subaddr[5] <= bus_subaddr[4]; bus_subaddr[4] <= bus_subaddr[3]; bus_subaddr[3] <= bus_subaddr[2]; bus_subaddr[2] <= bus_subaddr[1]; bus_subaddr[1] <= bus_subaddr[0]; bus_subaddr[0] <= 2'h3; if (w_this_rw_move) begin bus_active[3:0]<= 4'hf; // Once per clock bus_read[3:0] <= 4'hf; // These will be reads bus_subaddr[3] <= 2'h0; bus_subaddr[2] <= 2'h1; bus_subaddr[1] <= 2'h2; bus_new[{ 2'b0, rw_sub }] <= 1'b1; bus_read[3:0] <= (rw_we)? 4'h0:4'hf; end end always @(posedge i_clk) drive_dqs <= (~bus_read[`BUSREG])&&(|bus_active[`BUSREG]); // // // Now, let's see, can we issue a read command? // // wire w_s_match; assign w_s_match = (s_pending)&&(r_pending)&&(r_we == s_we) &&(r_row == s_row)&&(r_bank == s_bank) &&(r_col == s_col) &&(r_sub > s_sub); reg pipe_stall; always @(posedge i_clk) begin r_pending <= (i_wb_stb)&&(~o_wb_stall) ||(r_pending)&&(pipe_stall); if (~pipe_stall) s_pending <= r_pending; if (~pipe_stall) begin pipe_stall <= (r_pending)&&(((!w_r_valid)||(valid_bank))&&(!w_s_match)); o_wb_stall <= (r_pending)&&(((!w_r_valid)||(valid_bank))&&(!w_s_match)); end else begin // if (pipe_stall) pipe_stall <= (s_pending)&&((!w_s_valid)||(valid_bank)||(r_move)||(last_valid_bank)); o_wb_stall <= (s_pending)&&((!w_s_valid)||(valid_bank)||(r_move)||(last_valid_bank)); end if (need_refresh) o_wb_stall <= 1'b1; if (~pipe_stall) begin r_we <= i_wb_we; r_addr <= i_wb_addr; r_data <= i_wb_data; r_row <= i_wb_addr[25:12]; r_bank <= i_wb_addr[11:9]; r_col <= { i_wb_addr[8:2], 3'b000 }; // 9:2 r_sub <= i_wb_addr[1:0]; // pre-emptive work r_nxt_row <= (i_wb_addr[11:9]==3'h7)?i_wb_addr[25:12]+14'h1:i_wb_addr[25:12]; r_nxt_bank <= i_wb_addr[11:9]+3'h1; end if (~pipe_stall) begin // Moving one down the pipeline s_we <= r_we; s_addr <= r_addr; s_data <= r_data; s_row <= r_row; s_bank <= r_bank; s_col <= r_col; s_sub <= r_sub; // pre-emptive work s_nxt_row <= r_nxt_row; s_nxt_bank <= r_nxt_bank; s_match <= w_s_match; end end wire w_need_close_this_bank, w_need_open_bank, w_r_valid, w_s_valid; assign w_need_close_this_bank = (r_pending)&&(bank_status[r_bank][0]) &&(r_row != bank_address[r_bank]) ||(pipe_stall)&&(s_pending)&&(bank_status[s_bank][0]) &&(s_row != bank_address[s_bank]); assign w_need_open_bank = (r_pending)&&(bank_status[r_bank][1:0]==2'b00) ||(pipe_stall)&&(s_pending)&&(bank_status[s_bank][1:0]==2'b00); assign w_r_valid = (!need_refresh)&&(r_pending) &&(bank_status[r_bank][3]) &&(bank_address[r_bank]==r_row) &&(!bus_active[0]); assign w_s_valid = (!need_refresh)&&(s_pending) &&(bank_status[s_bank][3]) &&(bank_address[s_bank]==s_row) &&(!bus_active[0]); always @(posedge i_clk) begin need_close_bank <= (w_need_close_this_bank) &&(!w_this_closing_bank)&&(!last_closing_bank); maybe_close_next_bank <= (r_pending) &&(bank_status[r_nxt_bank][0]) &&(r_nxt_row != bank_address[r_nxt_bank]) &&(!w_this_maybe_close)&&(!last_maybe_close); close_bank_cmd <= { `DDR_PRECHARGE, r_bank, r_row[13:11], 1'b0, r_row[9:0] }; maybe_close_cmd <= { `DDR_PRECHARGE, r_nxt_bank, r_nxt_row[13:11], 1'b0, r_nxt_row[9:0] }; need_open_bank <= (w_need_open_bank) &&(!w_this_opening_bank)&&(!last_opening_bank); last_open_bank <= (w_this_opening_bank); maybe_open_next_bank <= (r_pending) &&(bank_status[r_bank][0] == 1'b1) &&(bank_status[r_nxt_bank][1:0] == 2'b00) &&(!w_this_maybe_open)&&(!last_maybe_open); last_maybe_open <= (w_this_maybe_open); activate_bank_cmd<= { `DDR_ACTIVATE, r_bank, r_row[13:0] }; maybe_open_cmd <= { `DDR_ACTIVATE,r_nxt_bank, r_nxt_row[13:0] }; valid_bank <= ((w_r_valid)||(pipe_stall)&&(w_s_valid)) &&(!last_valid_bank)&&(!r_move); last_valid_bank <= r_move; if ((s_pending)&&(pipe_stall)) rw_cmd[`DDR_CSBIT:`DDR_WEBIT] <= (s_we)?`DDR_WRITE:`DDR_READ; else if (r_pending) rw_cmd[`DDR_CSBIT:`DDR_WEBIT] <= (r_we)?`DDR_WRITE:`DDR_READ; else rw_cmd[`DDR_CSBIT:`DDR_WEBIT] <= `DDR_NOOP; if ((s_pending)&&(pipe_stall)) rw_cmd[`DDR_WEBIT-1:0] <= { s_bank, 3'h0, 1'b0, s_col }; else rw_cmd[`DDR_WEBIT-1:0] <= { r_bank, 3'h0, 1'b0, r_col }; if ((s_pending)&&(pipe_stall)) rw_sub <= 2'b11 - s_sub; else rw_sub <= 2'b11 - r_sub; if ((s_pending)&&(pipe_stall)) rw_we <= s_we; else rw_we <= r_we; end // // // Okay, let's look at the last assignment in our chain. It should look // something like: always @(posedge i_clk) if (i_reset) o_ddr_reset_n <= 1'b0; else if (reset_ztimer) o_ddr_reset_n <= reset_instruction[`DDR_RSTBIT]; always @(posedge i_clk) if (i_reset) o_ddr_cke <= 1'b0; else if (reset_ztimer) o_ddr_cke <= reset_instruction[`DDR_CKEBIT]; always @(posedge i_clk) if (i_reset) maintenance_override <= 1'b1; else maintenance_override <= (reset_override)||(need_refresh); initial maintenance_cmd = { `DDR_NOOP, 17'h00 }; always @(posedge i_clk) if (i_reset) maintenance_cmd <= { `DDR_NOOP, 17'h00 }; else maintenance_cmd <= (reset_override)?reset_cmd:refresh_cmd; assign w_this_closing_bank = (!maintenance_override) &&(need_close_bank); assign w_this_opening_bank = (!maintenance_override) &&(!need_close_bank)&&(need_open_bank); assign w_this_rw_move = (!maintenance_override) &&(!need_close_bank)&&(!need_open_bank) &&(valid_bank)&&(!r_move); assign w_this_maybe_close = (!maintenance_override) &&(!need_close_bank)&&(!need_open_bank) &&((!valid_bank)||(r_move)) &&(maybe_close_next_bank); assign w_this_maybe_open = (!maintenance_override) &&(!need_close_bank)&&(!need_open_bank) &&((!valid_bank)||(r_move)) &&(!maybe_close_next_bank) &&(maybe_open_next_bank); always @(posedge i_clk) begin last_opening_bank <= 1'b0; last_closing_bank <= 1'b0; last_maybe_open <= 1'b0; last_maybe_close <= 1'b0; r_move <= 1'b0; if (maintenance_override) // Command from either reset or cmd <= maintenance_cmd; // refresh logic else if (need_close_bank) begin cmd <= close_bank_cmd; last_closing_bank <= 1'b1; end else if (need_open_bank) begin cmd <= activate_bank_cmd; last_opening_bank <= 1'b1; end else if ((valid_bank)&&(!r_move)) begin cmd <= rw_cmd; r_move <= 1'b1; end else if (maybe_close_next_bank) begin cmd <= maybe_close_cmd; last_maybe_close <= 1'b1; end else if (maybe_open_next_bank) begin cmd <= maybe_open_cmd; last_maybe_open <= 1'b1; end else cmd <= { `DDR_NOOP, rw_cmd[(`DDR_WEBIT-1):0] }; end `define LGFIFOLN 4 `define FIFOLEN 16 reg [(`LGFIFOLN-1):0] bus_fifo_head, bus_fifo_tail; reg [31:0] bus_fifo_data [0:(`FIFOLEN-1)]; reg [1:0] bus_fifo_sub [0:(`FIFOLEN-1)]; reg bus_fifo_new [0:(`FIFOLEN-1)]; reg pre_ack; // The bus R/W FIFO wire w_bus_fifo_read_next_transaction; assign w_bus_fifo_read_next_transaction = (bus_fifo_sub[bus_fifo_tail]==bus_subaddr[`BUSREG]) &&(bus_fifo_tail != bus_fifo_head) &&(bus_active[`BUSREG]) &&(bus_new[`BUSREG] == bus_fifo_new[bus_fifo_tail]); always @(posedge i_clk) begin pre_ack <= 1'b0; o_ddr_dm <= 1'b0; if ((i_reset)||(reset_override)) begin bus_fifo_head <= 4'h0; bus_fifo_tail <= 4'h0; o_ddr_dm <= 1'b0; end else begin if ((w_this_rw_move)||((s_pending)&&(s_match)&&(!pipe_stall))) bus_fifo_head <= bus_fifo_head + 4'h1; o_ddr_dm <= (bus_active[`BUSREG])&&(!bus_read[`BUSREG]); if (w_bus_fifo_read_next_transaction) begin bus_fifo_tail <= bus_fifo_tail + 4'h1; pre_ack <= 1'b1; o_ddr_dm <= 1'b0; end end bus_fifo_data[bus_fifo_head] <= s_data; bus_fifo_sub[bus_fifo_head] <= s_sub; bus_fifo_new[bus_fifo_head] <= w_this_rw_move; end assign o_ddr_cs_n = cmd[`DDR_CSBIT]; assign o_ddr_ras_n = cmd[`DDR_RASBIT]; assign o_ddr_cas_n = cmd[`DDR_CASBIT]; assign o_ddr_we_n = cmd[`DDR_WEBIT]; assign o_ddr_dqs = drive_dqs; assign o_ddr_addr = cmd[(`DDR_ADDR_BITS-1):0]; assign o_ddr_ba = cmd[(`DDR_BABITS+`DDR_ADDR_BITS-1):`DDR_ADDR_BITS]; always @(posedge i_clk) o_ddr_data <= bus_fifo_data[bus_fifo_tail]; assign w_precharge_all = (cmd[`DDR_CSBIT:`DDR_WEBIT]==`DDR_PRECHARGE) &&(o_ddr_addr[10]); // 5 bits // Need to set o_wb_dqs high one clock prior to any read. // As per spec, ODT = 0 during reads assign o_ddr_bus_oe = ~bus_read[`BUSNOW]; // ODT must be in high impedence while reset_n=0, then it can be set // to low or high. assign o_ddr_odt = o_ddr_bus_oe; always @(posedge i_clk) o_wb_ack <= pre_ack; always @(posedge i_clk) o_wb_data <= i_ddr_data; endmodule
Go to most recent revision | Compare with Previous | Blame | View Log