还是基于状态机,思路是收到了一包AW通道的数据,记录下它的len,然后根据len和awid收相应的AXI Master的W通道数据,保证AW通道和W通道顺序一致。

那权重怎么变化呢?此处想的是每AW和W通道完成一次收数,权重变化一次。注意要保证AW接受和W接收必须来自同一个AXI Master
等待某个AW通道与AXI Slave握手完成,即可转入下一状态
● 根据req输出grant
此处的req其实就是各AXI Master的awvalid组成的多bit数据,而grant就是仲裁的结果。注意在WAIT_AW时状态不发生变化
● 状态转移条件:AW通道握手完成
注意原算法的状态转移条件是req发生变化就转移,但在此处需要某个Master的awvalid为高且awready信号拉高才能握手,如下图

prio其实就是权重。虽然req中途发生了变化,但状态转移的条件是与Master0握手完成才转移条件。
注意AW通道只是一次性传递多个控制信息,不是burst,awready&awvalid有效一拍即可完成握手。
转入WAIT_W状态后awready不应再拉高,必须等待从WAIT_W回到WAIT_AW才能再拉高。
然后进入WAIT_W状态,之前WAIT_AW状态下与哪个Master完成了握手,此处就必须等这个Master的W通道握手完成才能结束WAIT_W状态。
● grant保持,接受W通道数据
这里的grant必须要与WAIT_AW状态下握手完成时的grant一致,同时要一直接受W通道来的数据
● 状态转移条件:W通道握手完成
由于Master是固定的,所以只需看那个Master的wlast即可,这个信号表示最后一个数据。

握手完成之后,重新回到WAIT_AW状态。注意此时prio权重也要根据grant作修正,同时grant不能再继续保持了,转入WAIT_AW后要根据awvalid_mst作组合逻辑输出
综上所述,状态机变成

module axi_round_robin_arbiter_aw_w #(
parameter AWID_WIDTH = 8,
parameter AWADDR_WIDTH = 16,
parameter WDATA_WIDTH = 16,
parameter MAX_PRIO_INITIAL_INDEX = 0
)(
input aclk,
input arstn,
//AW CHANNEL
input [(AWID_WIDTH+2)*4-1:0] awid_mst,
input [AWADDR_WIDTH*4-1:0] awaddr_mst,
input [8*4-1:0] awlen_mst,
input [3*4-1:0] awsize_mst,
input [2*4-1:0] awburst_mst,
input [1*4-1:0] awvalid_mst,
output [1*4-1:0] awready_mst,
output [(AWID_WIDTH+2)-1:0] awid,
output [AWADDR_WIDTH-1:0] awaddr,
output [8-1:0] awlen,
output [3-1:0] awsize,
output [2-1:0] awburst,
output awvalid,
input awready,
//W CHANNEL
input [WDATA_WIDTH*4-1:0] wdata_mst,
input [1*4-1:0] wlast_mst,
input [1*4-1:0] wvalid_mst,
output [1*4-1:0] wready_mst,
output [WDATA_WIDTH-1:0] wdata,
output [1-1:0] wlast,
output [1-1:0] wvalid,
input [1-1:0] wready
);
localparam WAIT_AW = 1'b0;
localparam WAIT_W = 1'b1;
reg [4-1:0] cur_state;
reg [4-1:0] nxt_state;
reg [4-1:0] grant;
reg [4-1:0] grant_tmp;
reg [4-1:0] prio;
reg wvalid_mst_cs;
reg wlast_mst_cs;
wire [4-1:0] inital_state;
wire [4:0] res1;
wire [4:0] res2;
assign inital_state = {{(4-MAX_PRIO_INITIAL_INDEX-1){1'b0}},1'b1,{MAX_PRIO_INITIAL_INDEX{1'b0}}};
always@(posedge aclk or negedge arstn) begin
if(!arstn)
cur_state <= WAIT_AW;
else
cur_state <= nxt_state;
end
always@(*) begin
case(cur_state)
WAIT_AW:
if((|awvalid_mst) && awready)
nxt_state = WAIT_W;
else
nxt_state = WAIT_AW;
WAIT_W:
if(wvalid_mst_cs && wlast_mst_cs && wready)
nxt_state = WAIT_AW;
else
nxt_state = WAIT_W;
default: nxt_state = WAIT_AW;
endcase
end
always@(posedge aclk or negedge arstn) begin
if(!arstn)
prio <= inital_state;
else if(cur_state == WAIT_W && wvalid_mst_cs && wlast_mst_cs && wready)
prio <= (grant[3])? 4'b1:(grant << 1);
end
always@(*) begin
if(cur_state == WAIT_AW)
wlast_mst_cs = 1'b0;
else begin
case(grant)
4'b0001:
wlast_mst_cs = wlast_mst[0];
4'b0010:
wlast_mst_cs = wlast_mst[1];
4'b0100:
wlast_mst_cs = wlast_mst[2];
4'b1000:
wlast_mst_cs = wlast_mst[3];
default:
wlast_mst_cs = 1'b0;
endcase
end
end
always@(*) begin
if(cur_state == WAIT_W)
wvalid_mst_cs = 1'b0;
else begin
case(grant)
4'b0001:
wvalid_mst_cs = wvalid_mst[0];
4'b0010:
wvalid_mst_cs = wvalid_mst[1];
4'b0100:
wvalid_mst_cs = wvalid_mst[2];
4'b1000:
wvalid_mst_cs = wvalid_mst[3];
default:
wvalid_mst_cs = 1'b0;
endcase
end
end
always@(posedge aclk or negedge arstn) begin
if(!arstn)
grant_tmp <= 'd0;
else if(cur_state == WAIT_AW && (|awvalid_mst) && awready)
grant_tmp <= grant;
end
assign res1 = {1'b0,~awvalid_mst} + {1'b0,prio};
assign res2 = res1[4] + res1;
always@(*) begin
if(cur_state == WAIT_AW)
grant = awvalid_mst & res2;
else
grant = grant_tmp;
end
//-----------------AW channel chip select--------------------------
reg [(AWID_WIDTH+2)-1:0] awid_r;
reg [AWADDR_WIDTH-1:0] awaddr_r;
reg [8-1:0] awlen_r;
reg [3-1:0] awsize_r;
reg [2-1:0] awburst_r;
reg awvalid_r;
reg [1*4-1:0] awready_mst_r;
always@(*) begin
if(cur_state == WAIT_AW) begin
case(grant)
4'b0001:
awid_r = awid_mst[(AWID_WIDTH+2)-1:0];
4'b0010:
awid_r = awid_mst[(AWID_WIDTH+2)*2-1:(AWID_WIDTH+2)];
4'b0100:
awid_r = awid_mst[(AWID_WIDTH+2)*3-1:(AWID_WIDTH+2)*2];
4'b1000:
awid_r = awid_mst[(AWID_WIDTH+2)*4-1:(AWID_WIDTH+2)*3];
default:
awid_r = 'd0;
endcase
end
else
awid_r = 'd0;
end
assign awid = awid_r;
always@(*) begin
if(cur_state == WAIT_AW) begin
case(grant)
4'b0001:
awaddr_r = awaddr_mst[AWADDR_WIDTH-1:0];
4'b0010:
awaddr_r = awaddr_mst[AWADDR_WIDTH*2-1:AWADDR_WIDTH];
4'b0100:
awaddr_r = awaddr_mst[AWADDR_WIDTH*3-1:AWADDR_WIDTH*2];
4'b1000:
awaddr_r = awaddr_mst[AWADDR_WIDTH*4-1:AWADDR_WIDTH*3];
default:
awaddr_r = 'd0;
endcase
end
else
awaddr_r = 'd0;
end
assign awaddr = awaddr_r;
always@(*) begin
if(cur_state == WAIT_AW) begin
case(grant)
4'b0001:
awlen_r = awlen_mst[8-1:0];
4'b0010:
awlen_r = awlen_mst[8*2-1:8];
4'b0100:
awlen_r = awlen_mst[8*3-1:8*2];
4'b1000:
awlen_r = awlen_mst[8*4-1:8*3];
default:
awlen_r = 'd0;
endcase
end
else
awlen_r = 'd0;
end
assign awlen = awlen_r;
always@(*) begin
if(cur_state == WAIT_AW) begin
case(grant)
4'b0001:
awsize_r = awsize_mst[3-1:0];
4'b0010:
awsize_r = awsize_mst[3*2-1:3];
4'b0100:
awsize_r = awsize_mst[3*3-1:3*2];
4'b1000:
awsize_r = awsize_mst[3*4-1:3*3];
default:
awsize_r = 'd0;
endcase
end
else
awsize_r = 'd0;
end
assign awsize = awsize_r;
always@(*) begin
if(cur_state == WAIT_AW) begin
case(grant)
4'b0001:
awburst_r = awburst_mst[2-1:0];
4'b0010:
awburst_r = awburst_mst[2*2-1:2];
4'b0100:
awburst_r = awburst_mst[2*3-1:2*2];
4'b1000:
awburst_r = awburst_mst[2*4-1:2*3];
default:
awburst_r = 'd0;
endcase
end
else
awburst_r = 'd0;
end
assign awburst = awburst_r;
always@(*) begin
if(cur_state == WAIT_AW) begin
case(grant)
4'b0001:
awvalid_r = awvalid_mst[1-1:0];
4'b0010:
awvalid_r = awvalid_mst[1*2-1:1];
4'b0100:
awvalid_r = awvalid_mst[1*3-1:1*2];
4'b1000:
awvalid_r = awvalid_mst[1*4-1:1*3];
default:
awvalid_r = 'd0;
endcase
end
else
awvalid_r = 'd0;
end
assign awvalid = awvalid_r;
always@(*) begin
if(cur_state == WAIT_AW)
awready_mst_r = awready << grant;
else
awready_mst_r = 'd0;
end
assign awready_mst = awready_mst_r;
//-----------------W channel chip select--------------------------
reg [1*4-1:0] wready_mst_r;
reg [WDATA_WIDTH-1:0] wdata_r;
reg [1-1:0] wlast_r;
reg [1-1:0] wvalid_r;
always@(*) begin
if(cur_state == WAIT_AW)
wready_mst_r = 'd0;
else
wready_mst_r = wready << grant;
end
assign wready_mst = wready_mst_r;
always@(*) begin
if(cur_state == WAIT_AW)
wdata_r = 'd0;
else begin
case(grant)
4'b0001:
wdata_r = wdata_mst[WDATA_WIDTH-1:0];
4'b0010:
wdata_r = wdata_mst[WDATA_WIDTH*2-1:WDATA_WIDTH];
4'b0100:
wdata_r = wdata_mst[WDATA_WIDTH*3-1:WDATA_WIDTH*2];
4'b1000:
wdata_r = wdata_mst[WDATA_WIDTH*4-1:WDATA_WIDTH*3];
default:
wdata_r = 'd0;
endcase
end
end
assign wdata = wdata_r;
always@(*) begin
if(cur_state == WAIT_AW)
wlast_r = 'd0;
else begin
case(grant)
4'b0001:
wlast_r = wlast_mst[0];
4'b0010:
wlast_r = wlast_mst[1];
4'b0100:
wlast_r = wlast_mst[2];
4'b1000:
wlast_r = wlast_mst[3];
default:
wlast_r = 'd0;
endcase
end
end
assign wlast = wlast_r;
always@(*) begin
if(cur_state == WAIT_AW)
wvalid_r = 'd0;
else begin
case(grant)
4'b0001:
wvalid_r = wvalid_mst[0];
4'b0010:
wvalid_r = wvalid_mst[1];
4'b0100:
wvalid_r = wvalid_mst[2];
4'b1000:
wvalid_r = wvalid_mst[3];
default:
wvalid_r = 'd0;
endcase
end
end
assign wvalid = wvalid_r;
endmodule
可以发现,在上述状态机的设计中,WAIT_AW状态时AXI Master的AW通道和AXI Slave的AW通道信号能够相互通信,但此时W通道被阻断。在WAIT_W状态下,W通道的信号被打通,而AW通道的信号被阻隔。
此时想到,在WAIT_W状态下,AW通道直接被阻隔了,那能不能放开,让AW通道正常通信,即WAIT_AW和WAIT_W两种状态并行呢?
流水线设计可从状态机改造而来,例如乘法器就可分为先单bit相乘、再错位相加,那么在错位相加的时候可不可以对新的数据进行单bit相乘呢?可以,按照这个思路就将状态机优化成流水线了。
RTL乘法器IP设计
当然不是所有的状态机都可以完全优化成流水线,有的完全不能优化(例如USART),有的可以将部分状态进行流水优化。
那么 怎么将WAIT_AW和WAIT_W并行起来呢?
AW通道和W通道协同设计的根本原因是,W通道没有wid,所以AW通道的收数顺序必须与W通道的收数顺序一致。
所以,只需每次AW完成握手一次,记录下此时握手的Master是谁,即grant。每完成一次握手就将grant放入FIFO,而W通道呢则每完成一次握手就从FIFO读出grant知道下次要交互的Master,这样就实现了AW通道和W通道的流水啦。
既然两个通道使用同步FIFO隔离,那么就可以分成两个模块了

AW通道仲裁比较好说,但还是要使用状态机,此处的状态就要改成FIFO是否满了,FIFO满了通信就要阻断。
module axi_round_robin_arbiter_aw #(
parameter AWID_WIDTH = 8,
parameter AWADDR_WIDTH = 16,
parameter MAX_PRIO_INITIAL_INDEX = 0
)(
input aclk,
input arstn,
//AW CHANNEL
input [(AWID_WIDTH+2)*4-1:0] awid_mst,
input [AWADDR_WIDTH*4-1:0] awaddr_mst,
input [8*4-1:0] awlen_mst,
input [3*4-1:0] awsize_mst,
input [2*4-1:0] awburst_mst,
input [1*4-1:0] awvalid_mst,
output [1*4-1:0] awready_mst,
output [(AWID_WIDTH+2)-1:0] awid,
output [AWADDR_WIDTH-1:0] awaddr,
output [8-1:0] awlen,
output [3-1:0] awsize,
output [2-1:0] awburst,
output awvalid,
input awready,
input grant_fifo_full,
output [4-1:0] grant,
output grant_val
);
reg [4-1:0] cur_state;
reg [4-1:0] nxt_state;
wire [4-1:0] inital_state;
wire [4:0] res1;
wire [4:0] res2;
assign inital_state = {{(4-MAX_PRIO_INITIAL_INDEX-1){1'b0}},1'b1,{MAX_PRIO_INITIAL_INDEX{1'b0}}};
always@(posedge aclk or negedge arstn) begin
if(!arstn)
cur_state <= inital_state;
else
cur_state <= nxt_state;
end
always@(*) begin
if(grant_val) begin
if(grant[3])
nxt_state = 4'b1;
else
nxt_state = grant << 1;
end
else
nxt_state = cur_state;
end
assign res1 = {1'b0,~awvalid_mst} + {1'b0,cur_state};
assign res2 = res1[4] + res1;
assign grant = awvalid_mst & res2;
assign grant_val = awvalid && awready;
//-----------------AW channel chip select--------------------------
reg [(AWID_WIDTH+2)-1:0] awid_r;
reg [AWADDR_WIDTH-1:0] awaddr_r;
reg [8-1:0] awlen_r;
reg [3-1:0] awsize_r;
reg [2-1:0] awburst_r;
reg awvalid_r;
reg [1*4-1:0] awready_mst_r;
always@(*) begin
if(!grant_fifo_full) begin
case(grant)
4'b0001:
awid_r = awid_mst[(AWID_WIDTH+2)-1:0];
4'b0010:
awid_r = awid_mst[(AWID_WIDTH+2)*2-1:(AWID_WIDTH+2)];
4'b0100:
awid_r = awid_mst[(AWID_WIDTH+2)*3-1:(AWID_WIDTH+2)*2];
4'b1000:
awid_r = awid_mst[(AWID_WIDTH+2)*4-1:(AWID_WIDTH+2)*3];
default:
awid_r = 'd0;
endcase
end
else
awid_r = 'd0;
end
assign awid = awid_r;
always@(*) begin
if(!grant_fifo_full) begin
case(grant)
4'b0001:
awaddr_r = awaddr_mst[AWADDR_WIDTH-1:0];
4'b0010:
awaddr_r = awaddr_mst[AWADDR_WIDTH*2-1:AWADDR_WIDTH];
4'b0100:
awaddr_r = awaddr_mst[AWADDR_WIDTH*3-1:AWADDR_WIDTH*2];
4'b1000:
awaddr_r = awaddr_mst[AWADDR_WIDTH*4-1:AWADDR_WIDTH*3];
default:
awaddr_r = 'd0;
endcase
end
else
awaddr_r = 'd0;
end
assign awaddr = awaddr_r;
always@(*) begin
if(!grant_fifo_full) begin
case(grant)
4'b0001:
awlen_r = awlen_mst[8-1:0];
4'b0010:
awlen_r = awlen_mst[8*2-1:8];
4'b0100:
awlen_r = awlen_mst[8*3-1:8*2];
4'b1000:
awlen_r = awlen_mst[8*4-1:8*3];
default:
awlen_r = 'd0;
endcase
end
else
awlen_r = 'd0;
end
assign awlen = awlen_r;
always@(*) begin
if(!grant_fifo_full) begin
case(grant)
4'b0001:
awsize_r = awsize_mst[3-1:0];
4'b0010:
awsize_r = awsize_mst[3*2-1:3];
4'b0100:
awsize_r = awsize_mst[3*3-1:3*2];
4'b1000:
awsize_r = awsize_mst[3*4-1:3*3];
default:
awsize_r = 'd0;
endcase
end
else
awsize_r = 'd0;
end
assign awsize = awsize_r;
always@(*) begin
if(!grant_fifo_full) begin
case(grant)
4'b0001:
awburst_r = awburst_mst[2-1:0];
4'b0010:
awburst_r = awburst_mst[2*2-1:2];
4'b0100:
awburst_r = awburst_mst[2*3-1:2*2];
4'b1000:
awburst_r = awburst_mst[2*4-1:2*3];
default:
awburst_r = 'd0;
endcase
end
else
awburst_r = 'd0;
end
assign awburst = awburst_r;
always@(*) begin
if(!grant_fifo_full) begin
case(grant)
4'b0001:
awvalid_r = awvalid_mst[1-1:0];
4'b0010:
awvalid_r = awvalid_mst[1*2-1:1];
4'b0100:
awvalid_r = awvalid_mst[1*3-1:1*2];
4'b1000:
awvalid_r = awvalid_mst[1*4-1:1*3];
default:
awvalid_r = 'd0;
endcase
end
else
awvalid_r = 'd0;
end
assign awvalid = awvalid_r;
always@(*) begin
if(!grant_fifo_full)
awready_mst_r = awready << grant;
else
awready_mst_r = 'd0;
end
assign awready_mst = awready_mst_r;
endmodule
对于W通道而言,必须从FIFO读出grant才能与grant规定的Master握手,所以还是按照状态机的设计过程,分为两个状态

该状态下就一直读FIFO,同时W通道被阻塞,直到grant被读出

此时grant会一直保持,按照grant选择Master等待握手完成就可以。

module axi_round_robin_arbiter_w #(
parameter WDATA_WIDTH = 16,
parameter MAX_PRIO_INITIAL_INDEX = 0
)(
input aclk,
input arstn,
//W CHANNEL
input [WDATA_WIDTH*4-1:0] wdata_mst,
input [1*4-1:0] wlast_mst,
input [1*4-1:0] wvalid_mst,
output [1*4-1:0] wready_mst,
output [WDATA_WIDTH-1:0] wdata,
output [1-1:0] wlast,
output [1-1:0] wvalid,
input [1-1:0] wready,
output fifo_rd_en,
input fifo_empty,
input [4-1:0] grant,
input grant_val
);
localparam IDLE = 2'b00;
localparam RD_GRANT = 2'b01;
localparam HANDSHAKE = 2'b11;
reg [1:0] cur_state;
reg [1:0] nxt_state;
reg fifo_rd_en_r;
always@(posedge aclk or negedge arstn) begin
if(!arstn)
cur_state <= IDLE;
else
cur_state <= nxt_state;
end
always@(*) begin
case(cur_state)
IDLE:
nxt_state = RD_GRANT;
RD_GRANT:
if(grant_val)
nxt_state = HANDSHAKE;
else
nxt_state = RD_GRANT;
HANDSHAKE:
if(wlast && wready)
nxt_state = HANDSHAKE;
else
nxt_state = RD_GRANT;
default: nxt_state = IDLE;
endcase
end
always@(posedge aclk or negedge arstn) begin
if(!arstn)
fifo_rd_en_r <= 1'b0;
else if(cur_state == IDLE)
fifo_rd_en_r <= 1'b1;
else if(cur_state == RD_GRANT) begin
if(!fifo_empty)
fifo_rd_en_r <= 1'b0;
end
else if(cur_state == HANDSHAKE) begin
if(wlast && wready)
fifo_rd_en_r <= 1'b1;
end
end
assign fifo_rd_en = fifo_rd_en_r;
//-----------------W channel chip select--------------------------
reg [1*4-1:0] wready_mst_r;
reg [WDATA_WIDTH-1:0] wdata_r;
reg [1-1:0] wlast_r;
reg [1-1:0] wvalid_r;
always@(*) begin
if(!cur_state[0]) //(cur_state == IDLE) && (cur_state == RD_GRANT)
wready_mst_r = 'd0;
else
wready_mst_r = wready << grant;
end
assign wready_mst = wready_mst_r;
always@(*) begin
if(!cur_state[0])
wdata_r = 'd0;
else begin
case(grant)
4'b0001:
wdata_r = wdata_mst[WDATA_WIDTH-1:0];
4'b0010:
wdata_r = wdata_mst[WDATA_WIDTH*2-1:WDATA_WIDTH];
4'b0100:
wdata_r = wdata_mst[WDATA_WIDTH*3-1:WDATA_WIDTH*2];
4'b1000:
wdata_r = wdata_mst[WDATA_WIDTH*4-1:WDATA_WIDTH*3];
default:
wdata_r = 'd0;
endcase
end
end
assign wdata = wdata_r;
always@(*) begin
if(!cur_state[0])
wlast_r = 'd0;
else begin
case(grant)
4'b0001:
wlast_r = wlast_mst[0];
4'b0010:
wlast_r = wlast_mst[1];
4'b0100:
wlast_r = wlast_mst[2];
4'b1000:
wlast_r = wlast_mst[3];
default:
wlast_r = 'd0;
endcase
end
end
assign wlast = wlast_r;
always@(*) begin
if(!cur_state[0])
wvalid_r = 'd0;
else begin
case(grant)
4'b0001:
wvalid_r = wvalid_mst[0];
4'b0010:
wvalid_r = wvalid_mst[1];
4'b0100:
wvalid_r = wvalid_mst[2];
4'b1000:
wvalid_r = wvalid_mst[3];
default:
wvalid_r = 'd0;
endcase
end
end
assign wvalid = wvalid_r;
endmodule