blob: f6eadc1c4b004c75d6f0cb68be1bf7f390faabd7 [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
// 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>
//
/*********************************************************************
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: WISHBONE to SDRAM Controller Bus Transalator
1. This module translate the WISHBONE protocol to custom sdram controller i/f
2. Also Handle the clock domain change from Application layer to Sdram layer
To Do:
nothing
Author(s): Dinesh Annayya, dinesha@opencores.org
Version : 0.0 - Initial Release
0.1 - 2nd Feb 2012
Async Fifo towards the application layer is selected
with Registered Full Generation
0.2 - 2nd Feb 2012
Pending Read generation bug fix done to handle backto back write
followed by read request
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
*******************************************************************/
module wb2sdrc (
// WB bus
wb_rst_n ,
wb_clk_i ,
wb_stb_i ,
wb_ack_o ,
wb_addr_i ,
wb_we_i ,
wb_dat_i ,
wb_sel_i ,
wb_dat_o ,
wb_cyc_i ,
//SDRAM Controller Hand-Shake Signal
sdram_clk ,
sdram_resetn ,
sdr_req ,
sdr_req_addr ,
sdr_req_len ,
sdr_req_wr_n ,
sdr_req_ack ,
sdr_busy_n ,
sdr_wr_en_n ,
sdr_wr_next ,
sdr_rd_valid ,
sdr_last_rd ,
sdr_wr_data ,
sdr_rd_data
);
parameter dw = 32; // data width
parameter tw = 8; // tag id width
parameter bl = 9; // burst_lenght_width
parameter APP_AW = 26; // Application Address Width
//--------------------------------------
// Wish Bone Interface
// -------------------------------------
input wb_rst_n ;
input wb_clk_i ;
input wb_stb_i ;
output wb_ack_o ;
input [APP_AW-1:0] wb_addr_i ;
input wb_we_i ; // 1 - Write , 0 - Read
input [dw-1:0] wb_dat_i ;
input [dw/8-1:0] wb_sel_i ; // Byte enable
output [dw-1:0] wb_dat_o ;
input wb_cyc_i ;
/***************************************************
The Cycle Type Idenfier [CTI_IO()] Address Tag provides
additional information about the current cycle.
The MASTER sends this information to the SLAVE. The SLAVE can use this
information to prepare the response for the next cycle.
Table 4-2 Cycle Type Identifiers
CTI_O(2:0) Description
‘000’ Classic cycle.
‘001’ Constant address burst cycle
‘010’ Incrementing burst cycle
‘011’ Reserved
‘100’ Reserved
‘101 Reserved
‘110’ Reserved
‘111’ End-of-Burst
****************************************************/
//--------------------------------------------
// SDRAM controller Interface
//--------------------------------------------
input sdram_clk ; // sdram clock
input sdram_resetn ; // sdram reset
output sdr_req ; // SDRAM request
output [APP_AW-1:0] sdr_req_addr ; // SDRAM Request Address
output [bl-1:0] sdr_req_len ;
output sdr_req_wr_n ; // 0 - Write, 1 -> Read
input sdr_req_ack ; // SDRAM request Accepted
input sdr_busy_n ; // 0 -> sdr busy
output [dw/8-1:0] sdr_wr_en_n ; // Active low sdr byte-wise write data valid
input sdr_wr_next ; // Ready to accept the next write
input sdr_rd_valid ; // sdr read valid
input sdr_last_rd ; // Indicate last Read of Burst Transfer
output [dw-1:0] sdr_wr_data ; // sdr write data
input [dw-1:0] sdr_rd_data ; // sdr read data
//----------------------------------------------------
// Wire Decleration
// ---------------------------------------------------
wire cmdfifo_full ;
wire cmdfifo_empty ;
wire wrdatafifo_full ;
wire wrdatafifo_empty ;
wire tagfifo_full ;
wire tagfifo_empty ;
wire rddatafifo_empty ;
wire rddatafifo_full ;
reg pending_read ;
//-----------------------------------------------------------------------------
// Ack Generaltion Logic
// If Write Request - Acknowledge if the command and write FIFO are not full
// If Read Request - Generate the Acknowledgment once read fifo has data
// available
//-----------------------------------------------------------------------------
assign wb_ack_o = (wb_stb_i && wb_cyc_i && wb_we_i) ? // Write Phase
((!cmdfifo_full) && (!wrdatafifo_full)) :
(wb_stb_i && wb_cyc_i && !wb_we_i) ? // Read Phase
!rddatafifo_empty : 1'b0;
//---------------------------------------------------------------------------
// Command FIFO Write Generation
// If Write Request - Generate write, when Write fifo and command fifo is
// not full
// If Read Request - Generate write, when command fifo not full and there
// is no pending read request.
//---------------------------------------------------------------------------
wire cmdfifo_wr = (wb_stb_i && wb_cyc_i && wb_we_i && (!cmdfifo_full) ) ? wb_ack_o :
(wb_stb_i && wb_cyc_i && !wb_we_i && (!cmdfifo_full)) ? !pending_read: 1'b0 ;
//---------------------------------------------------------------------------
// command fifo read generation
// Command FIFo read will be generated, whenever SDRAM Controller
// Acknowldge the Request
//----------------------------------------------------------------------------
wire cmdfifo_rd = sdr_req_ack;
//---------------------------------------------------------------------------
// Application layer request is generated towards the controller, whenever
// Command FIFO is not full
// --------------------------------------------------------------------------
assign sdr_req = !cmdfifo_empty;
//----------------------------------------------------------------------------
// Since Burst length is not known at the start of the Burst, It's assumed as
// Single Cycle Burst. We need to improvise this ...
// --------------------------------------------------------------------------
wire [bl-1:0] burst_length = 1; // 0 Mean 1 Transfer
//-----------------------------------------------------------------------------
// In Wish Bone Spec, For Read Request has to be acked along with data.
// We need to identify the pending read request.
// Once we accept the read request, we should not accept one more read
// request, untill we have transmitted the read data.
// Pending Read will
// set - with Read Request
// reset - with Read Request + Ack
// ----------------------------------------------------------------------------
always @(negedge wb_rst_n or posedge wb_clk_i) begin
if(!wb_rst_n) begin
pending_read <= 1'b0;
end else begin
//pending_read <= wb_stb_i & wb_cyc_i & !wb_we_i & !wb_ack_o;
pending_read <= (cmdfifo_wr && !wb_we_i) ? 1'b1:
(wb_stb_i & wb_cyc_i & !wb_we_i & wb_ack_o) ? 1'b0: pending_read;
end
end
//---------------------------------------------------------------------
// Async Command FIFO. This block handle the clock domain change from
// Application layer to SDRAM Controller
// ------------------------------------------------------------------
// Address + Burst Length + W/R Request
async_fifo #(.W(APP_AW+bl+1),.DP(4),.WR_FAST(1'b0), .RD_FAST(1'b0)) u_cmdfifo (
// Write Path Sys CLock Domain
.wr_clk (wb_clk_i ),
.wr_reset_n (wb_rst_n ),
.wr_en (cmdfifo_wr ),
.wr_data ({burst_length,
!wb_we_i,
wb_addr_i} ),
.afull ( ),
.full (cmdfifo_full ),
// Read Path, SDRAM clock domain
.rd_clk (sdram_clk ),
.rd_reset_n (sdram_resetn ),
.aempty ( ),
.empty (cmdfifo_empty ),
.rd_en (cmdfifo_rd ),
.rd_data ({sdr_req_len,
sdr_req_wr_n,
sdr_req_addr} )
);
// synopsys translate_off
always @(posedge wb_clk_i) begin
if (cmdfifo_full == 1'b1 && cmdfifo_wr == 1'b1) begin
$display("ERROR:%m COMMAND FIFO WRITE OVERFLOW");
end
end
// synopsys translate_on
// synopsys translate_off
always @(posedge sdram_clk) begin
if (cmdfifo_empty == 1'b1 && cmdfifo_rd == 1'b1) begin
$display("ERROR:%m COMMAND FIFO READ OVERFLOW");
end
end
// synopsys translate_on
//---------------------------------------------------------------------
// Write Data FIFO Write Generation, when ever Acked + Write Request
// Note: Ack signal generation already taking account of FIFO full condition
// ---------------------------------------------------------------------
wire wrdatafifo_wr = wb_ack_o & wb_we_i ;
//------------------------------------------------------------------------
// Write Data FIFO Read Generation, When ever Next Write request generated
// from SDRAM Controller
// ------------------------------------------------------------------------
wire wrdatafifo_rd = sdr_wr_next;
//------------------------------------------------------------------------
// Async Write Data FIFO
// This block handle the clock domain change over + Write Data + Byte mask
// From Application layer to SDRAM controller layer
//------------------------------------------------------------------------
// Write DATA + Data Mask FIFO
async_fifo #(.W(dw+(dw/8)), .DP(8), .WR_FAST(1'b0), .RD_FAST(1'b1)) u_wrdatafifo (
// Write Path , System clock domain
.wr_clk (wb_clk_i ),
.wr_reset_n (wb_rst_n ),
.wr_en (wrdatafifo_wr ),
.wr_data ({~wb_sel_i,
wb_dat_i} ),
.afull ( ),
.full (wrdatafifo_full ),
// Read Path , SDRAM clock domain
.rd_clk (sdram_clk ),
.rd_reset_n (sdram_resetn ),
.aempty ( ),
.empty (wrdatafifo_empty ),
.rd_en (wrdatafifo_rd ),
.rd_data ({sdr_wr_en_n,
sdr_wr_data} )
);
// synopsys translate_off
always @(posedge wb_clk_i) begin
if (wrdatafifo_full == 1'b1 && wrdatafifo_wr == 1'b1) begin
$display("ERROR:%m WRITE DATA FIFO WRITE OVERFLOW");
end
end
always @(posedge sdram_clk) begin
if (wrdatafifo_empty == 1'b1 && wrdatafifo_rd == 1'b1) begin
$display("ERROR:%m WRITE DATA FIFO READ OVERFLOW");
end
end
// synopsys translate_on
// -------------------------------------------------------------------
// READ DATA FIFO
// ------------------------------------------------------------------
wire rd_eop; // last read indication
// Read FIFO write generation, when ever SDRAM controller issues the read
// valid signal
wire rddatafifo_wr = sdr_rd_valid;
// Read FIFO read generation, when ever ack is generated along with read
// request.
// Note: Ack generation is already accounted the write FIFO Not Empty
// condition
wire rddatafifo_rd = wb_ack_o & !wb_we_i;
//-------------------------------------------------------------------------
// Async Read FIFO
// This block handles the clock domain change over + Read data from SDRAM
// controller to Application layer.
// Note:
// 1. READ DATA FIFO depth is kept small, assuming that Sys-CLock > SDRAM Clock
// READ DATA + EOP
// 2. EOP indicate, last transfer of Burst Read Access. use-full for future
// Tag handling per burst
//
// ------------------------------------------------------------------------
async_fifo #(.W(dw+1), .DP(4), .WR_FAST(1'b0), .RD_FAST(1'b1) ) u_rddatafifo (
// Write Path , SDRAM clock domain
.wr_clk (sdram_clk ),
.wr_reset_n (sdram_resetn ),
.wr_en (rddatafifo_wr ),
.wr_data ({sdr_last_rd,
sdr_rd_data} ),
.afull ( ),
.full (rddatafifo_full ),
// Read Path , SYS clock domain
.rd_clk (wb_clk_i ),
.rd_reset_n (wb_rst_n ),
.empty (rddatafifo_empty ),
.aempty ( ),
.rd_en (rddatafifo_rd ),
.rd_data ({rd_eop,
wb_dat_o} )
);
// synopsys translate_off
always @(posedge sdram_clk) begin
if (rddatafifo_full == 1'b1 && rddatafifo_wr == 1'b1) begin
$display("ERROR:%m READ DATA FIFO WRITE OVERFLOW");
end
end
always @(posedge wb_clk_i) begin
if (rddatafifo_empty == 1'b1 && rddatafifo_rd == 1'b1) begin
$display("ERROR:%m READ DATA FIFO READ OVERFLOW");
end
end
// synopsys translate_on
endmodule