?? ctrl.v
字號:
refi_cnt_ok_r <= 1'b1; else refi_cnt_ok_r <= 1'b0; end // auto refresh interval counter in refresh_clk domain always @(posedge clk) begin if ((rst_r1) || (refi_cnt_ok_r)) begin refi_cnt_r <= 12'd0; end else begin refi_cnt_r <= refi_cnt_r + 1; end end // always @ (posedge clk) // auto refresh flag always @(posedge clk) begin if (refi_cnt_ok_r) begin ref_flag_r <= 1'b1; end else begin ref_flag_r <= 1'b0; end end // always @ (posedge clk) assign ctrl_ref_flag = ref_flag_r; //refresh flag detect //auto_ref high indicates auto_refresh requirement //auto_ref is held high until auto refresh command is issued. always @(posedge clk)begin if (rst_r1) auto_ref_r <= 1'b0; else if (ref_flag_r) auto_ref_r <= 1'b1; else if (state_r == CTRL_AUTO_REFRESH) auto_ref_r <= 1'b0; end // keep track of which chip selects got auto-refreshed (avoid auto-refreshing // all CS's at once to avoid current spike) always @(posedge clk)begin if (rst_r1 || (state_r1 == CTRL_PRECHARGE)) auto_cnt_r <= 'd0; else if (state_r == CTRL_AUTO_REFRESH) auto_cnt_r <= auto_cnt_r + 1; end // register for timing purposes. Extra delay doesn't really matter always @(posedge clk) phy_init_done_r <= phy_init_done; always @(posedge clk)begin if (rst_r1) begin state_r <= CTRL_IDLE; state_r1 <= CTRL_IDLE; end else begin state_r <= next_state; state_r1 <= state_r; end end //*************************************************************************** // main control state machine //*************************************************************************** always @(*) begin next_state = state_r; (* full_case, parallel_case *) case (state_r) CTRL_IDLE: begin // perform auto refresh as soon as we are done with calibration. // The calibration logic does not do any refreshes. if (phy_init_done_r) next_state = CTRL_AUTO_REFRESH; end CTRL_PRECHARGE: begin if (auto_ref_r) next_state = CTRL_PRECHARGE_WAIT1; // when precharging an LRU bank, do not have to go to wait state // since we can't possibly be activating row in same bank next // disabled for 2t timing. There needs to be a gap between cmds // in 2t timing else if (no_precharge_wait_r && !TWO_T_TIME_EN) next_state = CTRL_ACTIVE; else next_state = CTRL_PRECHARGE_WAIT; end CTRL_PRECHARGE_WAIT:begin if (rp_cnt_ok_r)begin if (auto_ref_r) // precharge again to make sure we close all the banks next_state = CTRL_PRECHARGE; else next_state = CTRL_ACTIVE; end end CTRL_PRECHARGE_WAIT1: if (rp_cnt_ok_r) next_state = CTRL_AUTO_REFRESH; CTRL_AUTO_REFRESH: next_state = CTRL_AUTO_REFRESH_WAIT; CTRL_AUTO_REFRESH_WAIT: //staggering Auto refresh for multi // chip select designs. The SM waits // for the rfc time before issuing the // next auto refresh. if (auto_cnt_r < (CS_NUM))begin if (rfc_ok_r ) next_state = CTRL_AUTO_REFRESH; end else if (rfc_ok_r)begin if(auto_ref_r) next_state = CTRL_AUTO_REFRESH; else if ( wr_flag || rd_flag) next_state = CTRL_ACTIVE; end CTRL_ACTIVE: next_state = CTRL_ACTIVE_WAIT; CTRL_ACTIVE_WAIT: begin if (rcd_cnt_ok_r) begin if ((conflict_detect_r && ~conflict_resolved_r) || auto_ref_r) begin if (no_precharge_r1 && ~auto_ref_r && trrd_cnt_ok_r) next_state = CTRL_ACTIVE; else if(precharge_ok_r) next_state = CTRL_PRECHARGE; end else if ((wr_flag_r) && (rd_to_wr_ok_r)) next_state = CTRL_BURST_WRITE; else if ((rd_flag_r)&& (wr_to_rd_ok_r)) next_state = CTRL_BURST_READ; end end // beginning of write burst CTRL_BURST_WRITE: begin if (BURST_LEN_DIV2 == 1) begin // special case if BL = 2 (i.e. burst lasts only one clk cycle) if (wr_flag) // if we have another non-conflict write command right after the // current write, then stay in this state next_state = CTRL_BURST_WRITE; else // otherwise, if we're done with this burst, and have no write // immediately scheduled after this one, wait until write-read // delay has passed next_state = CTRL_WRITE_WAIT; end else // otherwise BL > 2, and we have at least one more write cycle for // current burst next_state = CTRL_WRITE_WAIT; // continuation of write burst (also covers waiting after write burst // has completed for write-read delay to pass) end CTRL_WRITE_WAIT: begin if ((conflict_detect) || auto_ref_r) begin if (no_precharge_r && ~auto_ref_r && wrburst_ok_r) next_state = CTRL_ACTIVE; else if (precharge_ok_r) next_state = CTRL_PRECHARGE; end else if (wrburst_ok_r && wr_flag) next_state = CTRL_BURST_WRITE; else if ((rd_flag) && (wr_to_rd_ok_r)) next_state = CTRL_BURST_READ; end CTRL_BURST_READ: begin if (BURST_LEN_DIV2 == 1) begin // special case if BL = 2 (i.e. burst lasts only one clk cycle) if (rd_flag) next_state = CTRL_BURST_READ; else next_state = CTRL_READ_WAIT; end else next_state = CTRL_READ_WAIT; end CTRL_READ_WAIT: begin if ((conflict_detect) || auto_ref_r)begin if (no_precharge_r && ~auto_ref_r && rdburst_ok_r) next_state = CTRL_ACTIVE; else if (precharge_ok_r) next_state = CTRL_PRECHARGE; end else if (rdburst_ok_r && rd_flag) next_state = CTRL_BURST_READ; else if (wr_flag && (rd_to_wr_ok_r)) next_state = CTRL_BURST_WRITE; end endcase end //*************************************************************************** // control signals to memory //*************************************************************************** always @(posedge clk) begin if ((state_r == CTRL_AUTO_REFRESH) || (state_r == CTRL_ACTIVE) || (state_r == CTRL_PRECHARGE)) begin ddr_ras_n_r <= 1'b0; two_t_enable_r[0] <= 1'b0; end else begin if (TWO_T_TIME_EN) ddr_ras_n_r <= two_t_enable_r[0] ; else ddr_ras_n_r <= 1'd1; two_t_enable_r[0] <= 1'b1; end end always @(posedge clk)begin if ((state_r == CTRL_BURST_WRITE) || (state_r == CTRL_BURST_READ) || (state_r == CTRL_AUTO_REFRESH)) begin ddr_cas_n_r <= 1'b0; two_t_enable_r[1] <= 1'b0; end else begin if (TWO_T_TIME_EN) ddr_cas_n_r <= two_t_enable_r[1]; else ddr_cas_n_r <= 1'b1; two_t_enable_r[1] <= 1'b1; end end always @(posedge clk) begin if ((state_r == CTRL_BURST_WRITE) || (state_r == CTRL_PRECHARGE)) begin ddr_we_n_r <= 1'b0; two_t_enable_r[2] <= 1'b0; end else begin if(TWO_T_TIME_EN) ddr_we_n_r <= two_t_enable_r[2]; else ddr_we_n_r <= 1'b1; two_t_enable_r[2] <= 1'b1; end end // turn off auto-precharge when issuing commands (A10 = 0) // mapping the col add for linear addressing. generate if (TWO_T_TIME_EN) begin: gen_addr_col_two_t if (COL_WIDTH == ROW_WIDTH-1) begin: gen_ddr_addr_col_0 assign ddr_addr_col = {af_addr_r3[COL_WIDTH-1:10], 1'b0, af_addr_r3[9:0]}; end else begin if (COL_WIDTH > 10) begin: gen_ddr_addr_col_1 assign ddr_addr_col = {{(ROW_WIDTH-COL_WIDTH-1){1'b0}}, af_addr_r3[COL_WIDTH-1:10], 1'b0, af_addr_r3[9:0]}; end else begin: gen_ddr_addr_col_2 assign ddr_addr_col = {{(ROW_WIDTH-COL_WIDTH-1){1'b0}}, 1'b0, af_addr_r3[COL_WIDTH-1:0]}; end end end else begin: gen_addr_col_one_t if (COL_WIDTH == ROW_WIDTH-1) begin: gen_ddr_addr_col_0_1 assign ddr_addr_col = {af_addr_r2[COL_WIDTH-1:10], 1'b0, af_addr_r2[9:0]}; end else begin if (COL_WIDTH > 10) begin: gen_ddr_addr_col_1_1 assign ddr_addr_col = {{(ROW_WIDTH-COL_WIDTH-1){1'b0}}, af_addr_r2[COL_WIDTH-1:10], 1'b0, af_addr_r2[9:0]}; end else begin: gen_ddr_addr_col_2_1 assign ddr_addr_col = {{(ROW_WIDTH-COL_WIDTH-1){1'b0}}, 1'b0, af_addr_r2[COL_WIDTH-1:0]}; end end end endgenerate // Assign address during row activate generate if (TWO_T_TIME_EN) assign ddr_addr_row = af_addr_r3[ROW_RANGE_END:ROW_RANGE_START]; else assign ddr_addr_row = af_addr_r2[ROW_RANGE_END:ROW_RANGE_START]; endgenerate always @(posedge clk)begin if ((state_r == CTRL_ACTIVE) || ((state_r1 == CTRL_ACTIVE) && TWO_T_TIME_EN)) ddr_addr_r <= ddr_addr_row; else if ((state_r == CTRL_BURST_WRITE) || (state_r == CTRL_BURST_READ) || (((state_r1 == CTRL_BURST_WRITE) || (state_r1 == CTRL_BURST_READ)) && TWO_T_TIME_EN)) ddr_addr_r <= ddr_addr_col; else if (((state_r == CTRL_PRECHARGE) || ((state_r1 == CTRL_PRECHARGE) && TWO_T_TIME_EN)) && auto_ref_r) begin // if we're precharging as a result of AUTO-REFRESH, precharge all banks ddr_addr_r <= {ROW_WIDTH{1'b0}}; ddr_addr_r[10] <= 1'b1; end else if ((state_r == CTRL_PRECHARGE) || ((state_r1 == CTRL_PRECHARGE) && TWO_T_TIME_EN)) // if we're precharging to close a specific bank/row, set A10=0 ddr_addr_r <= {ROW_WIDTH{1'b0}}; else ddr_addr_r <= {ROW_WIDTH{1'bx}}; end always @(posedge clk)begin // whenever we're precharging, we're either: (1) precharging all banks (in // which case banks bits are don't care, (2) precharging the LRU bank, // b/c we've exceeded the limit of # of banks open (need to close the LRU // bank to make room for a new one), (3) we haven't exceed the maximum # // of banks open, but we trying to open a different row in a bank that's // already open if (((state_r == CTRL_PRECHARGE) || ((state_r1 == CTRL_PRECHARGE) && TWO_T_TIME_EN)) && bank_conflict_r && MULTI_BANK_EN) // When LRU bank needs to be closed ddr_ba_r <= bank_cmp_addr_r[(3*CMP_WIDTH)+CMP_BANK_RANGE_END: (3*CMP_WIDTH)+CMP_BANK_RANGE_START]; else begin // Either precharge due to refresh or bank hit case if (TWO_T_TIME_EN) ddr_ba_r <= af_addr_r3[BANK_RANGE_END:BANK_RANGE_START]; else ddr_ba_r <= af_addr_r2[BANK_RANGE_END:BANK_RANGE_START]; end end // chip enable generation logic generate // if only one chip select, always assert it after reset if (CS_BITS == 0) begin: gen_ddr_cs_0 always @(posedge clk) if (rst_r1) ddr_cs_n_r[0] <= 1'b1; else ddr_cs_n_r[0] <= 1'b0; // otherwise if we have multiple chip selects end else begin: gen_ddr_cs_1 always @(posedge clk) if (rst_r1) ddr_cs_n_r <= {CS_NUM{1'b1}}; else if (state_r == CTRL_AUTO_REFRESH) begin // if auto-refreshing, only auto-refresh one CS at any time (avoid // beating on the ground plane by refreshing all CS's at same time) ddr_cs_n_r <= {CS_NUM{1'b1}}; ddr_cs_n_r[auto_cnt_r] <= 1'b0; end else if ((state_r == CTRL_PRECHARGE) && bank_conflict_r && MULTI_BANK_EN) begin // precharging the LRU bank ddr_cs_n_r <= {CS_NUM{1'b1}}; ddr_cs_n_r[bank_cmp_addr_r[(3*CMP_WIDTH)+CMP_CS_RANGE_END: (3*CMP_WIDTH)+CMP_CS_RANGE_START]] <= 1'b0; end else begin // otherwise, check the upper address bits to see which CS to assert ddr_cs_n_r <= {CS_NUM{1'b1}}; ddr_cs_n_r <= af_addr_r2[CS_RANGE_END:CS_RANGE_START]; end end endgenerate // registring the two_t timing enable signal. // This signal will be asserted (low) when the // chip select has to be asserted. always @(posedge clk)begin if(&two_t_enable_r) two_t_enable_r1 <= {CS_NUM{1'b1}}; else two_t_enable_r1 <= {CS_NUM{1'b0}}; end assign ctrl_addr = ddr_addr_r; assign ctrl_ba = ddr_ba_r; assign ctrl_ras_n = ddr_ras_n_r; assign ctrl_cas_n = ddr_cas_n_r; assign ctrl_we_n = ddr_we_n_r; assign ctrl_cs_n = (TWO_T_TIME_EN) ? (ddr_cs_n_r | two_t_enable_r1) : ddr_cs_n_r;endmodule
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -