我是 蛋糕店老板,一名国科大数字IC在读研究生,研究兴趣是类脑神经网络芯片设计。
关注公众号,拉你进“IC设计交流群
”。
【蛋糕店老板 致力于写原创文章,希望将有深度、有帮助的干货文章带给大家~】
文章目录
2、AXI-Full源代码关键信号分析
2.1AXI-Full-Slave
2.2.1 Slave地址逻辑——AXI究竟如何寻址?
答案是:突发模式:包括以下三种
fixed burst
incremental burst
Wrapping burst
信号 | 方向 | 描述 |
---|---|---|
AWLEN | 主机to从机 | AWLEN[7:0]决定写传输的突发长度。AXI3只支持116次的突发传输(Burst_length=AxLEN[3:0]+1),AXI4扩展突发长度支持INCR突发类型为1256次传输,对于其他的传输类型依然保持1~16次突发传输(Burst_Length=AxLEN[7:0]+1)。burst传输具有如下规则:wraping burst ,burst长度必须是2,4,8,16burst不能跨4KB边界不支持提前终止burst传输 |
AWSIZE | 主机to从机 | 写突发大小,给出每次突发传输的字节数支持1、2、4、8、16、32、64、128 |
AWBURST | 主机to从机 | 突发类型:2’b00 FIXED:突发传输过程中地址固定,用于FIFO访问 2’b01 INCR :增量突发,传输过程中,地址递增。增加量取决AxSIZE的值。 2’b10 WRAP:回环突发,和增量突发类似,但会在特定高地址的边界处回到低地址处。回环突发的长度只能是2,4,8,16次传输,传输首地址和每次传输的大小对齐。最低的地址整个传输的数据大小对齐。回环边界等于(AxSIZE*AxLEN)2’b11 Reserved |
我们来分析突发模式代码:
复位逻辑
284行 if ( S_AXI_ARESETN == 1'b0 )
begin
axi_awaddr <= 0;
axi_awlen_cntr <= 0;
axi_awburst <= 0;
axi_awlen <= 0;
S_AXI_AWVALID信号传来时,开启地址锁存和awlen计数器的计数
293行 if (~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag)
begin
axi_awaddr <= S_AXI_AWADDR[C_S_AXI_ADDR_WIDTH - 1:0];
axi_awburst <= S_AXI_AWBURST;
axi_awlen <= S_AXI_AWLEN;
axi_awlen_cntr <= 0;
end
这段代码很重要:如果awlen计数器还没有计数到突发长度,并且此时写数据ready和vaild有效,这时候awlen计数器加一,并且引出axi_awburst类型的判断和响应操作
302行 else if((axi_awlen_cntr <= axi_awlen) && axi_wready && S_AXI_WVALID)
begin
axi_awlen_cntr <= axi_awlen_cntr + 1;
axi_awburst类型判断开始:
fixed burst 传输类型:awaddr是多少就是多少
incremental burst 传输类型:以字节寻址并且加一,字如其名自增突发
Wrapping burst 传输类型:回环突发,首先判断是不是到达回环的末尾地址:aw_wrap_en,如果不是,那么地址自己加一(字节寻址);如果是,地址回到突发地址的首位axi_awaddr <= (axi_awaddr - aw_wrap_size);
307行 case (axi_awburst)
2'b00: // fixed burst
begin
axi_awaddr <= axi_awaddr;
end
2'b01: //incremental burst
begin
axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
axi_awaddr[ADDR_LSB-1:0] <= {ADDR_LSB{1'b0}};
end
2'b10: //Wrapping burst
if (aw_wrap_en)
begin
axi_awaddr <= (axi_awaddr - aw_wrap_size);
end
else
begin
axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
axi_awaddr[ADDR_LSB-1:0] <= {ADDR_LSB{1'b0}};
end
default: //reserved (incremental burst for example)
begin
axi_awaddr <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
读地址araddr与写地址awaddr类似,就不多分析了
2.2.1 Slave数据逻辑——AXI究竟如何写\读数据?
答案是:从BRAM中读出数据
547行 generate
if (USER_NUM_MEM >= 1)
begin
assign mem_select = 1;
assign mem_address = (axi_arv_arr_flag? axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:(axi_awv_awr_flag? axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:0));
end
endgenerate
mem_address是多少呢?
axi_arv_arr_flag有效,那mem_address就是axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]
axi_awv_awr_flag有效,那mem_address就是axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]
都不满足,那mem_address就是0
其中: OPT_MEM_ADDR_BITS = 3;
The axi_awv_awr_flag代表 write address 有效
The axi_arv_arr_flag 代表 read address 有效
下面讲解 Block RAM(s)的实现
556行 generate
for(i=0; i<= USER_NUM_MEM-1; i=i+1)
begin:BRAM_GEN
wire mem_rden;
wire mem_wren;
assign mem_wren = axi_wready && S_AXI_WVALID ;
assign mem_rden = axi_arv_arr_flag ; //& ~axi_rvalid
生成Bram,mem_rden和mem_rden 设定启动条件
567行 for(mem_byte_index=0; mem_byte_index<= (C_S_AXI_DATA_WIDTH/8-1); mem_byte_index=mem_byte_index+1)
begin:BYTE_BRAM_GEN
wire [8-1:0] data_in ;
wire [8-1:0] data_out;
reg [8-1:0] byte_ram [0 : 15];
integer j;
//assigning 8 bit data
assign data_in = S_AXI_WDATA[(mem_byte_index*8+7) -: 8];
assign data_out = byte_ram[mem_address];
always @( posedge S_AXI_ACLK )
begin
if (mem_wren && S_AXI_WSTRB[mem_byte_index])
begin
byte_ram[mem_address] <= data_in;
end
end
always @( posedge S_AXI_ACLK )
begin
if (mem_rden)
begin
mem_data_out[i][(mem_byte_index*8+7) -: 8] <= data_out;
end
end
567行的代码:表示按字节寻址
下一行启动Bram生成代码BYTE_BRAM_GEN
后面定义了位宽为8,深度为16的一段存储[8-1:0] byte_ram [0 : 15];
data_in按字节赋值
data_out = byte_ram[mem_address]; 其中mem_address在之前代码给出
577行 always @( posedge S_AXI_ACLK )
begin
if (mem_wren && S_AXI_WSTRB[mem_byte_index])
begin
byte_ram[mem_address] <= data_in;
end
end
写数据阶段data_in就把数据写入ram中
always @( posedge S_AXI_ACLK )
begin
if (mem_rden)
begin
mem_data_out[i][(mem_byte_index*8+7) -: 8] <= data_out;
end
end
读数据阶段就字节寻址给出
endgenerate
读写数据结束
2.2AXI-Full-Master
AXI-Full-Master暂时不分析,跟lite类似