AMBA总线介绍
1 Burst传输
地址传输举例
- 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 地址译码
3 slave从设备的响应
响应种类
两周期响应
split和retry的区别
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