天天看點

AMBA總線(二) AHB總線

(一)AHB 總線的架構

總線周期:就是總線時鐘的頻率,對于AMBA AHB 或者APB 協定總線周期定義為從一個上升沿到臨界的上升沿的變化區間。

總線傳輸:AHB 總線傳輸是資料目标的讀寫操作,可能會持續一個或者多個總線周期,而總線的傳輸在收到從機的ready信号終止,總線位寬為8、16、32、64、128bits。

猝發傳輸:定義了一個或多個資料傳輸,由主線總機發起,在位址空間增加時,每次傳輸增加的步長,由總線傳輸的大小決定。

AMBA總線(二) AHB總線

(二)AHB總線特點

  • 高速總線,高性能
  • 流水線操作
  • 支援多個總線主裝置(最多16個)
  • 支援single、burst傳輸
  • 總線位寬8、16、32、64、128bits
  • 上升沿觸發

(三)AHB總線結構

AMBA總線(二) AHB總線

(1)AHB主裝置(master)

  • 初始化一次讀/寫操作
  • 某一時刻隻允許一個主裝置使用總線
  • uP、DMA、DSP、LCDC

    (2)AHB從裝置(slave)

  • 響應一次讀/寫操作
  • 外部存儲器控制器EMI、APB bridge

    (3)AHB仲裁器(arbiter)

    允許某一個主裝置控制總線(沒有定義仲裁算法)

    (4)AHB譯碼器

    通過位址譯碼來決定選擇哪一個從裝置

(四)AHB總線信号

AMBA總線(二) AHB總線
  • HCLK/HRESETn(時鐘與複位信号)
  • HSEL(指明目前被通路的從裝置,來自譯碼器)
  • HADDR[31:0] (32位系統位址總線)
  • HWDATA[31:0] (寫資料總線,從主裝置寫到從裝置)
  • HRDATA[31:0] (讀資料總線,從從裝置讀到主裝置)
  • HTRANS (傳輸的狀态有:NONSEQ、SEQ、IDLE、BUSY)
  • HSIZE(傳輸的資料寬度 8 、16 、32)
  • HBURST(傳輸的burst類型,single,incr4/8/16,wrap4/8/16)
  • HRESP(從裝置發給主裝置的總線傳輸狀态:OKAY、ERROR、RETRY、SPLIT)
  • HREADY(高-從裝置傳輸結束;低-從裝置需延遲傳輸周期)

(五)AHB基本傳輸

1、位址周期(位址與控制信号),隻有一個cycle

2、資料周期(讀周期/寫周期),由HREADY信号決定需要幾個cycle

(1)沒有等待的single transfer

AMBA總線(二) AHB總線

第一個周期的上升沿,主機将位址資訊和控制資訊發送到總線上

第二個周期的上升沿,從機采樣位址和控制信号,并将HREADY拉高;如果是寫操作,主機會在第二個周期的上升沿後寫入資料;如果是讀操作,從機會在HREADY信号拉高後将讀取的資料寫入總線。

第三個周期的上升沿,主機擷取HREADY高信号,如果是寫操作,表明從機已經接收資料;如果是讀操作,表明讀資料有效并接收。(HREADY在資料有效器件必須為高,并且儲存至第三個周期的上升沿之後)

(2)兩個等待周期的single transfer

AMBA總線(二) AHB總線

從機有時候存在太慢不能不處理的情況,需要插入等待狀态,HREADY信号早第二和第三周期拉低,需要主機等待兩個周期。如果是寫操作,主機需要在等待期間保持寫資料不變,直到本次傳輸完成;如果是讀操作,從機隻需在READY信号拉高後,給出資料即可。

(3)流水線AHB傳輸

AMBA總線(二) AHB總線

由于pipeline操作,盡管進行B的讀寫操作時,插入了一個等待狀态,但是傳遞三個資料總共用了5個周期。

由于AHB隻能将Address 與 Data 分開,是以在AHB 中流水線的深度是2,即總線上最多存在兩個未處理完成的transfer。

(4)burst傳輸

AMBA總線(二) AHB總線

突發資訊通過使用 HBURST[2:0]并且 8 種可能的類型在中定義如下:

(1)single transfer

(2)INCR 4-beat/8-beat/16-beat

(3)WRAP 4-beat/8-beat/16-beat

對于增量猝發,每一次傳輸位址都是前一次位址的增量

對于回環(wrap)猝發,如果傳輸的起始位址并未和位元組總數對齊,那麼傳輸位址将在邊界處回環。例如,一個4拍回環猝發的字(4位元組)通路将在16位元組邊界回環。是以位址将在16位元組處回環,如果起始位址為0x34,即0x3c之後的位址為0x30,那麼位址傳輸為0x34、0x38、0x3c、0x30;對于wrap8而言,位址将在32位元組邊界處回環,是以0x3c之後的位址如果起始位址為0x34,位址0x3c之後的位址是0x20,那麼位址傳輸為0x34,0x38、0x3c、0x20、0x24、0x28、0x2c、0x30.

注意:

burst傳輸不能穿越KB邊界,比如由0x000傳輸至0x400時,穿越KB邊界必須将猝發模式由SEQ轉為NSEQ,并繼續傳輸。這是由于slave的位址一般以KB分界,避免資料傳輸時發生錯誤

AMBA總線(二) AHB總線
AMBA總線(二) AHB總線

HTRANS[1:0] :

00:IDLE(主裝置占用總線,但沒有進行傳輸;兩次burst傳輸中間主裝置發送IDLE)

01:BUSY(主裝置占用總線,但是在burst傳輸過程中還沒有準備好進行下一次傳輸;一次burst傳輸中間主裝置發BUSY)

10:NONSEQ (表明一個單個資料的傳輸或者一個burst傳輸的第一個資料;其位址與控制信号與上一次傳輸無關)

11:SEQ(表明burst傳輸接下來的資料;位址與上一次傳輸的位址是相關的)

AMBA總線(二) AHB總線

其他控制信号:

HWRITE:高電平:寫;低電平:讀

HSIZE[2:0]:

000:8bits

001:16bits

010:32bits

011:64bits

100:128bits

101:256bits

110:512bits

111:1024bits

AMBA總線(二) AHB總線

注意:猝發大小表示猝發的節拍數量,并不是一次猝發傳輸的實際位元組數量。一次猝發資料總量可以用節拍數乘以每拍資料的位元組數來計算,每拍位元組數由HSIZE[2:0]确定,并且猝發傳輸必須将位址邊界與傳輸大小對齊。

由于猝發傳輸的大小受限->

下面是一個軟體(彙編)與硬體對應的圖:

AMBA總線(二) AHB總線

HRESP[1:0] 的編碼、傳輸響應信号和每個響應的描述如下:

AMBA總線(二) AHB總線

(五)仲裁信号

AMBA總線(二) AHB總線
  • HBUSREQ(總線請求 ,master發出)
  • HLOCKx(高電平:主裝置請求鎖定總線,master發出)
  • HGRANTx(指出主裝置x可通路總線,arbiter 發出;主裝置x控制總線,當HGRANTx=1且HREADY=1)
  • HMASTER[3:0](正在傳輸的主裝置)
  • HMASTLOCK(主裝置正在進行一次鎖定傳輸)
  • HSPLITx[15:0](從裝置用這個信号告訴仲裁器哪個主裝置允許重新嘗試一次split傳輸)

(1)無等待仲裁

AMBA總線(二) AHB總線

(2)有等待仲裁

AMBA總線(二) AHB總線

AHB主裝置端口

AMBA總線(二) AHB總線

AHB從裝置端口

AMBA總線(二) AHB總線

下面是AHB slave的RTL代碼:

module ahb_slave(
	input hclk,
	input hreset_n,
	input hselx,
	input [31:0] haddr,
	input hwrite,
	input [1:0] htrans,
	input [2:0] hsize,
	input [2:0] hburst,
	input [31:0] hwdata,
	output reg hready,
	output [1:0] hresp,
	output reg [31:0] hrdata);
reg hready1;
reg hready2;
reg hready3;
reg hready4;

wire [7:0] addr1= haddr[7:0];

reg [7:0] hrdata1;
reg [7:0] hrdata2;
reg [7:0] hrdata3;
reg [7:0] hrdata4;


parameter bits8 = 3'b000;
parameter bits16 = 3'b001;
parameter bits32 = 3'b010;
parameter bits64 = 3'b011;
parameter bits128 = 3'b100;
parameter bits256 = 3'b101;
parameter bits512 = 3'b110;
parameter bits1024 = 3'b111;

parameter single=3'b000;
parameter incr=3'b001;
parameter wrap4=3'b010;
parameter incr4=3'b011;
parameter wrap8=3'b100;
parameter incr8=3'b101;
parameter wrap16=3'b110;
parameter incr16=3'b111;

parameter okay=2'b00;
parameter error=2'b01;
parameter retry=2'b10;
parameter split=2'b11;

reg [31:0] data [256-1:0];
integer i;
//read and write


[email protected](posedge hclk or negedge hreset_n)
begin
	if(!hreset_n)
	begin
		for(i=0;i<=256-1;i=i+1)
		begin
			data[i]<=0;
		end
		hready<=1'b0;
		hrdata<=32'b0;
		hrdata1<=8'h0;
		hrdata2<=8'h0;
		hrdata3<=8'h0;
		hrdata4<=8'h0;
	end
	else 
	begin
		case(hburst)
		single:
		begin
			if(!hwrite&&hselx&&(htrans[1:0]==2'b10))
			begin
				hready<=1'b1;
				hready1<=hready;
				if(hready1==1)
				begin
					hrdata<={hrdata4,hrdata3,hrdata2,hrdata1};
					case(hsize)
					bits8:
					begin
						hrdata1<=data[addr1];
					end
					bits16:
					begin
						hrdata1<=data[addr1];
						hrdata2<=data[addr1+1];
							
					end
					bits32:
					begin
						hrdata1<=data[addr1];
						hrdata2<=data[addr1+1];
						hrdata3<=data[addr1+2];
						hrdata4<=data[addr1+3];
					end
					endcase
				end
			end
			else if(hwrite&&hselx&&(htrans[1:0]==2'b10))
			begin
				hready<=1'b1;
				hready1<=hready;
				if(hready1==1)
				begin
					case(hsize)
					bits8:
					begin
						data[addr1]<=hwdata[7:0];
					end
					bits16:
					begin
						data[addr1]<=hwdata[7:0];
						data[addr1+1]<=hwdata[15:8];
					end
					bits32:
					begin
						data[addr1]<=hwdata[7:0];
						data[addr1+1]<=hwdata[15:8];
						data[addr1+2]<=hwdata[23:16];
						data[addr1+3]<=hwdata[31:24];
					end
					endcase
				end
			end
		end
		incr4:
		begin
			if(!hwrite&&hselx&&(htrans[1:0]==2'b10))
			begin
				hready<=1;
				hready1<=hready;
				hready2<=hready1;
				hready3<=hready2;
				hready4<=hready3;
				case(hsize)
					bits32:
					begin
						if(hready1==1)
							hrdata<=data[addr1];
						else if(hready2==1)
							hrdata<=data[addr1+4];
						else if(hready3==1)
							hrdata<=data[addr1+8];
						else if(hready4==1)
							hrdata<=data[addr1+12];
					end
				endcase
			end
			else if(hwrite&&hselx&&(htrans[1:0]==2'b10))
			begin
				hready<=1;
				hready1<=hready;
				hready2<=hready1;
				hready3<=hready2;
				hready4<=hready3;
				case(hsize)
					bits32:
					begin
						if(hready1==1)
							data[addr1]<=hwdata;
						else if(hready2==1)
							data[addr1+4]<=hwdata;
						else if(hready3==1)
							data[addr1+8]<=hwdata;
						else if(hready4==1)
							data[addr1+12]<=hwdata;
					end
				endcase
			end
		end
		wrap4:
		begin
			if(!hwrite&&hselx&&(htrans[1:0]==2'b10))
			begin
				hready<=1;
				hready1<=hready;
				hready2<=hready1;
				hready3<=hready2;
				hready4<=hready3;
				case(hsize)
				bits32:
				begin
					if(hready1==1)
					begin
					case(addr1[3:0])
					4'h0:
						begin
						if(hready1==1)
							hrdata<=data[addr1];
						else if(hready2==1)
							hrdata<=data[addr1+4];
						else if(hready3==1)
							hrdata<=data[addr1+8];
						else if(hready4==1)
							hrdata<=data[addr1+12];
						end
					4'h4:
						begin
						if(hready1==1)
							hrdata<=data[addr1];
						else if(hready2==1)
							hrdata<=data[addr1+4];
						else if(hready3==1)
							hrdata<=data[addr1+8];
						else if(hready4==1)
							hrdata<=data[addr1-4];
						end
					4'h8:
						begin					
						if(hready1==1)
							hrdata<=data[addr1];
						else if(hready2==1)
							hrdata<=data[addr1+4];
						else if(hready3==1)
							hrdata<=data[addr1-8];
						else if(hready4==1)
							hrdata<=data[addr1-4];
						end
					4'hc:
						begin
						if(hready1==1)
							hrdata<=data[addr1];
						else if(hready2==1)
							hrdata<=data[addr1-12];
						else if(hready3==1)
							hrdata<=data[addr1-8];
						else if(hready4==1)
							hrdata<=data[addr1-4];
						end
					endcase
					end
				end
				endcase
			end
			else if(hwrite&&hselx&&(htrans[1:0]==2'b10))
			begin
				hready<=1;
				hready1<=hready;
				hready2<=hready1;
				hready3<=hready2;
				hready4<=hready3;
				case(hsize)
				bits32:
				begin
					if(hready1==1)
					begin
					case(addr1[3:0])
					4'h0:
						begin
						if(hready1==1)
							data[addr1]<=hwdata;
						else if(hready2==1)
							data[addr1+4]<=hwdata;
						else if(hready3==1)
							data[addr1+8]<=hwdata;
						else if(hready4==1)
							data[addr1+12]<=hwdata;
						end
					4'h4:
						begin
						if(hready1==1)
							data[addr1]<=hwdata;
						else if(hready2==1)
							data[addr1+4]<=hwdata;
						else if(hready3==1)
							data[addr1+8]<=hwdata;
						else if(hready4==1)
							data[addr1-4]<=hwdata;
						end
					4'h8:
						begin					
						if(hready1==1)
							data[addr1]<=hwdata;
						else if(hready2==1)
							data[addr1+4]<=hwdata;
						else if(hready3==1)
							data[addr1-8]<=hwdata;
						else if(hready4==1)
							data[addr1-4]<=hwdata;
						end
					4'hc:
						begin
						if(hready1==1)
							data[addr1]<=hwdata;
						else if(hready2==1)
							data[addr1-12]<=hwdata;
						else if(hready3==1)
							data[addr1-8]<=hwdata;
						else if(hready4==1)
							data[addr1-4]<=hwdata;
						end
					endcase
					end
				end
				endcase	
			end
		end
		endcase
	end
end
endmodule										
           
module tb();
reg hclk;
reg hreset_n;
reg hselx;
reg [31:0] haddr;
reg hwrite;
reg [1:0] htrans;
reg [2:0] hsize;
reg [2:0] hburst;
reg [31:0] hwdata;
wire hready;
wire [31:0] hrdata;

ahb_slave u1(
	.hclk(hclk),
	.hreset_n(hreset_n),
	.hselx(hselx),
	.haddr(haddr),
	.hwrite(hwrite),
	.htrans(htrans),
	.hsize(hsize),
	.hburst(hburst),
	.hwdata(hwdata),
	.hready(hready),
	.hresp(),
	.hrdata(hrdata));
initial
begin
	hclk=0;
	forever #(20/2) hclk=~hclk;
end

initial
begin
	hreset_n=0;
	#(60) hreset_n=1;
	hwrite=1;
	hselx=1;
	haddr=32'h45684120;
	hsize=3'b010;
	hburst=3'b000;
	htrans=2'b10;
	#(20);
	hwdata=32'h123045;
	#(40);
	hwrite=1;
	hselx=1;
	haddr=32'h45684124;
	hsize=3'b010;
	hburst=3'b010;
	htrans=2'b10;
	#(20);
	hwdata=32'h546123;
	#(20);
	hwdata=32'h123456;
	#(20);
	hwdata=32'h11111111;
	#(20);
	hwdata=32'h22222222;
	#(100);
	hwrite=0;
	hselx=1;
	haddr=32'h45684120;
	hsize=3'b010;
	hburst=3'b000;
	htrans=2'b10;
	#(40);
	hwrite=0;
	hselx=1;
	haddr=32'h45684124;
	hsize=3'b010;
	hburst=3'b010;
	htrans=2'b10;
end
endmodule
           
AMBA總線(二) AHB總線