【AHB协议时序及代码示例】


【博客首发于微信公众号《漫谈芯片与编程》,欢迎专注一下,多谢大家】

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值