AHB协议时序及Verilog Demo
【博客首发于微信公众号《漫谈芯片与编程》,欢迎专注一下,多谢大家】
AHB协议用于在片上系统SoC中提供高性能通信,特别适合连接高性能(高带宽和低延迟)高时钟频率的应用,如何CPU,DMA控制器和内存控制器等;
AHB协议特点:
1.高性能:
- AHB支持单周期总线授权,可以快速响应总线请求;
- 支持突发传输(burst transfer),可以连接传输多个数据包;
2.多主多从架构:
- AHB支持多个主设备和多个从设备;每个主设备可以独立发起总线请求;
3.流水线操作
- AHB协议支持流水线操作,允许在同一时钟周期内进行多个数据传输,提高了总线利用率;
1 AHB协议
1.1 AHB系统
术语:
总线周期:总线周期是总线时间的基本单位,真实就是总线时钟的频率;
总线传输:总线传输在收到从机地址的完成响应后终止;
突发Burst传输::突发传输定义了一个或多个数据传输,由主线总机发起,在地址空间增加时,传输宽度保持不变。每次传输增加的步长(地址),由传输大小决定(字节,半字,字),APB不支持突发传输。
典型的AHB协议系统设计:AHB总线由AHB总线主机master、AHB总线从机slave和infrastructure组成。infrastrucure具体包括:仲裁器、数据多路选择器、地址和控制信号多路选择器和译码器构成;
- AHB master:master主动发起地址和控制信号;
- AHB arbiter& Multiplexer:来保证同一时刻只允许一个master处于占用总线状态;
- AHB decoder:对每次传输进行地址译码并且在传输中包含一个从机选择信号;
- AHB slave:接收写数据和返回读数据;
在下图中央多路选择器AHB协议方案中:
1.所有总线主机设备输出地址和控制信号来指示他们想执行的传输;
2.仲裁器决定哪一个主机能够将它的地址和控制信号+写数据连通到总线上的所有从机;
3.中央译码器来控制来自从机的读数据和应答信号的多路数据选择器;
1.2 AHB相关信号
hclk: 总线时钟;
hrstn:总线复位信号;
//======================
haddr[31:0]: 32位地址总线;
htrans[1:0]: 传输类型:连续、不连续、空闲和忙;
hwrite: 高:写传输;低:读传输;
hsize[2:0]: 表示传输大小–0…7,分别对应8bits(byte), 16bits(halfword),32bits(word),64bits, 128bits,256bits, 512bits,1024bits;必须小于数据总线的位宽
hburst[2:0]:表示传输是否组成了突发的一部分。支持4个,8个,16个节拍的突发传输,突发传输可以使增量或回环。
hprot[3:0]: 保护控制–提供总线访问的附加信息,主要是给希望执行某种保护级别的模块使用;例如:保护模式访问或者用户模式访问;
hwdata[31:0]: 写数据–写操作期间:主机向从机发起的写数据;
hselx: 从机选择;
hrdata: 读数据–从机–读操作期间:从机向主机传输的数据;
hready: hready为高时表示总线上的传输已完成;
hresp[1:0]: 传输影响转态:OKEY,ERROR,RETRYh和SPLIT;
1.3 AHB总线操作
在一次 AMBA AHB 传输开始之前总线主机必须被授予访问总线;过程开始于总线主机向仲裁器断言一个请求信号。仲裁器指示主机何时能够被授予使用总线。被授权的总线主机通过驱动地址和控制信号来发起一次 AMBA AHB 传输。这些信号提供关于地址、方向和传输宽度的信息,以及表示传输类型是否为一次突发传输的部分。
1.3.1 AHB基本传输
AHB基本传输包括两个部分:
1.地址相位:持续一个周期;
2.数据相位:无反压时持续一个周期,HREADY信号反压时需要维持多个周期。
无等待传输即无反压情况下:读操作和写操作;
这上面也可以看到流水线的;haddress和hwdata/hrdata的连续流水;
**有等待传输(有反压)情况下:**所谓反压就是slave未把HREADY拉高,表示忙碌,因此这笔数据传输不下去,只能维持着;直到HREADY拉高,表示这笔数据传输下去了。在反压时,地址周期需要保持,因此也叫等待传输。
A传输和C传输都是0等待周期,地址相位在T1时刻被采样后,T2时刻写数据就有效。
B传输是1等待周期,地址相位在T2时刻被采样后,T3时刻HREADY为低,这笔传输需要维持住。
C传输在T3时刻给出,但B传输未完成,T4时刻才完成,所以C传输也是等到T4时刻address生效,T5时刻被采样;
1.3.2 突发传输
突发传输是允许master在一次请求中连续传输多个数据项,而不是每一次请求只传输一个数据项,主设备在每次传输后自动递增地址,以便访问下一个连续的地址,这种传输方式减少了总线请求的次数,从而提高了总线利用率和数据传输速率;
突发传输类型:突发传输可以是递增(Incrementing)、回环(Wrapping)模式、固定Fixed模式;
- INCR:地址递增:例如:如果起始地址是 0x1000,突发长度为 4,那么传输的地址将是 0x1000, 0x1004, 0x1008, 0x100C。
- WRAP:地址在达到某个边界后回绕; 例如:如果起始地址是 0x1000,突发长度为 4,包裹边界为 16 字节(4 个 32 位字),那么传输的地址将是 0x1000, 0x1004, 0x1008, 0x100C,然后回绕到 0x1000。应用场景:主要应用在Cache操作中,因为cache是按照cache line进行操作,采用wrap传输可以方便的实现从内存中取回整个cache line。
- FIXED:在固定地址突发传输中,所有传输都使用相同的地址。例如,如果起始地址是 0x1000,突发长度为 4,那么所有传输的地址都是 0x1000。应用场景:主要应用在FIFO的传输中,因为FIFO为先入先出,只需要往同一个地址写数据即可。(AXI中存在FIXED传输);
结合Hburst的8种突发操作;
Hburst[2:0] Type 描述
000 SINGLE 单一传输
001 INCR 未指定长度的增量突发
010 WRA4 4拍回环突发
011 INCR4 4拍增量突发
100 WRAP8 8拍回环突发
101 INCR8 8拍增量突发
110 WRAP16 16拍回环突发
111 INCR16 16拍增量突发
下图表示了Htrans的作用:
该时序图阐释:表示一个突发类型为INCR的突发操作;
T0-T1: 由NONSEQ传输开始一个4拍的读操作
T1-T2: Master不能立即执行突发传输种的第二次传输,所以使用BUSY来延迟下一拍传出;注意此时地址已经是下次传输的地址,但相关信号继续保持到下一拍;但与此同时,slave提供第一拍的读数据;
T2-T3: master开始第二次传输,因此该htrans是seq,并忽略该拍下的hrdata;
T3-T4: master执行第三此传输,提供好地址,并slave返回第二次的传输rdata;
T4-T5: master执行最后一拍传输;slave无法提供第三次的hrdata,因此拉低hready一拍等待状态;
T5-T6: slave提供第三拍的数据,并且hready拉高;
T6-T7: slave提供最后一拍的读数据;
突发传输长度:可以指定传输的长度,即连续访问的地址数量。这个长度可以在传输开始前由主设备设置。
1.3.2 突发传输控制
突发传输由以下信号控制:
HTRANS:传输类型,指示当前传输是单次传输还是突发传输。
* IDLE:空闲状态。
* BUSY:忙碌状态。
* NONSEQ:非顺序传输。
* SEQ:顺序传输(用于突发传输)。
HBURST:突发类型,指示突发传输的类型(如 INCR、WRAP 等)。
HADDR:起始地址,指示突发传输的起始地址。
HWDATA/HWDATA:写数据/读数据,用于传输的数据。
HSIZE:数据大小,指示每个数据项的大小(如 8 位、16 位、32 位等)。HSIZE设置的传输大小必须≤数据总线的位宽。例如32位数据总线只能配置为b000、b001、b010;HSIZE信号和HBURST信号共同决定了Wrap Burst传输的地址边界。
一个传输HBURST为WRAP4,HSIZE为word(4 Byte),那它会在16 Byte边界上发生回卷。如果突发的起始地址是0x34,那么它的传输地址变化是:0x34、0x38、0x3C、0x30。
1.3.4 ahb_2_apb Demo代码
在这里在网上找了一个ahb_slave_2_apb_master的代码示例:
`timescale 1ns / 1ps
module ahb_to_apb #(
// Parameter to define address width
// 16 = 2^16 = 64KB APB address space
parameter ADDRWIDTH = 16,
parameter REGISTER_RDATA = 1,
parameter REGISTER_WDATA = 0
)
(
//----------------------------------
// IO Declarations
//----------------------------------
input wire HCLK, // Clock
input wire HRESETn, // Reset
input wire PCLKEN, // APB clock enable signal
input wire HSEL, // Device select
input wire [ADDRWIDTH-1:0] HADDR, // Address
input wire [1:0] HTRANS, // Transfer control
input wire [2:0] HSIZE, // Transfer size
input wire [3:0] HPROT, // Protection control
input wire HWRITE, // Write control
input wire HREADY, // Transfer phase done
input wire [31:0] HWDATA, // Write data
output reg HREADYOUT, // Device ready
output wire [31:0] HRDATA, // Read data output
output wire HRESP, // Device response
// APB Output
output wire [ADDRWIDTH-1:0] PADDR, // APB Address
output wire PENABLE, // APB Enable
output wire PWRITE, // APB Write
output wire [3:0] PSTRB, // APB Byte Strobe
output wire [2:0] PPROT, // APB Prot
output wire [31:0] PWDATA, // APB write data
output wire PSEL, // APB Select
output wire APBACTIVE, // APB bus is active, for clock gating of APB bus
// APB Input
input wire [31:0] PRDATA, // Read data for each APB slave
input wire PREADY, // Ready for each APB slave
input wire PSLVERR // Error state for each APB slave
);
//----------------------------------
// Variable Declarations
//----------------------------------
reg [ADDRWIDTH-3:0] addr_reg; // Address sample register
reg wr_reg; // Write control sample register
reg [2:0] state_reg; // State for finite state machine
reg [3:0] pstrb_reg; // Byte lane strobe register
wire [3:0] pstrb_nxt; // Byte lane strobe next state
reg [1:0] pprot_reg; // PPROT register
wire [1:0] pprot_nxt; // PPROT register next state
wire apb_select; // APB bridge is selected
wire apb_tran_end; // Transfer is completed on APB
reg [2:0] next_state; // Next state for finite state machine
reg [31:0] rwdata_reg; // Read/Write data sample register
wire reg_rdata_cfg; // REGISTER_RDATA paramater
wire reg_wdata_cfg; // REGISTER_WDATA paramater
reg sample_wdata_reg; // Control signal to sample HWDATA
//----------------------------------
// Local Parameter Declarations
//----------------------------------
// State machine
localparam ST_BITS = 3;
localparam [ST_BITS-1:0] ST_IDLE = 3'b000; // Idle waiting for transaction
localparam [ST_BITS-1:0] ST_APB_WAIT = 3'b001; // Wait APB transfer
localparam [ST_BITS-1:0] ST_APB_TRNF = 3'b010; // Start APB transfer
localparam [ST_BITS-1:0] ST_APB_TRNF2 = 3'b011; // Second APB transfer cycle
localparam [ST_BITS-1:0] ST_APB_ENDOK = 3'b100; // Ending cycle for OKAY
localparam [ST_BITS-1:0] ST_APB_ERR1 = 3'b101; // First cycle for Error response
localparam [ST_BITS-1:0] ST_APB_ERR2 = 3'b110; // Second cycle for Error response
localparam [ST_BITS-1:0] ST_ILLEGAL = 3'b111; // Illegal state
//----------------------------------
// Start of Main Code
//----------------------------------
// Configuration signal
assign reg_rdata_cfg = (REGISTER_RDATA == 0) ? 1'b0 : 1'b1;
assign reg_wdata_cfg = (REGISTER_WDATA == 0) ? 1'b0 : 1'b1;
// Generate APB bridge select
assign apb_select = HSEL & HTRANS[1] & HREADY;
// Generate APB transfer ended
assign apb_tran_end = (state_reg == 3'b011) & PREADY;
assign pprot_nxt[0] = HPROT[1]; // (0) Normal, (1) Privileged
assign pprot_nxt[1] = ~HPROT[0]; // (0) Data, (1) Instruction
// Byte strobe generation
// - Only enable for write operations
// - For word write transfers (HSIZE[1]=1), all byte strobes are 1
// - For hword write transfers (HSIZE[0]=1), check HADDR[1]
// - For byte write transfers, check HADDR[1:0]
assign pstrb_nxt[0] = HWRITE & ((HSIZE[1])|((HSIZE[0])&(~HADDR[1]))|(HADDR[1:0]==2'b00));
assign pstrb_nxt[1] = HWRITE & ((HSIZE[1])|((HSIZE[0])&(~HADDR[1]))|(HADDR[1:0]==2'b01));
assign pstrb_nxt[2] = HWRITE & ((HSIZE[1])|((HSIZE[0])&( HADDR[1]))|(HADDR[1:0]==2'b10));
assign pstrb_nxt[3] = HWRITE & ((HSIZE[1])|((HSIZE[0])&( HADDR[1]))|(HADDR[1:0]==2'b11));
// Sample control signals
always @(posedge HCLK or negedge HRESETn)
begin
if (~HRESETn) begin
addr_reg <= {(ADDRWIDTH-2){1'b0}};
wr_reg <= 1'b0;
pprot_reg <= {2{1'b0}};
pstrb_reg <= {4{1'b0}};
end
else if (apb_select) begin // Capture transfer information at the end of AHB address phase
addr_reg <= HADDR[ADDRWIDTH-1:2];
wr_reg <= HWRITE;
pprot_reg <= pprot_nxt;
pstrb_reg <= pstrb_nxt;
end
end
// Sample write data control signal
// Assert after write address phase, deassert after PCLKEN=1
wire sample_wdata_set = apb_select & HWRITE & reg_wdata_cfg;
wire sample_wdata_clr = sample_wdata_reg & PCLKEN;
always @(posedge HCLK or negedge HRESETn)
begin
if (~HRESETn)
sample_wdata_reg <= 1'b0;
else if (sample_wdata_set | sample_wdata_clr)
sample_wdata_reg <= sample_wdata_set;
end
// Generate next state for FSM
// Note : case 3'b111 is not used. The design has been checked that
// this illegal state cannot be entered using formal verification.
always @(state_reg or PREADY or PSLVERR or apb_select or reg_rdata_cfg or
PCLKEN or reg_wdata_cfg or HWRITE)
begin
case (state_reg)
// Idle
ST_IDLE : begin
if (PCLKEN & apb_select & ~(reg_wdata_cfg & HWRITE))
next_state = ST_APB_TRNF; // Start APB transfer in next cycle
else if (apb_select)
next_state = ST_APB_WAIT; // Wait for start of APB transfer at PCLKEN high
else
next_state = ST_IDLE; // Remain idle
end
// Transfer announced on AHB, but PCLKEN was low, so waiting
ST_APB_WAIT : begin
if (PCLKEN)
next_state = ST_APB_TRNF; // Start APB transfer in next cycle
else
next_state = ST_APB_WAIT; // Wait for start of APB transfer at PCLKEN high
end
// First APB transfer cycle
ST_APB_TRNF : begin
if (PCLKEN)
next_state = ST_APB_TRNF2; // Change to second cycle of APB transfer
else
next_state = ST_APB_TRNF; // Change to state-2
end
// Second APB transfer cycle
ST_APB_TRNF2 : begin
if (PREADY & PSLVERR & PCLKEN) // Error received - Generate two cycle
// Error response on AHB by
next_state = ST_APB_ERR1; // Changing to state-5 and 6
else if (PREADY & (~PSLVERR) & PCLKEN) begin // Okay received
if (reg_rdata_cfg)
// Registered version
next_state = ST_APB_ENDOK; // Generate okay response in state 4
else
// Non-registered version
next_state = {2'b00, apb_select}; // Terminate transfer
end
else // Slave not ready
next_state = ST_APB_TRNF2; // Unchange
end
// Ending cycle for OKAY (registered response)
ST_APB_ENDOK : begin
if (PCLKEN & apb_select & ~(reg_wdata_cfg & HWRITE))
next_state = ST_APB_TRNF; // Start APB transfer in next cycle
else if (apb_select)
next_state = ST_APB_WAIT; // Wait for start of APB transfer at PCLKEN high
else
next_state = ST_IDLE; // Remain idle
end
// First cycle for Error response
ST_APB_ERR1 :
next_state = ST_APB_ERR2; // Goto 2nd cycle of error response
// Second cycle for Error response
ST_APB_ERR2 : begin
if (PCLKEN & apb_select & ~(reg_wdata_cfg & HWRITE))
next_state = ST_APB_TRNF; // Start APB transfer in next cycle
else if (apb_select)
next_state = ST_APB_WAIT; // Wait for start of APB transfer at PCLKEN high
else
next_state = ST_IDLE; // Remain idle
end
default : // Not used
next_state = 3'bxxx; // X-Propagation
endcase
end
// Registering state machine
always @(posedge HCLK or negedge HRESETn)
begin
if (~HRESETn)
state_reg <= 3'b000;
else
state_reg <= next_state;
end
// Sample PRDATA or HWDATA
always @(posedge HCLK or negedge HRESETn)
begin
if (~HRESETn)
rwdata_reg <= {32{1'b0}};
else
if (sample_wdata_reg & reg_wdata_cfg & PCLKEN)
rwdata_reg <= HWDATA;
else if (apb_tran_end & reg_rdata_cfg & PCLKEN)
rwdata_reg <= PRDATA;
end
// Connect outputs to top level
assign PADDR = {addr_reg, 2'b00}; // from sample register
assign PWRITE = wr_reg; // from sample register
// From sample register or from HWDATA directly
assign PWDATA = (reg_wdata_cfg) ? rwdata_reg : HWDATA;
assign PSEL = (state_reg == ST_APB_TRNF) | (state_reg == ST_APB_TRNF2);
assign PENABLE = (state_reg == ST_APB_TRNF2);
assign PPROT = {pprot_reg[1], 1'b0, pprot_reg[0]};
assign PSTRB = pstrb_reg[3:0];
// Generate HREADYOUT
always @(state_reg or reg_rdata_cfg or PREADY or PSLVERR or PCLKEN)
begin
case (state_reg)
ST_IDLE : HREADYOUT = 1'b1; // Idle
ST_APB_WAIT : HREADYOUT = 1'b0; // Transfer announced on AHB, but PCLKEN was low, so waiting
ST_APB_TRNF : HREADYOUT = 1'b0; // First APB transfer cycle
// Second APB transfer cycle:
// if Non-registered feedback version, and APB transfer completed without error
// Then response with ready immediately. If registered feedback version,
// wait until state_reg == ST_APB_ENDOK
ST_APB_TRNF2 : HREADYOUT = (~reg_rdata_cfg) & PREADY & (~PSLVERR) & PCLKEN;
ST_APB_ENDOK : HREADYOUT = reg_rdata_cfg; // Ending cycle for OKAY (registered response only)
ST_APB_ERR1 : HREADYOUT = 1'b0; // First cycle for Error response
ST_APB_ERR2 : HREADYOUT = 1'b1; // Second cycle for Error response
default : HREADYOUT = 1'bx; // x propagation (note :3'b111 is illegal state)
endcase
end
// From sample register or from PRDATA directly
assign HRDATA = (reg_rdata_cfg) ? rwdata_reg : PRDATA;
assign HRESP = (state_reg == ST_APB_ERR1) | (state_reg == ST_APB_ERR2);
assign APBACTIVE = (HSEL & HTRANS[1]) | (|state_reg);
endmodule
【REF】
1.https://www.cnblogs.com/xianyuIC/p/17301009.html
2.https://blog.csdn.net/qq_33300585/article/details/128683551
3.https://www.cnblogs.com/wzx19970918/p/15729032.html
4.https://www.cnblogs.com/sjtu-zsj-990702/p/17251396.html
5.https://ee.ac.cn/index.php/archives/600.html