blob: a21f54fa538b7b554206033ca5355b91483f8c65 [file] [log] [blame]
//----------------------------------------------------------------------
// Srdy/drdy round-robin arbiter
// but without the one cycle decision delay.
//
// This component supports multiple round-robin modes:
//
// Mode 0 : Each input gets a single cycle, regardless of data
// availability. This mode functions like a TDM
// demultiplexer. Output flow control will cause the
// component to stall, so that inputs do not miss their
// turn due to flow control.
// Mode 0 fast arb : Each input gets a single grant. If the
// output is not ready (p_drdy deasserted), then the
// machine will hold on that particular input until it
// receives a grant. Once a single token has been
// accepted the machine will round-robin arbitrate.
// When there are no requests the machine returns to
// its default state.
// Mode 1 : Each input can transmit for as long as it has data.
// When input deasserts, device will begin to hunt for a
// new input with data.
// Mode 2 : Continue to accept input until the incoming data
// matches a particular "end pattern". The end pattern
// is provided on the c_rearb (re-arbitrate) input. When
// c_rearb is high, will hunt for new inputs on next clock.
//
// This component also supports two arbitration modes: slow and fast.
// slow rotates the grant from requestor to requestor cycle by cycle,
// so each requestor gets serviced at most once every #inputs cycles.
// This can be useful for producing a TDM-type interface, however
// requestors may be delayed waiting for the grant to come around even
// if there are no other requestors.
//
// Fast mode immediately grants the highest-priority requestor, however
// it is drdy-noncompliant (drdy will not be asserted until srdy is
// asserted).
//
// Naming convention: c = consumer, p = producer, i = internal interface
//----------------------------------------------------------------------
// Author: Frank Wang
//
// This block is uncopyrighted and released into the public domain.
//----------------------------------------------------------------------
`ifndef _SD_RRMUX_V_
`define _SD_RRMUX_V_
// Clocking statement for synchronous blocks. Default is for
// posedge clocking and positive async reset
`ifndef SDLIB_CLOCKING
`define SDLIB_CLOCKING posedge clk or posedge reset
`endif
// delay unit for nonblocking assigns, default is to #1
`ifndef SDLIB_DELAY
`define SDLIB_DELAY #1
`endif
module sd_rrmux
#(parameter width=8,
parameter inputs=2,
parameter mode=0,
parameter fast_arb=1)
(
input clk,
input reset,
input [(width*inputs)-1:0] c_data,
input [inputs-1:0] c_srdy,
output [inputs-1:0] c_drdy,
input c_rearb, // for use with mode 2 only
output reg [width-1:0] p_data,
output [inputs-1:0] p_grant,
output reg p_srdy,
input p_drdy
);
// bmp for the c_srdy that has just been granted and accepted by p_drdy
reg [inputs-1:0] just_granted;
//control path, transit only after p_drdy ("accepted" part).
reg [inputs-1:0] to_be_granted;
//for data path, regardless of p_drdy, help to remove combo loops
//rational being, when p_drdy==1'b0, it doesn't matter what p_data is.
reg [inputs-1:0] to_tx_data;
wire [width-1:0] rr_mux_grid [0:inputs-1];
reg rr_locked;
reg nxt_rr_locked; // ri lint_check_waive NOT_DRIVEN
genvar i;
integer j;
assign c_drdy = to_be_granted & {inputs{p_drdy}};
assign p_grant = to_be_granted;
function [inputs-1:0] nxt_grant;
input [inputs-1:0] cur_grant;
input [inputs-1:0] cur_req;
input cur_accept;
reg [inputs-1:0] msk_req;
reg [inputs-1:0] tmp_grant;
reg [inputs-1:0] tmp_grant2;
begin
// scenario:
// in cycle 0, src 1 is granted and accepted by p_drdy,
// in cycle 1, src 3 is requesting, but p_drdy is 0, so c_data3 is presented at p_data with p_srdy
// in cycle 2, if src 2 comes in requesting, should hold src 3 at p_data till p_drdy,
// src 2 will only participate in next round arb.
// the way is in this scenario, pretend src2 is the just_granted in cycle 1.
// so arbitration is excercies in two cases: (1): p_drdy,
// or (2) p_not_drdy, the immediate next c_not_srdy, but at least one remote c_srdy
msk_req = cur_req & ~((cur_grant - 1) | cur_grant);
tmp_grant = msk_req & (~msk_req + 1);
tmp_grant2 = cur_req & (~cur_req + 1);
if(cur_accept)begin
if (msk_req != 0) nxt_grant = tmp_grant;
else nxt_grant = tmp_grant2;
//end else if (rem_neighbor_rearb) begin
end else if (| cur_req) begin
if (msk_req != 0) nxt_grant = {tmp_grant[0],tmp_grant[inputs-1:1]};
else nxt_grant = {tmp_grant2[0],tmp_grant2[inputs-1:1]};
end else begin
nxt_grant = cur_grant;
end
end
endfunction
generate
for (i=0; i<inputs; i=i+1)
begin : grid_assign
//assign rr_mux_grid[i] = c_data >> (i*width);
assign rr_mux_grid[i] = c_data[i*width+width-1 : i*width];
end
if (mode == 2)
begin : tp_gen
always @*
begin
nxt_rr_locked = rr_locked;
if ((c_srdy & just_granted) & (!rr_locked))
nxt_rr_locked = 1;
else if ((c_srdy & just_granted & c_rearb))
nxt_rr_locked = 0;
end
always @(`SDLIB_CLOCKING)
begin
if (reset)
rr_locked <= 0;
else
rr_locked <= nxt_rr_locked;
end
end // block: tp_gen
endgenerate
// always @*
// begin
// p_data = 0;
// p_srdy = 0;
// for (j=0; j<inputs; j=j+1)
// if (just_granted[j])
// begin
// p_data = rr_mux_grid[j];
// p_srdy = c_srdy[j];
// end
// end
always @(*) begin
p_srdy = | c_srdy;
p_data = {width{1'b0}};
for (j=0; j<inputs; j=j+1) begin
if (to_tx_data[j]) begin
p_data = rr_mux_grid[j];
p_srdy = c_srdy[j];
end
end
end
always @*
begin
to_tx_data = just_granted;
to_be_granted = just_granted;
if ((mode == 1) & (|(c_srdy & just_granted)))
to_be_granted = just_granted;
else if ((mode == 0) && !fast_arb)begin
to_be_granted=p_drdy?{just_granted[0],just_granted[inputs-1:1]}:just_granted;
to_tx_data={just_granted[0],just_granted[inputs-1:1]};
end
//else if ((mode == 0) && |(just_granted & c_srdy) && !p_drdy && fast_arb)
// to_be_granted = just_granted;
else if ((mode == 2) & (nxt_rr_locked | (|(c_srdy & just_granted))))
to_be_granted = just_granted;
else if (fast_arb) begin
to_be_granted=nxt_grant (just_granted, c_srdy, p_drdy);
to_tx_data = nxt_grant(just_granted, c_srdy, 1'b1);
end
else begin
to_be_granted=p_drdy?{just_granted[0],just_granted[inputs-1:1]}:just_granted;
to_tx_data={just_granted[0],just_granted[inputs-1:1]};
end
end
always @(`SDLIB_CLOCKING)
begin
if (reset)
just_granted <= {1'b1,{inputs-1{1'b0}}};
else
if (to_be_granted==0)
just_granted <= just_granted;
else
just_granted <= to_be_granted;
end
endmodule
`endif // _SD_RRMUX_V_