AHB和APB總線基礎


AHB

典型AMBA系統中的AHB

特點
1、高性能
2、通道操作
3、突發傳輸
4、多總線主機
5、分塊傳輸

AHB基本信號

Master
(1)HADDR[31:0]:32位系統地址總線
(2)HWDATA:寫數據總線,從Mastre指向Slave
(3)HWRITE:傳輸方向,1-寫,0-讀
(4)HTRANS[1:0]:指示傳輸類型,00-空閑,01-忙,10-非連續,11-連續

      空閑:表示沒有數據傳輸的要求。
      忙:允許總線主機在突發傳輸中間插入空閑周期。這種傳輸類型表示總線主機正在連續執行一個突發傳輸,但是下一次傳輸不能立即發生。
      非連續:表示一次突發的第一個傳輸或者一個單一傳輸。
      連續:表示突發中剩下的傳輸,其地址是和上一次傳輸有關的,控制信息和前一次傳輸一樣,地址等於前一次傳輸的地址加上傳輸大小(字節)。

(5)HSIZE[2:0]:傳輸單位,000-字節,001-半字,010-字,011-雙字,…… 111-1024位
(6)HBURST[2:0]:表示突發類型,支持四個、八個或者 16 個節拍的突發傳輸並且突發傳輸可以是增量或者是回環。

      增量突發:訪問連續地址並且突發中的每次傳輸地址僅是前一次地址的一個增量,如0x38, 0x3C, 0x40, 0x44;
      回環突發:如果傳輸的起始地址並未和突發(x 拍)中字節總數對齊那么突發傳輸地址將在達到邊界處回環。例如,一個四拍回環突發的字
(4 字節)訪問將在16 字節邊界回環。因此,如果傳輸的起始地址是 0x38,那么它將包含四個到地址0x38, 0x3C, 0x30, 0x34;

      一些突發規則:
      1、突發禁止超過1KB的地址邊界,1k邊界是指低10bit為0的地址,例如32'h00000400,32'h00000800...;
ARM對AHB burst這樣設計的目的是在於,SLAVE的地址訪問空間基本都是以1KB為單位的,當AHB以burst方式傳輸時,
為了避免錯誤的訪問到其他的Slave空間而造成系統致命錯誤,因此在burst傳輸時限制1KB,若需要跨1KB邊界時,
需要重新initial一個新的傳輸。在AHB划分系統時,最小的地址空間為1KB,即slave至少地址空間是1k,或者2K,或者1M等。
這樣,當AHB訪問地址空間時,因為地址空間對其的原因,就不會惡意的訪問到其他的地址空間。https://blog.csdn.net/hit_shaoqi/article/details/53245521
      2、一個增量突發可以是任何長度,但是上限由地址不能超過1KB邊界這個事實限定。
      3、突發大小表示突發的節拍數量,而每拍字節數由HSIZE[1:0]指示。
      4、所有突發傳輸必須將地址邊界和傳輸大小對齊。即:字傳輸-A[1:0]=00,半字傳輸-A[0]=0
      5、判斷突發結束:監控HTRANS,如果產生一個非連續或者空閑傳輸那么表明一個新的突發已經開始那么前一次突發一定已經終止。
HBURST[2:0] 類型 描述
000 SINGLE 單一傳輸
001 INCR 未指定長度的增量突發
010 WRAP4 4拍回環突發
011 INCR4 4拍增量突發
100 WRAP8 8拍回環突發
101 INCR8 8拍增量突發
110 WRAP16 16拍回環突發
111 INCR16 16拍增量突發

Slave
(1)HRDATA[31:0]:讀數據總線,從Slave指向Master
(2)HREADY:為高時表示傳輸完成,在擴展傳輸時可能被拉低
(3)HRESP[1:0]:傳輸響應,00-OKAY,01-ERROR,10-RETRY,11-SPLIT

AHB-Lite總線時序

無等待基本讀傳輸

有等待基本讀傳輸

無等待基本寫傳輸

有等待基本寫傳輸

AHB上掛載LED模塊示例

module AHB2LED(
	//AHBLITE INTERFACE
		//Slave Select Signals
			input wire HSEL,
		//Global Signal
			input wire HCLK,
			input wire HRESETn,
		//Address, Control & Write Data
			input wire HREADY,
			input wire [31:0] HADDR,
			input wire [1:0] HTRANS,
			input wire HWRITE,
			input wire [2:0] HSIZE,
			
			input wire [31:0] HWDATA,
		// Transfer Response & Read Data
			output wire HREADYOUT,
			output wire [31:0] HRDATA,
		//LED Output
			output wire [7:0] LED
);


//Address Phase Sampling Registers
  reg rHSEL;
  reg [31:0] rHADDR;
  reg [1:0] rHTRANS;
  reg rHWRITE;
  reg [2:0] rHSIZE;

  reg [7:0] rLED;
 
//Address Phase Sampling
  always @(posedge HCLK or negedge HRESETn)
  begin
	 if(!HRESETn)
	 begin
		rHSEL	<= 1'b0;
		rHADDR	<= 32'h0;
		rHTRANS	<= 2'b00;
		rHWRITE	<= 1'b0;
		rHSIZE	<= 3'b000;
	 end
    else if(HREADY)
    begin
                rHSEL	<= HSEL;
		rHADDR	<= HADDR;
		rHTRANS	<= HTRANS;
		rHWRITE	<= HWRITE;
		rHSIZE	<= HSIZE;
    end
  end

//Data Phase data transfer
  always @(posedge HCLK or negedge HRESETn)
  begin
    if(!HRESETn)
      rLED <= 8'hFF;
    else if(rHSEL & rHWRITE & rHTRANS[1])
      rLED <= HWDATA[7:0];
  end

//Transfer Response
  assign HREADYOUT = 1'b1; //Single cycle Write & Read. Zero Wait state operations

//Read Data  
  assign HRDATA = {24'h0000_00,rLED};

  assign LED = rLED;

endmodule


AHB上掛載存儲模塊示例

359	module AHB2MEM
360	   #(parameter MEMWIDTH = 15)               // Size = 32KB
361	   (
362	   input wire           HSEL,
363	   input wire           HCLK,
364	   input wire           HRESETn,
365	   input wire           HREADY,
366	   input wire    [31:0] HADDR,
367	   input wire     [1:0] HTRANS,
368	   input wire           HWRITE,
369	   input wire     [2:0] HSIZE,
370	   input wire    [31:0] HWDATA,
371	   output wire          HREADYOUT,
372	   output reg    [31:0] HRDATA
373	   );
374	
375	   assign HREADYOUT = 1'b1; // Always ready
376	
377	   // Memory Array
378	   reg  [31:0] memory[0:(2**(MEMWIDTH-2)-1)];
379	
380	   // Registers to store Adress Phase Signals
381	   reg  [31:0] hwdata_mask;
382	   reg         we;
383	   reg  [31:0] buf_hwaddr;
384	
385	   // Sample the Address Phase   
386	   always @(posedge HCLK or negedge HRESETn)
387	   begin
388	      if(!HRESETn)
389	      begin
390	         we <= 1'b0;
391	         buf_hwaddr <= 32'h0;
392	      end
393	      else
394	         if(HREADY)
395	         begin
396	            we <= HSEL & HWRITE & HTRANS[1];
397	            buf_hwaddr <= HADDR;
398	   
399	            casez (HSIZE[1:0])
400	               2'b1?: hwdata_mask <=  32'hFFFFFFFF;                        // Word write
401	               2'b01: hwdata_mask <= (32'h0000FFFF << (16 * HADDR[1]));    // Halfword write
402	               2'b00: hwdata_mask <= (32'h000000FF << (8 * HADDR[1:0]));   // Byte write
403	            endcase
404	          end
405	   end
406	   
407	   // Read and Write Memory
408	   always @ (posedge HCLK)
409	   begin
410	      if(we)
411	         memory[buf_hwaddr[MEMWIDTH:2]] <= (HWDATA & hwdata_mask) | (HRDATA & ~hwdata_mask);
412	      HRDATA = memory[HADDR[MEMWIDTH:2]];
413	   end
414	
415	endmodule

APB

典型AMBA系統中的APB

主要特點
1、一種優化的,低功耗的,精簡接口總線,可以技術多種不同慢速外設;
2、主要應用在低帶寬的外設上,如UART、 I2C,它的架構不像AHB總線是多主設備的架構,APB總線的唯一主設備是APB橋(與AXI或APB相連),因此不需要仲裁一些Request/grant信號
3、固定兩個時鍾周期完成一次讀或寫的操作。其特性包括:兩個時鍾周期傳輸,無需等待周期和回應信號,控制邏輯簡單,只有四個控制信號(PSEL, PENABLE, PADDR, PWRITE)。

狀態圖

基本寫傳輸和讀傳輸

APB橋

接口框圖

主要功能

仲裁器

仲裁算法

1、仲裁算法有固定優先級的仲裁(Fixed priority),循環式優先級仲裁(Round Robin),或是隨機性的仲裁(Random)和競爭仲裁優先級(Tournament)
2、固定優先級算法,就是指總線中各主設備的優先級是事先確定好的,在仲裁器仲裁過程中固定不變。
3、而循環優先級算法則不同,各主設備的優先級在仲裁器的仲裁過程中不是一成不變,而是根據一定規律發生變化的。
4、兩者各有利弊,采用固定優先級算法,可以對那些有重要數據傳輸或有大量實時數據傳輸以及經常需要占用總線的主設備賦予較高的優先權,以便有效地利用AHB總線。固定優先級算法的缺點是可能會出現總線主設備“撐死”和“餓死”的現象,即優先級高的主設備總是優於優先級低的主設備獲得總線的訪問權,從而導致優先級低的設備不能及時獲得總線的訪問權而造成數據發送堵塞。相反,采用循環優先級算法則可以克服這種“飽餓”不均的弊端,在循環優先級算法中,由於其優先級隨着每個總線周期動態地改變,各個設備在總線上的身份平等,獲得總線占用權的機會均等。所以,在一定意義上來說,優先級循環是最公平的算法。循環優先級的缺點是當處理某些設備的大批量實時數據時會造成效率下降。

verilog實現(循環優先級)

`timescale 1ns / 1ps

module bus_arbiter(
input clk,
input rstn,

input valid_a,
input valid_b,
input valid_c,

input [31:0] data_a,
input [31:0] data_b,
input [31:0] data_c,

output grant_a,
output grant_b,
output grant_c,

output valid,
output [31:0] data
    );

reg valid_reg;
reg [31:0] data_reg;
reg [2:0] grant;

assign {grant_a,grant_b,grant_c} = grant;
assign data = data_reg;
assign valid = valid_reg;

// 只要有一路valid則最終valid
always @(posedge clk or negedge rstn) begin
	if(!rstn) valid_reg <= 1'b0;
	else valid_reg <= valid_a | valid_b | valid_c;
end


// 循環優先級
always @(posedge clk or negedge rstn) begin
	if(!rstn) begin
		grant <= 3'b100;  // 初始化a獲得總線
	end
	else begin
		case(grant)
		3'b100: // a
			begin
				case({valid_a,valid_b,valid_c})
					3'b000: 
					begin
						grant <= 3'b100;
						data_reg <= data_a;
					end
					3'b001: 
					begin
						grant <= 3'b001;
						data_reg <= data_c;
					end
					3'b010: 
					begin
						grant <= 3'b010;
						data_reg <= data_b;
					end
					3'b011: 
					begin
						grant <= 3'b010;
						data_reg <= data_b;
					end
					3'b100: 
					begin
						grant <= 3'b100;
						data_reg <= data_a;
					end
					3'b101: 
					begin
						grant <= 3'b001;
						data_reg <= data_c;
					end
					3'b110: 
					begin
						grant <= 3'b010;
						data_reg <= data_b;
					end
					3'b111: 
					begin
						grant <= 3'b010;
						data_reg <= data_b;
					end
				endcase
			end
		3'b010: // b
			begin
				case({valid_a,valid_b,valid_c})
					3'b000: 
					begin
						grant <= 3'b010;
						data_reg <= data_b;
					end
					3'b001: 
					begin
						grant <= 3'b001;
						data_reg <= data_c;
					end
					3'b010: 
					begin
						grant <= 3'b010;
						data_reg <= data_b;
					end
					3'b011: 
					begin
						grant <= 3'b001;
						data_reg <= data_c;
					end
					3'b100: 
					begin
						grant <= 3'b100;
						data_reg <= data_a;
					end
					3'b101: 
					begin
						grant <= 3'b001;
						data_reg <= data_c;
					end
					3'b110: 
					begin
						grant <= 3'b100;
						data_reg <= data_a;
					end
					3'b111: 
					begin
						grant <= 3'b001;
						data_reg <= data_c;
					end
				endcase
			end
		3'b001: // c
			begin
				case({valid_a,valid_b,valid_c})
					3'b000: 
					begin
						grant <= 3'b001;
						data_reg <= data_c;
					end
					3'b001: 
					begin
						grant <= 3'b001;
						data_reg <= data_c;
					end
					3'b010: 
					begin
						grant <= 3'b010;
						data_reg <= data_b;
					end
					3'b011: 
					begin
						grant <= 3'b010;
						data_reg <= data_b;
					end
					3'b100: 
					begin
						grant <= 3'b100;
						data_reg <= data_a;
					end
					3'b101: 
					begin
						grant <= 3'b100;
						data_reg <= data_a;
					end
					3'b110: 
					begin
						grant <= 3'b100;
						data_reg <= data_a;
					end
					3'b111: 
					begin
						grant <= 3'b100;
						data_reg <= data_a;
					end
				endcase
			end
		default: grant <= 3'b100;
			
		endcase
		
	end

end


endmodule


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM