| ////////////////////////////////////////////////////////////////////////////// |
| // SPDX-FileCopyrightText: 2021 , Dinesh Annayya |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // SPDX-License-Identifier: Apache-2.0 |
| // SPDX-FileContributor: Created by Dinesh Annayya <dinesha@opencores.org> |
| // |
| /********************************************************************* |
| |
| SDRAM Controller Request Generation |
| |
| This file is part of the sdram controller project |
| https://github.com/dineshannayya/yifive_r0.git |
| http://www.opencores.org/cores/yifive/ |
| http://www.opencores.org/cores/sdr_ctrl/ |
| |
| Description: SDRAM Controller Reguest Generation |
| |
| Address Generation Based on cfg_colbits |
| cfg_colbits= 2'b00 |
| Address[7:0] - Column Address |
| Address[9:8] - Bank Address |
| Address[22:10] - Row Address |
| cfg_colbits= 2'b01 |
| Address[8:0] - Column Address |
| Address[10:9] - Bank Address |
| Address[23:11] - Row Address |
| cfg_colbits= 2'b10 |
| Address[9:0] - Column Address |
| Address[11:10] - Bank Address |
| Address[24:12] - Row Address |
| cfg_colbits= 2'b11 |
| Address[10:0] - Column Address |
| Address[12:11] - Bank Address |
| Address[25:13] - Row Address |
| |
| The SDRAMs are operated in 4 beat burst mode. |
| |
| If Wrap = 0; |
| If the current burst cross the page boundary, then this block split the request |
| into two coressponding change in address and request length |
| |
| if the current burst cross the page boundar. |
| This module takes requests from the memory controller, |
| chops them to page boundaries if wrap=0, |
| and passes the request to bank_ctl |
| |
| Note: With Wrap = 0, each request from Application layer will be splited into two request, |
| if the current burst cross the page boundary. |
| |
| To Do: |
| nothing |
| |
| Author(s): |
| - Dinesh Annayya, dinesha@opencores.org |
| Version : 0.0 - 8th Jan 2012 |
| 0.1 - 5th Feb 2012, column/row/bank address are register to improve the timing issue in FPGA synthesis |
| 0.2 - 19th Aug 2021, Address Mapping fix |
| |
| |
| |
| Copyright (C) 2000 Authors and OPENCORES.ORG |
| |
| 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 source file is free software; you can redistribute it |
| and/or modify it under the terms of the GNU Lesser General |
| Public License as published by the Free Software Foundation; |
| either version 2.1 of the License, or (at your option) any |
| later version. |
| |
| This source 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 Lesser General Public License for more |
| details. |
| |
| You should have received a copy of the GNU Lesser General |
| Public License along with this source; if not, download it |
| from http://www.opencores.org/lgpl.shtml |
| |
| *******************************************************************/ |
| |
| `include "sdrc_define.v" |
| |
| module sdrc_req_gen (clk, |
| reset_n, |
| cfg_colbits, |
| sdr_width, |
| |
| /* Request from app */ |
| req, // Transfer Request |
| req_id, // ID for this transfer |
| req_addr, // SDRAM Address |
| req_len, // Burst Length (in 32 bit words) |
| req_wrap, // Wrap mode request (xfr_len = 4) |
| req_wr_n, // 0 => Write request, 1 => read req |
| req_ack, // Request has been accepted |
| |
| /* Req to xfr_ctl */ |
| r2x_idle, |
| |
| /* Req to bank_ctl */ |
| r2b_req, // request |
| r2b_req_id, // ID |
| r2b_start, // First chunk of burst |
| r2b_last, // Last chunk of burst |
| r2b_wrap, // Wrap Mode |
| r2b_ba, // bank address |
| r2b_raddr, // row address |
| r2b_caddr, // col address |
| r2b_len, // length |
| r2b_write, // write request |
| b2r_ack, |
| b2r_arb_ok |
| ); |
| |
| parameter APP_AW = 26; // Application Address Width |
| parameter APP_DW = 32; // Application Data Width |
| parameter APP_BW = 4; // Application Byte Width |
| parameter APP_RW = 9; // Application Request Width |
| |
| parameter SDR_DW = 16; // SDR Data Width |
| parameter SDR_BW = 2; // SDR Byte Width |
| |
| |
| input clk ; |
| input reset_n ; |
| input [1:0] cfg_colbits ; // 2'b00 - 8 Bit column address, 2'b01 - 9 Bit, 10 - 10 bit, 11 - 11Bits |
| |
| /* Request from app */ |
| input req ; // Request |
| input [`SDR_REQ_ID_W-1:0] req_id ; // Request ID |
| input [APP_AW-1:0] req_addr ; // Request Address |
| input [APP_RW-1:0] req_len ; // Request length |
| input req_wr_n ; // 0 -Write, 1 - Read |
| input req_wrap ; // 1 - Wrap the Address on page boundary |
| output req_ack ; // Request Ack |
| |
| /* Req to bank_ctl */ |
| output r2x_idle ; |
| output r2b_req ; // Request |
| output r2b_start ; // First Junk of the Burst Access |
| output r2b_last ; // Last Junk of the Burst Access |
| output r2b_write ; // 1 - Write, 0 - Read |
| output r2b_wrap ; // 1 - Wrap the Address at the page boundary. |
| output [`SDR_REQ_ID_W-1:0] r2b_req_id; |
| output [1:0] r2b_ba ; // Bank Address |
| output [12:0] r2b_raddr ; // Row Address |
| output [12:0] r2b_caddr ; // Column Address |
| output [`REQ_BW-1:0] r2b_len ; // Burst Length |
| input b2r_ack ; // Request Ack |
| input b2r_arb_ok ; // Bank controller fifo is not full and ready to accept the command |
| // |
| input [1:0] sdr_width; // 2'b00 - 32 Bit, 2'b01 - 16 Bit, 2'b1x - 8Bit |
| |
| |
| /****************************************************************************/ |
| // Internal Nets |
| |
| `define REQ_IDLE 2'b00 |
| `define REQ_ACTIVE 2'b01 |
| `define REQ_PAGE_WRAP 2'b10 |
| |
| reg [1:0] req_st, next_req_st; |
| reg r2x_idle, req_ack, r2b_req, r2b_start, |
| r2b_write, req_idle, req_ld, lcl_wrap; |
| reg [`SDR_REQ_ID_W-1:0] r2b_req_id; |
| reg [`REQ_BW-1:0] lcl_req_len; |
| |
| wire r2b_last, page_ovflw; |
| reg page_ovflw_r; |
| wire [`REQ_BW-1:0] r2b_len, next_req_len; |
| wire [12:0] max_r2b_len; |
| reg [12:0] max_r2b_len_r; |
| |
| reg [1:0] r2b_ba; |
| reg [12:0] r2b_raddr; |
| reg [12:0] r2b_caddr; |
| |
| reg [APP_AW-1:0] curr_sdr_addr ; |
| wire [APP_AW-1:0] next_sdr_addr ; |
| |
| |
| //-------------------------------------------------------------------- |
| // Generate the internal Adress and Burst length Based on sdram width |
| //-------------------------------------------------------------------- |
| reg [APP_AW:0] req_addr_int; |
| reg [APP_RW-1:0] req_len_int; |
| |
| always @(*) begin |
| if(sdr_width == 2'b00) begin // 32 Bit SDR Mode |
| req_addr_int = {1'b0,req_addr}; |
| req_len_int = req_len; |
| end else if(sdr_width == 2'b01) begin // 16 Bit SDR Mode |
| // Changed the address and length to match the 16 bit SDR Mode |
| req_addr_int = {1'b0,req_addr}; |
| req_len_int = {req_len,1'b0}; |
| end else begin // 8 Bit SDR Mode |
| // Changed the address and length to match the 16 bit SDR Mode |
| req_addr_int = {1'b0,req_addr}; |
| req_len_int = {req_len,2'b0}; |
| end |
| end |
| |
| // |
| // Identify the page over flow. |
| // Find the Maximum Burst length allowed from the selected column |
| // address, If the requested burst length is more than the allowed Maximum |
| // burst length, then we need to handle the bank cross over case and we |
| // need to split the reuest. |
| // |
| assign max_r2b_len = (cfg_colbits == 2'b00) ? (12'h100 - {4'b0, req_addr_int[7:0]}) : |
| (cfg_colbits == 2'b01) ? (12'h200 - {3'b0, req_addr_int[8:0]}) : |
| (cfg_colbits == 2'b10) ? (12'h400 - {2'b0, req_addr_int[9:0]}) : (12'h800 - {1'b0, req_addr_int[10:0]}); |
| |
| |
| // If the wrap = 0 and current application burst length is crossing the page boundary, |
| // then request will be split into two with corresponding change in request address and request length. |
| // |
| // If the wrap = 0 and current burst length is not crossing the page boundary, |
| // then request from application layer will be transparently passed on the bank control block. |
| |
| // |
| // if the wrap = 1, then this block will not modify the request address and length. |
| // The wrapping functionality will be handle by the bank control module and |
| // column address will rewind back as follows XX -> FF ? 00 ? 1 |
| // |
| // Note: With Wrap = 0, each request from Application layer will be spilited into two request, |
| // if the current burst cross the page boundary. |
| assign page_ovflw = ({1'b0, req_len_int} > max_r2b_len) ? ~r2b_wrap : 1'b0; |
| |
| assign r2b_len = r2b_start ? ((page_ovflw_r) ? max_r2b_len_r : lcl_req_len) : |
| lcl_req_len; |
| |
| assign next_req_len = lcl_req_len - r2b_len; |
| |
| assign next_sdr_addr = curr_sdr_addr + r2b_len; |
| |
| |
| assign r2b_wrap = lcl_wrap; |
| |
| assign r2b_last = (r2b_start & !page_ovflw_r) | (req_st == `REQ_PAGE_WRAP); |
| // |
| // |
| // |
| always @ (posedge clk) begin |
| |
| page_ovflw_r <= (req_ack) ? page_ovflw: 'h0; |
| |
| max_r2b_len_r <= (req_ack) ? max_r2b_len: 'h0; |
| r2b_start <= (req_ack) ? 1'b1 : |
| (b2r_ack) ? 1'b0 : r2b_start; |
| |
| r2b_write <= (req_ack) ? ~req_wr_n : r2b_write; |
| |
| r2b_req_id <= (req_ack) ? req_id : r2b_req_id; |
| |
| lcl_wrap <= (req_ack) ? req_wrap : lcl_wrap; |
| |
| lcl_req_len <= (req_ack) ? req_len_int : |
| (req_ld) ? next_req_len : lcl_req_len; |
| |
| curr_sdr_addr <= (req_ack) ? req_addr_int : |
| (req_ld) ? next_sdr_addr : curr_sdr_addr; |
| |
| end // always @ (posedge clk) |
| |
| always @ (*) begin |
| r2x_idle = 1'b0; |
| req_idle = 1'b0; |
| req_ack = 1'b0; |
| req_ld = 1'b0; |
| r2b_req = 1'b0; |
| next_req_st = `REQ_IDLE; |
| |
| case (req_st) |
| |
| `REQ_IDLE : begin |
| r2x_idle = ~req; |
| req_idle = 1'b1; |
| req_ack = req & b2r_arb_ok; |
| req_ld = 1'b0; |
| r2b_req = 1'b0; |
| next_req_st = (req & b2r_arb_ok) ? `REQ_ACTIVE : `REQ_IDLE; |
| end // case: `REQ_IDLE |
| |
| `REQ_ACTIVE : begin |
| r2x_idle = 1'b0; |
| req_idle = 1'b0; |
| req_ack = 1'b0; |
| req_ld = b2r_ack; |
| r2b_req = 1'b1; // req_gen to bank_req |
| next_req_st = (b2r_ack ) ? ((page_ovflw_r) ? `REQ_PAGE_WRAP :`REQ_IDLE) : `REQ_ACTIVE; |
| end // case: `REQ_ACTIVE |
| `REQ_PAGE_WRAP : begin |
| r2x_idle = 1'b0; |
| req_idle = 1'b0; |
| req_ack = 1'b0; |
| req_ld = b2r_ack; |
| r2b_req = 1'b1; // req_gen to bank_req |
| next_req_st = (b2r_ack) ? `REQ_IDLE : `REQ_PAGE_WRAP; |
| end // case: `REQ_ACTIVE |
| |
| endcase // case(req_st) |
| |
| end // always @ (req_st or ....) |
| |
| always @ (posedge clk) |
| if (~reset_n) begin |
| req_st <= `REQ_IDLE; |
| end // if (~reset_n) |
| else begin |
| req_st <= next_req_st; |
| end // else: !if(~reset_n) |
| // |
| // addrs bits for the bank, row and column |
| // |
| // Register row/column/bank to improve fpga timing issue |
| wire [APP_AW-1:0] map_address ; |
| |
| assign map_address = (req_ack) ? req_addr_int : |
| (req_ld) ? next_sdr_addr : curr_sdr_addr; |
| |
| always @ (posedge clk) begin |
| // Bank Bits are always - 2 Bits |
| r2b_ba <= (cfg_colbits == 2'b00) ? {map_address[9:8]} : |
| (cfg_colbits == 2'b01) ? {map_address[10:9]} : |
| (cfg_colbits == 2'b10) ? {map_address[11:10]} : map_address[12:11]; |
| |
| /******************** |
| * Colbits Mapping: |
| * 2'b00 - 8 Bit |
| * 2'b01 - 16 Bit |
| * 2'b10 - 10 Bit |
| * 2'b11 - 11 Bits |
| ************************/ |
| r2b_caddr <= (cfg_colbits == 2'b00) ? {5'b0, map_address[7:0]} : |
| (cfg_colbits == 2'b01) ? {4'b0, map_address[8:0]} : |
| (cfg_colbits == 2'b10) ? {3'b0, map_address[9:0]} : {2'b0, map_address[10:0]}; |
| |
| r2b_raddr <= (cfg_colbits == 2'b00) ? map_address[22:10] : |
| (cfg_colbits == 2'b01) ? map_address[23:11] : |
| (cfg_colbits == 2'b10) ? map_address[24:12] : map_address[25:13]; |
| end |
| |
| endmodule // sdr_req_gen |