blob: 76b9981fc8af77b5bec66872175f735a78993134 [file] [log] [blame]
//////////////////////////////////////////////////////////////////////
//// ////
//// yifive common library Module ////
//// ////
//// This file is part of the yifive cores project ////
//// http://www.opencores.org/cores/yifive/ ////
//// ////
//// Description ////
//// This module does the Wishone crossbar network ////
//// ////
//// To Do: ////
//// nothing ////
//// ////
//// Author(s): ////
//// - Dinesh Annayya, dinesha@opencores.org ////
//// ////
//////////////////////////////////////////////////////////////////////
//// Revision : ////
//// v0: Nov 26, 2016, Dinesh A ////
//// This files copied from my open core ////
//// turbo8051 project ////
//////////////////////////////////////////////////////////////////////
//// ////
//// 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 ////
//// ////
//////////////////////////////////////////////////////////////////////
/**********************************************
Wish-bone cross bar M-Master By S-Slave
**********************************************/
module wb_crossbar (
rst_n ,
clk ,
// Master Interface Signal
wbd_taddr_master ,
wbd_din_master ,
wbd_dout_master ,
wbd_adr_master ,
wbd_be_master ,
wbd_we_master ,
wbd_ack_master ,
wbd_stb_master ,
wbd_cyc_master ,
wbd_err_master ,
wbd_rty_master ,
// Slave Interface Signal
wbd_din_slave ,
wbd_dout_slave ,
wbd_adr_slave ,
wbd_be_slave ,
wbd_we_slave ,
wbd_ack_slave ,
wbd_stb_slave ,
wbd_cyc_slave ,
wbd_err_slave ,
wbd_rty_slave
);
parameter WB_SLAVE = 4 ;
parameter WB_MASTER = 4 ;
parameter D_WD = 16; // Data Width
parameter BE_WD = 2; // Byte Enable
parameter ADR_WD = 28; // Address Width
parameter TAR_WD = 4; // Target Width
input clk; // CLK_I The clock input [CLK_I] coordinates all activities
// for the internal logic within the WISHBONE interconnect.
// All WISHBONE output signals are registered at the
// rising edge of [CLK_I].
// All WISHBONE input signals must be stable before the
// rising edge of [CLK_I].
input rst_n; // RST_I The reset input [RST_I] forces the WISHBONE interface
// to restart. Furthermore, all internal self-starting state
// machines will be forced into an initial state.
input [(WB_MASTER *TAR_WD)-1:0] wbd_taddr_master; // target address from master
input [WB_MASTER-1:0] wbd_stb_master;
// STB_O The strobe output [STB_O] indicates a valid data
// transfer cycle. It is used to qualify various other signals
// on the interface such as [SEL_O(7..0)]. The SLAVE must
// assert either the [ACK_I], [ERR_I] or [RTY_I] signals in
// response to every assertion of the [STB_O] signal.
output [WB_SLAVE-1:0] wbd_stb_slave;
// STB_O The strobe output [STB_O] indicates a valid data
// transfer cycle. It is used to qualify various other signals
// on the interface such as [SEL_O(7..0)]. The SLAVE must
// assert either the [ACK_I], [ERR_I] or [RTY_I] signals in
// response to every assertion of the [STB_O] signal.
input [WB_MASTER-1:0] wbd_we_master;
// WE_O The write enable output [WE_O] indicates whether the
// current local bus cycle is a READ or WRITE cycle. The
// signal is negated during READ cycles, and is asserted
// during WRITE cycles.
output [WB_SLAVE-1:0] wbd_we_slave;
// WE_O The write enable output [WE_O] indicates whether the
// current local bus cycle is a READ or WRITE cycle. The
// signal is negated during READ cycles, and is asserted
// during WRITE cycles.
output [WB_MASTER-1:0] wbd_ack_master;
// The acknowledge input [ACK_I], when asserted,
// indicates the termination of a normal bus cycle.
// Also see the [ERR_I] and [RTY_I] signal descriptions.
input [WB_SLAVE-1:0] wbd_ack_slave;
// The acknowledge input [ACK_I], when asserted,
// indicates the termination of a normal bus cycle.
// Also see the [ERR_I] and [RTY_I] signal descriptions.
input [(WB_MASTER *ADR_WD)-1:0] wbd_adr_master;
// The address output array [ADR_O(63..0)] is used
// to pass a binary address, with the most significant
// address bit at the higher numbered end of the signal array.
// The lower array boundary is specific to the data port size.
// The higher array boundary is core-specific.
// In some cases (such as FIFO interfaces)
// the array may not be present on the interface.
output [(WB_SLAVE *ADR_WD)-1:0] wbd_adr_slave;
// The address output array [ADR_O(63..0)] is used
// to pass a binary address, with the most significant
// address bit at the higher numbered end of the signal array.
// The lower array boundary is specific to the data port size.
// The higher array boundary is core-specific.
// In some cases (such as FIFO interfaces)
// the array may not be present on the interface.
input [(WB_MASTER * BE_WD)-1:0] wbd_be_master; // Byte Enable
// SEL_O(7..0) The select output array [SEL_O(7..0)] indicates
// where valid data is expected on the [DAT_I(63..0)] signal
// array during READ cycles, and where it is placed on the
// [DAT_O(63..0)] signal array during WRITE cycles.
// Also see the [DAT_I(63..0)], [DAT_O(63..0)] and [STB_O]
// signal descriptions.
output [(WB_SLAVE * BE_WD)-1:0] wbd_be_slave; // Byte Enable
// SEL_O(7..0) The select output array [SEL_O(7..0)] indicates
// where valid data is expected on the [DAT_I(63..0)] signal
// array during READ cycles, and where it is placed on the
// [DAT_O(63..0)] signal array during WRITE cycles.
// Also see the [DAT_I(63..0)], [DAT_O(63..0)] and [STB_O]
// signal descriptions.
input [WB_MASTER -1:0] wbd_cyc_master;
// CYC_O The cycle output [CYC_O], when asserted,
// indicates that a valid bus cycle is in progress.
// The signal is asserted for the duration of all bus cycles.
// For example, during a BLOCK transfer cycle there can be
// multiple data transfers. The [CYC_O] signal is asserted
// during the first data transfer, and remains asserted
// until the last data transfer. The [CYC_O] signal is useful
// for interfaces with multi-port interfaces
// (such as dual port memories). In these cases,
// the [CYC_O] signal requests use of a common bus from an
// arbiter. Once the arbiter grants the bus to the MASTER,
// it is held until [CYC_O] is negated.
output [WB_SLAVE -1:0] wbd_cyc_slave;
// CYC_O The cycle output [CYC_O], when asserted,
// indicates that a valid bus cycle is in progress.
// The signal is asserted for the duration of all bus cycles.
// For example, during a BLOCK transfer cycle there can be
// multiple data transfers. The [CYC_O] signal is asserted
// during the first data transfer, and remains asserted
// until the last data transfer. The [CYC_O] signal is useful
// for interfaces with multi-port interfaces
// (such as dual port memories). In these cases,
// the [CYC_O] signal requests use of a common bus from an
// arbiter. Once the arbiter grants the bus to the MASTER,
// it is held until [CYC_O] is negated.
input [(WB_MASTER * D_WD)-1:0] wbd_din_master;
// DAT_I(63..0) The data input array [DAT_I(63..0)] is
// used to pass binary data. The array boundaries are
// determined by the port size. Also see the [DAT_O(63..0)]
// and [SEL_O(7..0)] signal descriptions.
output [(WB_SLAVE * D_WD)-1:0] wbd_din_slave;
// DAT_I(63..0) The data input array [DAT_I(63..0)] is
// used to pass binary data. The array boundaries are
// determined by the port size. Also see the [DAT_O(63..0)]
// and [SEL_O(7..0)] signal descriptions.
output [(WB_MASTER * D_WD)-1:0] wbd_dout_master;
// DAT_O(63..0) The data output array [DAT_O(63..0)] is
// used to pass binary data. The array boundaries are
// determined by the port size. Also see the [DAT_I(63..0)]
// and [SEL_O(7..0)] signal descriptions.
input [(WB_SLAVE * D_WD)-1:0] wbd_dout_slave;
// DAT_O(63..0) The data output array [DAT_O(63..0)] is
// used to pass binary data. The array boundaries are
// determined by the port size. Also see the [DAT_I(63..0)]
// and [SEL_O(7..0)] signal descriptions.
output [WB_MASTER -1:0] wbd_err_master;
// ERR_I The error input [ERR_I] indicates an abnormal
// cycle termination. The source of the error, and the
// response generated by the MASTER is defined by the IP core
// supplier in the WISHBONE DATASHEET. Also see the [ACK_I]
// and [RTY_I] signal descriptions.
input [WB_SLAVE -1:0] wbd_err_slave;
// ERR_I The error input [ERR_I] indicates an abnormal
// cycle termination. The source of the error, and the
// response generated by the MASTER is defined by the IP core
// supplier in the WISHBONE DATASHEET. Also see the [ACK_I]
// and [RTY_I] signal descriptions.
output [WB_MASTER -1:0] wbd_rty_master;
// RTY_I The retry input [RTY_I] indicates that the indicates
// that the interface is not ready to accept or send data, and
// that the cycle should be retried. When and how the cycle is
// retried is defined by the IP core supplier in the WISHBONE
// DATASHEET. Also see the [ERR_I] and [RTY_I] signal
// descriptions.
input [WB_SLAVE -1:0] wbd_rty_slave;
// RTY_I The retry input [RTY_I] indicates that the indicates
// that the interface is not ready to accept or send data, and
// that the cycle should be retried. When and how the cycle is
// retried is defined by the IP core supplier in the WISHBONE
// DATASHEET. Also see the [ERR_I] and [RTY_I] signal
// descriptions.
reg [WB_MASTER-1:0] wbd_ack_master;
reg [WB_MASTER-1:0] wbd_err_master;
reg [WB_MASTER-1:0] wbd_rty_master;
reg [WB_MASTER-1:0] master_busy; // master busy flag
reg [WB_SLAVE-1:0] slave_busy; // slave busy flag
reg [TAR_WD -1:0] master_mx_id[WB_MASTER-1:0];
reg [TAR_WD -1:0] slave_mx_id [WB_SLAVE-1:0];
wire [TAR_WD-1:0] wbd_taddr_master_t[WB_MASTER-1:0]; // target address from master
wire [D_WD-1:0] wbd_din_master_t[WB_MASTER-1:0]; // target address from master
reg [D_WD-1:0] wbd_dout_master_t[WB_MASTER-1:0]; // target address from master
wire [ADR_WD-1:0] wbd_adr_master_t[WB_MASTER-1:0]; // target address from master
wire [BE_WD-1:0] wbd_be_master_t[WB_MASTER-1:0]; // target address from master
reg [WB_SLAVE-1:0] wbd_stb_slave;
reg [WB_SLAVE-1:0] wbd_we_slave;
reg [WB_SLAVE-1:0] wbd_cyc_slave;
wire [D_WD-1:0] wbd_dout_slave_t[WB_SLAVE-1:0]; // target data towards master
reg [D_WD-1:0] wbd_din_slave_t[WB_SLAVE-1:0]; // target address from master
reg [ADR_WD-1:0] wbd_adr_slave_t[WB_SLAVE-1:0]; // target address from master
reg [BE_WD-1:0] wbd_be_slave_t[WB_SLAVE-1:0]; // target address from master
integer i,k,l,n;
/**********************************************************
Re-Arraging the array in seperate two dimensional information
***********************************************************/
genvar j,m;
generate
// Connect the Master Mux
for(j=0; j < WB_MASTER ; j = j + 1) begin : master_expand
assign wbd_taddr_master_t[j] = wbd_taddr_master[((j+1)*TAR_WD)-1:j * TAR_WD];
assign wbd_din_master_t[j] = wbd_din_master[((j+1)*D_WD)-1:j * D_WD];
assign wbd_adr_master_t[j] = wbd_adr_master[((j+1)*ADR_WD)-1:j * ADR_WD];
assign wbd_be_master_t[j] = wbd_be_master[((j+1)*BE_WD)-1:j * BE_WD];
assign wbd_dout_master[((j+1)*D_WD)-1:j * D_WD] = wbd_dout_master_t[j];
end
// Connect the Slave Mux
for(m=0; m < WB_SLAVE ; m = m + 1) begin : slave_expand
assign wbd_din_slave[((m+1)*D_WD)-1:m * D_WD] = wbd_din_slave_t[m];
assign wbd_adr_slave[((m+1)*ADR_WD)-1:m * ADR_WD] = wbd_adr_slave_t[m];
assign wbd_be_slave[((m+1)*BE_WD)-1:m * BE_WD] = wbd_be_slave_t[m];
assign wbd_dout_slave_t[m] = wbd_dout_slave[((m+1)*D_WD)-1:m * D_WD];
end
endgenerate
always @* begin
for(k = 0; k < WB_MASTER; k = k + 1) begin
if(master_busy[k] == 1) begin
wbd_dout_master_t[k] = wbd_dout_slave_t[master_mx_id[k]];
wbd_ack_master[k] = wbd_ack_slave[master_mx_id[k]];
wbd_err_master[k] = wbd_err_slave[master_mx_id[k]];
wbd_rty_master[k] = wbd_rty_slave[master_mx_id[k]];
end else begin
wbd_dout_master_t[k] = 0;
wbd_ack_master[k] = 0;
wbd_err_master[k] = 0;
wbd_rty_master[k] = 0;
end
end
for(l = 0; l < WB_SLAVE; l = l + 1) begin
if(slave_busy[l] == 1) begin
wbd_din_slave_t[l] = wbd_din_master_t[slave_mx_id[l]];
wbd_adr_slave_t[l] = wbd_adr_master_t[slave_mx_id[l]];
wbd_be_slave_t[l] = wbd_be_master_t[slave_mx_id[l]];
wbd_stb_slave[l] = wbd_stb_master[slave_mx_id[l]];
wbd_we_slave[l] = wbd_we_master[slave_mx_id[l]];
wbd_cyc_slave[l] = wbd_cyc_master[slave_mx_id[l]];
end else begin
wbd_din_slave_t[l] = 0;
wbd_adr_slave_t[l] = 0;
wbd_be_slave_t[l] = 0;
wbd_stb_slave[l] = 0;
wbd_we_slave[l] = 0;
wbd_cyc_slave[l] = 0;
end
end
end
/*******************************************************
Parsing through the master and deciding on mux connectio
Step-1: analysis the master from 0 to total master
Step-2: If the previously master is not busy,
Then check for any new request from the master and
check corresponding slave is free or not. If there is
master request and requesting slave is free.
Then set the master max id to slave id &
requesting slave to master number & set the master
and slave busy flag
Step-3: If the previous state of master is busy and bus-cycle
is de-asserted, then reset the master and corresponding
slave busy flag
*********************************************************/
always @(negedge rst_n or posedge clk) begin
if(rst_n == 0) begin
master_busy <= 0;
slave_busy <= 0;
end else begin
for(i = 0; i < WB_MASTER; i = i + 1) begin
if(master_busy[i] == 0) begin
if(wbd_stb_master[i] & slave_busy[wbd_taddr_master_t[i]] == 0) begin
$display("Locking Master Id: %d for tar_master: %d, Total Master: %x ", i, wbd_taddr_master_t[i], wbd_taddr_master);
slave_busy[wbd_taddr_master_t[i]] = 1;
master_busy[i] = 1;
end
end else if(wbd_cyc_master[i] == 0) begin
master_busy[i] <= 0;
slave_busy[wbd_taddr_master_t[i]] <= 0;
end
end
end
end
// Seperated non resetable two dimensional reg
always @(posedge clk) begin
for(n = 0; n < WB_MASTER; n = n + 1) begin
if(master_busy[n] == 0) begin
if(wbd_stb_master[n] & slave_busy[wbd_taddr_master_t[n]] == 0) begin
master_mx_id[n] <= wbd_taddr_master_t[n];
slave_mx_id [wbd_taddr_master_t[n]] <= n;
// synopsys translate_off
$display("%m:%t: Locking Master : %d with Slave : %d",$time,i,wbd_taddr_master_t[n]);
// synopsys translate_on
end
end else if(wbd_cyc_master[n] == 0) begin
if(master_busy[n] == 1) begin
// synopsys translate_off
$display("%m:%t: Releasing Master : %d with Slave : %d",$time,i,wbd_taddr_master_t[n]);
// synopsys translate_on
end
end
end
end
endmodule