AMBA总线介绍-02
AMBA总线介绍
1 HSIZE
AHB总线的地址位宽和数据位宽一般都是32bit,一个字节8bit,一个字节占用一个地址空间,但当一个32bit的数据写入一个存储器中或者从一个存储器中读取,32bit数据几个时钟能够传输完成,这和hsize信号有关,这个信号表示一个时钟周期传输的数据的位宽,当hsize[2:0]=3'b000,一个时钟周期完成一个8bit数据传输,每个时钟,地址递增一个,所以hdata[31:0]需要4个时钟周期完成传输,如果hsize[2:0]=3'b001,一个时钟周期完成16bit数据传输,所以hdata[31:0]对应2个时钟周期,以此类推。
2 Burst传输
地址传输举例
- 地址加1,表示加一个单位,是由HSIZE决定的,byte--地址增加0,1,2,3,4,5,6;halfword--地址增加0,2,4,6,8;word--地址增加0,4,8,c
- 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
3 地址译码
- HADDR是一个广播信号,需要通过HSEL信号决定选择的slave
4 slave从设备的响应
响应种类
两周期响应
split和retry的区别
split效率比retry更高
5 Arbiter
仲裁举例
说明
AHB主设备接口
master发起仲裁请求,得到授权之后,锁定总线,发送控制信号、地址信号、写数据
AHB从设备接口
slave被选中之后,根据控制信号、地址信号进行写数据和读数据操作,并给出响应
AHB Arbiter接口
AHB Decoder接口
6 多层AHB系统结构举例
7 AHB总结
8 AHB Slave
- ahb_clac_top.v
- ahb_slave_.v
- clac.v
一共三个模块 - master想要进行计算操作,需要配置AHB_slave_if中的寄存器(包括计算模块的使能寄存器\操作符寄存器\操作数寄存器),ahb_slave_if接收到master通过ahb发送过来信息之后配置寄存器,配置完成寄存器之后就会输出对于计算模块的输出信号,计算模块接受到输出信号之后,进行相应的计算,然后将结果返回给ahb_slave_if模块,然后返回给master
- 计算模块主要处理计算,接收运算a,b和ctrl(运算符),进行加减,或,异或....运算,运算主要由clac模块进行
- Master-->AHB-->接口(ahb_slave_if)配置寄存器(运算值,和运算类型及开始计算的标识)-->clac
8.1 clac.v模块
- 接收来自ahb_slave_if.v的控制信号(操作符\操作数\使能信号),完成计算并返回相应的结果
module clac {
input ctrl, // 判断能不能进行计算
input [1:0] clac_mode, // 四种计算模式,所以需要2bit
input [15:0] opcode_a, //
input [15:0] opcode_b,
input 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 = 32'b00;
end
endmodule
8.2 ahb_slave_if.v
module ahb_slave_if{
// input signals ahb输入
input hclk, // 时钟
input hrestn, // 复位
input hsel,
input hwrite,
input hready,
input [2:0] hsize,
input [1:0] htrans,
input [2:0] hburst,
input [31:0] hwdata,
input [7:0] haddr, // 总线信号
input [31:0] result,
// output signals slave输出
output hready_resp, // 这是之前讲的hready
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;
// ahb控制信号要打一拍,所以要设置寄存器
reg hwrite_r;
reg [2:0] hsize_r;
reg [2:0] hburst_r
reg [1:0] htrans_r;
reg [7:0] haddr_r;
// 将ahb总线的信号和打拍的信号转换为读写信号,通过写信号,写ahb_slave_if中的控制寄存器,通过读信号读取ahb_slave_if中的读数据寄存器
wire ahb_write;
wire ahb_read;
// master要进行读写操作,需要配置这些寄存器
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;
// 寄存器有相应的地址,通过ahb传递过来的地址,配置相应的寄存器,配置好寄存器之后,clac模块才知道做什么
parameter ENABLE_ADDR = 8'h00, // 定义寄存器地址
CTRL_ADDR = 8'h04,
OPA_ADDR = 8'h08,
OPB_ADDR = 8'h0c,
RESULT_ADDR = 8'h10;
// 1.将ahb总线的地址信号和控制信号进行打拍,与数据阶段对齐
// 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
// 2.根据ahb信号产生读写信号
// 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
// 3.进行写操作,需要配置控制寄存器
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]; // 配置寄存器的地址从haddr中得到,根据地址配置相应的寄存器
CTRL_ADDR : ctrl_r = hwdata[1:0];
OPA_ADDR : opa_r = hwdata[15:0];
OPB_ADDR : opb_r = hwdata[15:0];
endcase
end
end
// 4.进行读操作,
// 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}; // 读数据,读取的是ahb_slave_if中寄存器的值,很据haddr中的低8bit找到相应的寄存器读取值
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
// 将控制信号输出给clac模块
assign ctrl = enable_r;
assign clac_mode = ctrl_r;
assign opcode_a = opa_r;
assign opcode_b = opb_r;
// 返回给ahb的信号
assign hready_resp = 1'b1; // hready_resp 固定为1表示能够随时输出计算结果
assign hresp = 2'b00;
endmodule