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