总线互联结构(以4*4的总线互联结构为例,其中对于master来说优先级3>2>0>1
,其中2是dummy master,1是defalult master):1.结构中最多可以有16个master,除去dummy master,也就是总线中支持的master数量最多为15个。这一点主要是为了适配hmaster信号一共4bit,对应16;多个master通过仲裁器来决定谁获得总线优先权,获得总线优先权的master通过地址信息和译码电路实现对具体哪个slave进行访问。仲裁器会保证同一时刻只会有一个master在工作。
2.对于dummpy master来说,在slave支持split的系统中需要存在。在如下情况中需要dummy master进行工作:(1)lock传输的时候返回split(2)slave返回split响应的时候其他master也正在split过程中。
具体代码如下:
always @ (posedge hclk or negedge hrst_n)begin
if(!hrst_n)begin
grant <= 'b0;
end
else begin
if(is_locked && (hresp == `SPLIT) || req_mask == 'b0 || (hgrantx1 && hresp == `SPLIT && !hbusreqx2 && !hbusreqx3))begin
grant <= 'b0;
end
else if(is_degrant)begin
grant <= next_grant;
end
end
end
分析:传输过程中+split;所有slave都在split;最低优先级master掌握总线并且该master被回应split。
3.slave关于split的逻辑产生:
always @ (posedge hclk or negedge hrst_n)begin
if(!hrst_n)begin
pending_split <= 'b0;
ready_split <= 'b0;
end
else if(current_state == SPLIT1)begin
case(hmaster)
4'h1: pending_split <= pending_split | 4'b0010;
4'h2: pending_split <= pending_split | 4'b0100;
4'h3: pending_split <= pending_split | 4'b1000;
default: pending_split <= pending_split | 4'b0001;
endcase
end
else begin
if(deassert_split)begin
ready_split <= pending_split | ready_split;
end
else begin
if(hsel)begin
case(hmaster)
4'h1: begin
if(ready_split[1]) begin
ready_split <= ready_split & 4'b1101;
end
end
4'h2: begin
if(ready_split[2]) begin
ready_split <= ready_split & 4'b1011;
end
end
4'h3: begin
if(ready_split[3]) begin
ready_split <= ready_split & 4'b0111;
end
end
default: begin
if(ready_split[0]) begin
ready_split <= ready_split & 4'b1110;
end
end
end
end
end
首先slave在需要进行分段传输的时候需要给master回应hresp信号,同时内部的状态机应该跳转到split的状态中,这个逻辑的产生是根据slvae自身需要发起的;
当前如果slave处在split状态,slave通过master给到自己的hmaster信号感知是哪个mater此时在和我进行数据传输,并且通过pending_split 信号记录下来这个信息,这个信息相当于记录了哪个master的数据传输被split。在slave将数据准备好的时候,deassert_split信号拉高。随后将pending的split信号给到ready的split信号,这里或了一个ready的split信号目的在于记录原来处在split状态的但是数据还没准备好的slave的信息,由于一次只会有一个master工作,清除split的时候一次只能清除一个,因此需要将这个信息保留。需要注意的是在deassert_split拉高的当前拍并不会立刻将这个slave被split的数据准备好的信息告诉mater。当deassert_split信号拉高后表示对应的slave数据已经准备好了,ready_split对应的那一位也拉高了,当ready_split对应的那一位拉高后将其清除掉进而告诉master分段数据已经准备好了(在这里为0表示准备好了,为1表示没有准备好)。
4.arbiter关于被split的master的处理:
always @ (*) begin
// Free HBUSREQ mask based on HSPLIT
next_req_mask = req_mask | HSPLIT;
// Mask bits if is_split
if(is_split) begin
case(HMASTER)
2'b00: next_req_mask[0] = 1'b0;
2'b01: next_req_mask[1] = 1'b0;
2'b10: next_req_mask[2] = 1'b0;
2'b11: next_req_mask[3] = 1'b0;
endcase
end
end
always @ (posedge HCLK or negedge HRESETn) begin
if(!HRESETn) begin
req_mask <= 4'b1111;
end
else begin
req_mask <= next_req_mask;
end
end
这里需要注意is_split信号表示slave回应给master一个split的信号,表示于当前slave建立传输的master需要被mask,直到slave准备好数据(也就是将对应的req_mask变为0)。可以观察下面对next_grant的判断的时候,在给master权限的时候都加了req_mask信号。也就是req_mask信号如果为0,那么仲裁器是不会给对应master的权限。
always @(*)begin
if(hbusreqx3 && req_mask[3])begin
next_grant = 4'h3;
end
else if(hbusreqx2 && req_mask[2])begin
next_grant = 4'h2;
end
else begin
next_grant = 4'h1;
end
end
5.arbiter中一次master的burst传输何时结束需要考虑以下几点:
(1)是否是定长传输,在定长传输的时候,由于hbusreq信号在获得总线授权的情况下该信号就会拉低,因此需要在arbiter内部设置计数器,自己计算传输什么时候结束,代码如下:
always @ (posedge hclk or negedge hrst_n)begin
if(!hrst_n)begin
count <= 'b0;
end
else begin
count <= next_count;
end
end
always @(*)begin
if(htrans == `NONSEQ)begin
if(hready)begin
case(hburst)
`WRAP4: next_count = 6'h3;
`INCR4: next_count = 6'h3;
`WRAP8: next_count = 6'h7;
`INCR8: next_count = 6'h7;
`WRAP16: next_count = 6'hf;
`WRAP16: next_count = 6'hf;
endcase
end
else begin
case(hburst)
`WRAP4: next_count = 6'h4;
`INCR4: next_count = 6'h4;
`WRAP8: next_count = 6'h8;
`INCR8: next_count = 6'h8;
`WRAP16: next_count = 6'h10;
`WRAP16: next_count = 6'h10;
endcase
end
end
else if(htrans == `BUSY)begin
next_count = count;
end
else if(htrans == `IDLE)begin
next_count = 'b0;
end
else begin
if(hready)begin
next_count = count - 1;
end
else begin
next_count = count;
end
end
end
在count赋值的时候需要考虑当前拍的ready信号,如果ready信号为高说明当前拍已经算一次传输周期了,因此count值要减一。
(2)不是定长传输的时候,由于hbusreq需要持续拉高,因此可以用hbusreq和对应的hgrant信号合并判断什么时候数据传输结束。此外还需要考虑split、retry、idle情况时,也是相当于需要开启一下新的传输。整体逻辑如下:
always @ (*)begin
if(!is_fixed_length && ((hgrantx0 && !hbusreqx0)||
(hgrantx1 && !hbusreqx1)||
(hgrantx2 && !hbusreqx2)||
(hgrantx3 && !hbusreqx3)))begin
is_degrant = 'b1;
end
else if(htrans == `IDLE)begin
is_degrant = 'b1;
end
else if(is_fixed_length && (!is_locked) && (next_count == 'b0 || next_count == 'b1))begin
is_degrant = 'b1;
end
else if(is_split || is_retry)begin
is_degrant = 'b1;
end
else begin
is_degrant = 'b0;
end
end
5.slave的lock逻辑产生: