AMBA总线介绍

1 Burst传输

AMBA总线介绍-02-小白菜博客
地址传输举例

  • WRAP4--4笔回环,每笔4byte
    地址回环操作
    Wrapping burst(回环):例如4beat的wrapping burst字传输(4byte)
    0x34 -> 0x38 -> 0x3c -> 0x30,这里什么时候地址回环很有讲究,由burst和hsize共同决定,比如上面的例子是:4beat * 4byte = 16 byte =0x10,注意这里的0x10是地址的序号,而一个地址可以存储8bit数据也就是1byte数据,所以这里16byte是地址0x10。每当取数据遇到0x10的整数倍时,就要返回回环。上面的例子就是要遇到0x40了,所以需要返回回环。那如果是8beat的4byte的传输呢?那就是8beat * 4byte = 32 byte = 0x20,每0x20的整数倍就要进行回环,比如0x34 -> 0x38 -> 0x3c -> 0x20 -> 0x24 -> 0x28 -> 0x2c -> 0x30 这样走回环。如果他的起始地址恰好是回环地址的倍数,那Wrapping burst就和INCR没区别,比如INCR[4]。

INCR8 Burst

WRAP8 Burst

INCR4 Burst

WRAP4 Burst

未定义长度的Burst传输

LDM AHB Activity

INCR4和Single传输混合使用的例子

注意

  • 如果需要跨越1kb边界的传输,可以将传输切分为小的传输,1k边界之前,1k边界之后
    INCR Burst over 1k boundary
  • 跨越1K边界需要重启一个burst传输
  • 1k=1024=0x400

2 地址译码

AMBA总线介绍-02-小白菜博客

3 slave从设备的响应

响应种类

AMBA总线介绍-02-小白菜博客
AMBA总线介绍-02-小白菜博客
AMBA总线介绍-02-小白菜博客
两周期响应
AMBA总线介绍-02-小白菜博客
split和retry的区别
AMBA总线介绍-02-小白菜博客
AMBA总线介绍-02-小白菜博客
AMBA总线介绍-02-小白菜博客
split效率比retry更高

4 AHB Slave设计

  • ahb_clac_top.v
  • ahb_slave.v
  • clac.v
    一共三个模块
  • 计算模块主要处理计算,包含接口模块ahb_slave_if,直接与AHB互联,因为是slave只能接收AHB总线的访问,接收运算a,b和ctrl(运算符),进行加减,或,异或....运算,运算主要由clac模块进行
  • Master-->AHB-->计算模块-->接口-->(ahb_slave_if)配置寄存器(运算值,和运算类型及开始计算的标识)-->clac

clac模块

module clac {
  ctrl,     // 判断能不能进行计算
  clac_mode,  // 计算模式
  opcode_a,   //
  opcode_b,
  result      // 返回结果
};

  input ctrl;
  input [1:0] clac_mode;
  input [15:0] opcode_a
  input [15:0] opcode_b;
  
  output [31:0] result;
  reg [31:0] result;

  always @(*)
  begin
    if(ctrl)
      case(clac_mode)
      2'b00 : result = opcode_a & opcode_b;
      2'b01 :result = opcode_a | opcode_b;
      2'b10 :result = opcode_a ^ opcode_b;
      2'b11 :result = opcode_a + opcode_b;
      endcase
    else
      result = 2'b00;
  end
endmodule

ahb_slave

module ahb_slave_clac{
  // input signals  ahb输入
  hclk,
  hrestn,
  hsel,
  hwrite,
  hready,
  hsize,
  htrans,
  hburst,
  hwdata,
  haddr,     // 总线信号
  
  result,  
  // output signals   slave输出
  hready_resp, // 这是之前讲的hready
  hresp,
  hrdata,
  ctrl,
  clac_mode,
  opcode_a,
  opcode_b
};
  input hclk;
  input hrestn;
  input hsel;
  input hwrite;
  input hready;    // 表示当前能不能接收master的信号
  input [2:0] hsize;
  input [2:0] hburst;
  input [1:0] htrans;
  input [31:0] hwdata
  input [7:0] haddr;

  input [31:0] result;
  
  output hready_resp;     // slave输出,表示当前模块是不是能直接输出结果
  output [1:0] hresp;
  output [31:0] hrdata;
  output ctrl;
  ouput [1:0] clac_mode;
  output [15:0] opcode_a;
  output [15:0] opcode_b;
  
  reg [31:0] hrdata;

  reg hwrite_r;
  reg [2:0] hsize_r;
  reg [2:0] hburst_r
  reg [1:0] htrans_r;
  reg [7:0] haddr_r;
  
  wire ahb_write;
  wire ahb_read;
  
  reg enable_r;
  reg [1:0] ctrl_r;
  reg [15:0] opa_r;
  reg [15:0] opb_r;

  parameter IDLE = 2'b00,
            BUSY = 2'b01,
            NONSEQ = 2'b10,
            SEQ = 2'b11;
  parameter ENABLE_ADDR = 8'h00,
            CTRL_ADDR = 8'h04,
            OPA_ADDR = 8'h08,
            OPB_ADDR = 8'h0c,
            RESULT_ADDR = 8'h10;
  
  assign ctrl = enable_r;
  assign clac_mode = ctrl_r;
  assign opcode_a = opa_r;
  assign opcode_b = opb_r;
    
  assign hready_resp = 1'b1;   // hready_resp 固定为1表示能够随时输出计算结果
  assign hresp = 2'b00;

  // generate write and read signal
  assign ahb_write = ((htrans_r == NONSEQ)|| (htrans_r == SEQ)) && hwrite_r && hready
  assign ahb_read = ((htrans_r == NONSEQ)|| (htrans_r == SEQ)) && hwrite_r && hready

  always @(posedge hclk or negedge hrestn)
  begin
    if(!hrestn)
    begin
      enable_r <= 1'b0;;
      ctrl_r <= 2'b0;
      opa_r <= 16'b0;
      opb_r <= 16'b0;
    end
    else if(ahb_write)
    begin
      case(haddr_r)
        ENABLE_ADDR    :  enable_r = hwdata[0];
        CTRL_ADDR      :  ctrl_r = hwdata[1:0];
        OPA_ADDR       :  opa_r = hwdata[15:0];
        OPB_ADDR       :  opb_r = hwdata[15:0];
      endcase      
    end
  end
    
  
  // tmp the ahb address and control signals
  always@(posedge hckl or negedge hrestn)
  begin
    if(!hrestn)
      begin
        hwrite_r <= 1'b0;
        hsize_r <= 2'b0;
        hburst_r <= 3'b0;
        htrans_r <= 2'b0;
        haddr_r <= 8'b0;
      end
   else
   if(hready && hsel)   // 如果hready拉高和hsel拉高,就将控制信号寄存
   begin                // hsel是decoder输出的信号,hsel拉高,slave进行处理
     hwrite_r <= hwrite;
     hsize_r <= hsize;
     hburst_r <= hburst;
     htrans_r <= htrans;  // 将数据与data phaze对齐
     haddr_r <= haddr;
   end
   else
    begin
        hwrite_r <= 1'b0;
        hsize_r <= 2'b0;
        hburst_r <= 3'b0;
        htrans_r <= 2'b0;
        haddr_r <= 8'b0;      
    end
  end  
  

  // assign hrdata = ahb_read ? bogus_reg : 32'h0;
  always @(*)
  begin
    if(ahb_read)
    begin
      case(haddr_r[7:0])
        ENABLE_ADDR    :hrdata = {31'b0,enable_r};
        CTRL_ADDR      :hrdata = {31'b0,ctrl_r};
        OPA_ADDR       :hrdata = {16'b0,opa_r};
        OPB_ADDR       :hrdata = {16'b0,opb_r};
        RESULT_ADDR    :hrdata = result;
        default        :hrdata = 32'h0;
      endcase 
    end
    else
      hrdata = 32'h0;
  end
endmodule