You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
6.5 KiB
Verilog

`include "defs.v"
module arb # (
) (
input clk,
input rst,
input bus_rdy_0,
input bus_rdy_1,
input [`CMD_SIZE-1:0] cmd_in_0_0,
input [`CMD_SIZE-1:0] cmd_in_1_0,
output [1:0] cmd_tkn_0,
input [`CMD_SIZE-1:0] cmd_in_0_1,
input [`CMD_SIZE-1:0] cmd_in_1_1,
output [1:0] cmd_tkn_1,
input [`CMD_SIZE-1:0] cmd_in_0_2,
input [`CMD_SIZE-1:0] cmd_in_1_2,
output [1:0] cmd_tkn_2,
input [`CMD_SIZE-1:0] cmd_in_0_3,
input [`CMD_SIZE-1:0] cmd_in_1_3,
output [1:0] cmd_tkn_3,
output [`CMD_SIZE-1:0] cmd_out_0,
output [`CMD_SIZE-1:0] cmd_out_1
);
// fairly choose 1 or 2 (depending on output buses) cmds
// mark taken from queue
// obey restrictions from smp, addr cmp, etc. (cmd_stall)
//reg [7:0] pri_0_q;
//wire [7:0] pri_0_d;
reg [1:0] pri_0_q[0:3];
wire [1:0] pri_0_d[0:3];
wire [7:0] pri_update_0;
reg [1:0] pri_1_q[0:3];
wire [1:0] pri_1_d[0:3];
wire [7:0] pri_update_1;
wire [3:0] cmd_valids_0;
wire [1:0] cmd_sel_0;
wire cmd_out_val_0;
wire [3:0] cmd_valids_1;
wire [1:0] cmd_sel_1;
wire cmd_out_val_1;
integer i;
// FF
always @(posedge clk) begin
if (rst) begin
for (i = 0; i < 4; i++) begin
pri_0_q[i] = i;
pri_1_q[i] = i;
end
end else begin
for (i = 0; i < 4; i++) begin
pri_0_q[i] = pri_0_d[i];
pri_1_q[i] = pri_1_d[i];
end
end
end
// select next commands; 00 is highest priority
assign cmd_valids_0 = {cmd_in_0_0[`CMD_VALID],cmd_in_0_1[`CMD_VALID],cmd_in_0_2[`CMD_VALID],cmd_in_0_3[`CMD_VALID]};
assign cmd_sel_0 = pri_sel(cmd_valids_0, pri_0_q);
assign cmd_out_val_0 = bus_rdy_0 & (|cmd_valids_0); //wtf depends if you want to allow it to change while bus is busy
assign cmd_out_0 = cmd_sel_0 == 2'b00 ? cmd_in_0_0 :
cmd_sel_0 == 2'b01 ? cmd_in_0_1 :
cmd_sel_0 == 2'b10 ? cmd_in_0_2 :
cmd_in_0_3;
assign cmd_valids_1 = {cmd_in_1_0[`CMD_VALID],cmd_in_1_1[`CMD_VALID],cmd_in_1_2[`CMD_VALID],cmd_in_1_3[`CMD_VALID]};
assign cmd_sel_1 = pri_sel(cmd_valids_1, pri_1_q);
assign cmd_out_val_1 = bus_rdy_1 & (|cmd_valids_1); //wtf depends if you want to allow it to change while bus is busy
assign cmd_out_1 = cmd_sel_1 == 2'b00 ? cmd_in_1_0 :
cmd_sel_1 == 2'b01 ? cmd_in_1_1 :
cmd_sel_1 == 2'b10 ? cmd_in_1_2 :
cmd_in_1_3;
// update priorities if cmd selected
assign pri_update_0 = pri_upd(cmd_sel_0, pri_0_q);
assign pri_0_d[0] = cmd_out_val_0 ? pri_update_0[1:0] : pri_0_q[0];
assign pri_0_d[1] = cmd_out_val_0 ? pri_update_0[3:2] : pri_0_q[1];
assign pri_0_d[2] = cmd_out_val_0 ? pri_update_0[5:4] : pri_0_q[2];
assign pri_0_d[3] = cmd_out_val_0 ? pri_update_0[7:6] : pri_0_q[3];
assign pri_update_1 = pri_upd(cmd_sel_1, pri_1_q);
assign pri_1_d[0] = cmd_out_val_1 ? pri_update_1[1:0] : pri_1_q[0];
assign pri_1_d[1] = cmd_out_val_1 ? pri_update_1[3:2] : pri_1_q[1];
assign pri_1_d[2] = cmd_out_val_1 ? pri_update_1[5:4] : pri_1_q[2];
assign pri_1_d[3] = cmd_out_val_1 ? pri_update_1[7:6] : pri_1_q[3];
// mark taken
assign cmd_tkn_0[0] = cmd_out_val_0 & (cmd_sel_0 == 2'b00);
assign cmd_tkn_1[0] = cmd_out_val_0 & (cmd_sel_0 == 2'b01);
assign cmd_tkn_2[0] = cmd_out_val_0 & (cmd_sel_0 == 2'b10);
assign cmd_tkn_3[0] = cmd_out_val_0 & (cmd_sel_0 == 2'b11);
assign cmd_tkn_0[1] = cmd_out_val_1 & (cmd_sel_1 == 2'b00);
assign cmd_tkn_1[1] = cmd_out_val_1 & (cmd_sel_1 == 2'b01);
assign cmd_tkn_2[1] = cmd_out_val_1 & (cmd_sel_1 == 2'b10);
assign cmd_tkn_3[1] = cmd_out_val_1 & (cmd_sel_1 == 2'b11);
endmodule
// could also account for configured thread/core priority
function [1:0] pri_sel (input [0:3] val, [1:0] pri[0:3]);
begin
pri_sel = 2'b00;
if (val[0]) begin
if (~(val[1] & pri[1] < pri[0]) | (val[2] & pri[2] < pri[0] | val[3] & pri[3] < pri[0])) begin
assign pri_sel = 2'b00;
end
end
if (val[1]) begin
if (~(val[0] & pri[0] < pri[1]) | (val[2] & pri[2] < pri[1] | val[3] & pri[3] < pri[1])) begin
assign pri_sel = 2'b01;
end
end
if (val[2]) begin
if (~(val[0] & pri[0] < pri[2]) | (val[1] & pri[1] < pri[2] | val[3] & pri[3] < pri[2])) begin
assign pri_sel = 2'b10;
end
end
if (val[3]) begin
if (~(val[0] & pri[0] < pri[3]) | (val[1] & pri[1] < pri[3] | val[2] & pri[2] < pri[3])) begin
assign pri_sel = 2'b11;
end
end
end
endfunction
//function [7:0] pri_upd (input [1:0] sel, [1:0] p3, [1:0] p2, [1:0] p1, [1:0] p0);
function [7:0] pri_upd (input [1:0] sel, [1:0] pri[0:3]);
begin
if (sel == 2'b00) begin
assign pri_upd[1:0] = 2'b11;
assign pri_upd[3:2] = pri_up(pri[0], pri[1]);
assign pri_upd[5:4] = pri_up(pri[0], pri[2]);
assign pri_upd[7:6] = pri_up(pri[0], pri[3]);
end
if (sel == 2'b01) begin
assign pri_upd[1:0] = pri_up(pri[1], pri[0]);
assign pri_upd[3:2] = 2'b11;
assign pri_upd[5:4] = pri_up(pri[1], pri[2]);
assign pri_upd[7:6] = pri_up(pri[1], pri[3]);
end
if (sel == 2'b10) begin
assign pri_upd[1:0] = pri_up(pri[2], pri[0]);
assign pri_upd[3:2] = pri_up(pri[2], pri[1]);
assign pri_upd[5:4] = 2'b11;
assign pri_upd[7:6] = pri_up(pri[2], pri[3]);
end
if (sel == 2'b11) begin
assign pri_upd[1:0] = pri_up(pri[3], pri[0]);
assign pri_upd[3:2] = pri_up(pri[3], pri[1]);
assign pri_upd[5:4] = pri_up(pri[3], pri[2]);
assign pri_upd[7:6] = 2'b11;
end
end
endfunction
// raise priority by 1, if it's higher than lvl
function [1:0] pri_up(input [1:0] lvl, [1:0] pri);
begin
/* dont work!
if (pri > lvl) begin
if (pri == 2'b01)
assign pri_up = 2'b00;
if (pri == 2'b10)
assign pri_up = 2'b01;
if (pri == 2'b11)
assign pri_up = 2'b10;
else
assign pri_up = pri;
end
*/
assign pri_up = pri > lvl ? pri - 1: pri; // 0 always sticks
end
endfunction