blob: 857ec2e3a35ff50009296b1e8e262a2575ac48b9 [file] [log] [blame]
/* wb_mux. Part of wb_intercon
*
* ISC License
*
* Copyright (C) 2013-2019 Olof Kindgren <olof.kindgren@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
Wishbone multiplexer, burst-compatible
Simple mux with an arbitrary number of slaves.
The parameters MATCH_ADDR and MATCH_MASK are flattened arrays
aw*NUM_SLAVES sized arrays that are used to calculate the
active slave. slave i is selected when
(wb_adr_i & MATCH_MASK[(i+1)*aw-1:i*aw] is equal to
MATCH_ADDR[(i+1)*aw-1:i*aw]
If several regions are overlapping, the slave with the lowest
index is selected. This can be used to have fallback
functionality in the last slave, in case no other slave was
selected.
If no match is found, the wishbone transaction will stall and
an external watchdog is required to abort the transaction
Todo:
Registered master/slave connections
Rewrite with System Verilog 2D arrays when tools support them
*/
module wb_mux
#(parameter dw = 32, // Data width
parameter aw = 32, // Address width
parameter num_slaves = 2, // Number of slaves
parameter [num_slaves*aw-1:0] MATCH_ADDR = 0,
parameter [num_slaves*aw-1:0] MATCH_MASK = 0)
(
`ifdef USE_POWER_PINS
inout vccd1, // User area 1 1.8V supply
inout vssd1, // User area 1 digital ground
`endif
input wb_clk_i,
input wb_rst_i,
// Master Interface
input [aw-1:0] wbm_adr_i,
input [dw-1:0] wbm_dat_i,
input [3:0] wbm_sel_i,
input wbm_we_i,
input wbm_cyc_i,
input wbm_stb_i,
input [2:0] wbm_cti_i,
input [1:0] wbm_bte_i,
output [dw-1:0] wbm_dat_o,
output wbm_ack_o,
output wbm_err_o,
output wbm_rty_o,
// Wishbone Slave interface
output [num_slaves*aw-1:0] wbs_adr_o,
output [num_slaves*dw-1:0] wbs_dat_o,
output [num_slaves*4-1:0] wbs_sel_o,
output [num_slaves-1:0] wbs_we_o,
output [num_slaves-1:0] wbs_cyc_o,
output [num_slaves-1:0] wbs_stb_o,
output [num_slaves*3-1:0] wbs_cti_o,
output [num_slaves*2-1:0] wbs_bte_o,
input [num_slaves*dw-1:0] wbs_dat_i,
input [num_slaves-1:0] wbs_ack_i,
input [num_slaves-1:0] wbs_err_i,
input [num_slaves-1:0] wbs_rty_i);
///////////////////////////////////////////////////////////////////////////////
// Master/slave connection
///////////////////////////////////////////////////////////////////////////////
//Use parameter instead of localparam to work around a bug in Xilinx ISE
parameter slave_sel_bits = num_slaves > 1 ? $clog2(num_slaves) : 1;
reg wbm_err;
wire [slave_sel_bits-1:0] slave_sel;
wire [num_slaves-1:0] match;
genvar idx;
generate
for(idx=0; idx<num_slaves ; idx=idx+1) begin : addr_match
assign match[idx] = (wbm_adr_i & MATCH_MASK[idx*aw+:aw]) == MATCH_ADDR[idx*aw+:aw];
end
endgenerate
//
// Find First 1 - Start from MSB and count downwards, returns 0 when no bit set
//
function [slave_sel_bits-1:0] ff1;
input [num_slaves-1:0] in;
integer i;
begin
ff1 = 0;
for (i = num_slaves-1; i >= 0; i=i-1) begin
if (in[i])
/* verilator lint_off WIDTH */
ff1 = i;
/* verilator lint_on WIDTH */
end
end
endfunction
assign slave_sel = ff1(match);
always @(posedge wb_clk_i)
wbm_err <= wbm_cyc_i & !(|match);
assign wbs_adr_o = {num_slaves{wbm_adr_i}};
assign wbs_dat_o = {num_slaves{wbm_dat_i}};
assign wbs_sel_o = {num_slaves{wbm_sel_i}};
assign wbs_we_o = {num_slaves{wbm_we_i}};
/* verilator lint_off WIDTH */
assign wbs_cyc_o = match & (wbm_cyc_i << slave_sel);
/* verilator lint_on WIDTH */
assign wbs_stb_o = {num_slaves{wbm_stb_i}};
assign wbs_cti_o = {num_slaves{wbm_cti_i}};
assign wbs_bte_o = {num_slaves{wbm_bte_i}};
assign wbm_dat_o = wbs_dat_i[slave_sel*dw+:dw];
assign wbm_ack_o = wbs_ack_i[slave_sel];
assign wbm_err_o = wbs_err_i[slave_sel] | wbm_err;
assign wbm_rty_o = wbs_rty_i[slave_sel];
endmodule