(一)AHB 總線的架構
總線周期:就是總線時鐘的頻率,對于AMBA AHB 或者APB 協定總線周期定義為從一個上升沿到臨界的上升沿的變化區間。
總線傳輸:AHB 總線傳輸是資料目标的讀寫操作,可能會持續一個或者多個總線周期,而總線的傳輸在收到從機的ready信号終止,總線位寬為8、16、32、64、128bits。
猝發傳輸:定義了一個或多個資料傳輸,由主線總機發起,在位址空間增加時,每次傳輸增加的步長,由總線傳輸的大小決定。
(二)AHB總線特點
- 高速總線,高性能
- 流水線操作
- 支援多個總線主裝置(最多16個)
- 支援single、burst傳輸
- 總線位寬8、16、32、64、128bits
- 上升沿觸發
(三)AHB總線結構
(1)AHB主裝置(master)
- 初始化一次讀/寫操作
- 某一時刻隻允許一個主裝置使用總線
-
uP、DMA、DSP、LCDC
(2)AHB從裝置(slave)
- 響應一次讀/寫操作
-
外部存儲器控制器EMI、APB bridge
(3)AHB仲裁器(arbiter)
允許某一個主裝置控制總線(沒有定義仲裁算法)
(4)AHB譯碼器
通過位址譯碼來決定選擇哪一個從裝置
(四)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
第一個周期的上升沿,主機将位址資訊和控制資訊發送到總線上
第二個周期的上升沿,從機采樣位址和控制信号,并将HREADY拉高;如果是寫操作,主機會在第二個周期的上升沿後寫入資料;如果是讀操作,從機會在HREADY信号拉高後将讀取的資料寫入總線。
第三個周期的上升沿,主機擷取HREADY高信号,如果是寫操作,表明從機已經接收資料;如果是讀操作,表明讀資料有效并接收。(HREADY在資料有效器件必須為高,并且儲存至第三個周期的上升沿之後)
(2)兩個等待周期的single transfer
從機有時候存在太慢不能不處理的情況,需要插入等待狀态,HREADY信号早第二和第三周期拉低,需要主機等待兩個周期。如果是寫操作,主機需要在等待期間保持寫資料不變,直到本次傳輸完成;如果是讀操作,從機隻需在READY信号拉高後,給出資料即可。
(3)流水線AHB傳輸
由于pipeline操作,盡管進行B的讀寫操作時,插入了一個等待狀态,但是傳遞三個資料總共用了5個周期。
由于AHB隻能将Address 與 Data 分開,是以在AHB 中流水線的深度是2,即總線上最多存在兩個未處理完成的transfer。
(4)burst傳輸
突發資訊通過使用 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分界,避免資料傳輸時發生錯誤
HTRANS[1:0] :
00:IDLE(主裝置占用總線,但沒有進行傳輸;兩次burst傳輸中間主裝置發送IDLE)
01:BUSY(主裝置占用總線,但是在burst傳輸過程中還沒有準備好進行下一次傳輸;一次burst傳輸中間主裝置發BUSY)
10:NONSEQ (表明一個單個資料的傳輸或者一個burst傳輸的第一個資料;其位址與控制信号與上一次傳輸無關)
11:SEQ(表明burst傳輸接下來的資料;位址與上一次傳輸的位址是相關的)
其他控制信号:
HWRITE:高電平:寫;低電平:讀
HSIZE[2:0]:
000:8bits
001:16bits
010:32bits
011:64bits
100:128bits
101:256bits
110:512bits
111:1024bits
注意:猝發大小表示猝發的節拍數量,并不是一次猝發傳輸的實際位元組數量。一次猝發資料總量可以用節拍數乘以每拍資料的位元組數來計算,每拍位元組數由HSIZE[2:0]确定,并且猝發傳輸必須将位址邊界與傳輸大小對齊。
由于猝發傳輸的大小受限->
下面是一個軟體(彙編)與硬體對應的圖:
HRESP[1:0] 的編碼、傳輸響應信号和每個響應的描述如下:
(五)仲裁信号
- HBUSREQ(總線請求 ,master發出)
- HLOCKx(高電平:主裝置請求鎖定總線,master發出)
- HGRANTx(指出主裝置x可通路總線,arbiter 發出;主裝置x控制總線,當HGRANTx=1且HREADY=1)
- HMASTER[3:0](正在傳輸的主裝置)
- HMASTLOCK(主裝置正在進行一次鎖定傳輸)
- HSPLITx[15:0](從裝置用這個信号告訴仲裁器哪個主裝置允許重新嘗試一次split傳輸)
(1)無等待仲裁
(2)有等待仲裁
AHB主裝置端口
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