上篇文章給大家介紹了APB協(xié)議相關(guān)的知識(shí)點(diǎn),本篇文章通過一個(gè)實(shí)際的APB slave的設(shè)計(jì)幫助大家鞏固對(duì)APB的掌握。
APB slave設(shè)計(jì)Spec
其框圖如上圖所示,這里提一嘴,大家在做數(shù)字IC設(shè)計(jì)的時(shí)候,都應(yīng)該像這樣規(guī)劃好各個(gè)模塊的連接關(guān)系,確定好以后再寫代碼。該模塊是一個(gè)基于APB協(xié)議完成寄存器配置或讀取的設(shè)計(jì)實(shí)例。設(shè)計(jì)相對(duì)比較簡單,但不失為一個(gè)很好的學(xué)習(xí)資料。
上面APB相關(guān)的信號(hào)都介紹過,這里不再重復(fù)介紹,其中的ECOREVNUM的意思是ECO revision number,如果沒有用到ARM的ECO的話,將該信號(hào)固定為全0即可。
右邊這個(gè)slave_reg實(shí)際上就對(duì)應(yīng)我們自己設(shè)計(jì)的IP的寄存器配置部分。這一部分的接口是native interface,也就是沒有考慮通用性的原生接口。想要通過APB總線對(duì)其進(jìn)行配置,就需要通過slave_interface這個(gè)模塊進(jìn)行協(xié)議轉(zhuǎn)換,進(jìn)而完成APB協(xié)議的傳輸。我們經(jīng)常能夠看到的apb2reg模塊,實(shí)際上也是做了這件事。該APB slave有以下的特點(diǎn):
- 不支持反壓
- 不支持錯(cuò)誤傳輸
- 支持4個(gè)RW類型的寄存器
- 支持12個(gè)RO類型寄存器
- 支持字節(jié)選通信號(hào)
APB slave設(shè)計(jì)代碼
apb_slave_interface代碼
下面是slave_interface的關(guān)鍵代碼邏輯。我們對(duì)其進(jìn)行分析:- 首先由于不支持反壓和錯(cuò)誤傳輸,因此將pready固定為1,pslverr固定為0。
- APB傳輸進(jìn)來的paddr可以直接賦給addr,作為讀寫的地址。
- read_en需要在psel為1且pwrite為0的時(shí)候拉高。這實(shí)際上是希望在整個(gè)讀傳輸過程中都讓read_en信號(hào)有效。讀者可能就想問了,讀應(yīng)該對(duì)應(yīng)著兩個(gè)階段嗎?不需要判斷嗎?實(shí)際上讀的話,master那邊自己控制好就行了,對(duì)于slave而言完全可以在第一拍和第二拍都把rdata提供好,這個(gè)是沒有關(guān)系的。
- write_en則對(duì)應(yīng)著setup phase,實(shí)際上在這個(gè)場(chǎng)景中修改write_en的邏輯讓該信號(hào)對(duì)應(yīng)著access phase也是可以的,其它的信號(hào)直接賦值就可以,應(yīng)該很好理解。
// APB interface assign pready = 1'b1; //always ready. Can be customized to support waitstate if required. assign pslverr = 1'b0; //always OKAY. Can be customized to support error response if required. // register read and write signal assign addr = paddr; assign read_en = psel & (~pwrite); // assert for whole apb read transfer assign write_en = psel & (~penable) & pwrite; // assert for 1st cycle of write transfer // It is also possible to change the design to perform the write in the 2nd // APB cycle. E.g. // assign write_en = psel & penable & pwrite; // However, if the design generate waitstate, this expression will result // in write_en being asserted for multiple cycles. assign byte_strobe = pstrb; assign wdata = pwdata; assign prdata = rdata;
apb_slave_reg代碼
其關(guān)鍵邏輯如下所示,我們對(duì)其進(jìn)行分析:- 首先由于分為RW寄存器和RO寄存器。這里確定寫地址是否在規(guī)定區(qū)間,同時(shí)寫使能是否有效,以及byte_strobe信號(hào),來決定要不要寫,寫哪個(gè)字節(jié)。
- 讀的話就比較簡單了,當(dāng)讀使能有效,根據(jù)地址信號(hào)決定rdata。實(shí)際上這就是個(gè)MUX選擇邏輯。根據(jù)read_en加地址從多個(gè)寄存器的Q端選出某一個(gè)來。
// Address decoding for write operations
assign wr_sel[0] = ((addr[(ADDRWIDTH-1):2]==10'b0000000000)&(write_en)) ? 1'b1: 1'b0;
assign wr_sel[1] = ((addr[(ADDRWIDTH-1):2]==10'b0000000001)&(write_en)) ? 1'b1: 1'b0;
assign wr_sel[2] = ((addr[(ADDRWIDTH-1):2]==10'b0000000010)&(write_en)) ? 1'b1: 1'b0;
assign wr_sel[3] = ((addr[(ADDRWIDTH-1):2]==10'b0000000011)&(write_en)) ? 1'b1: 1'b0;
// register write, byte enable
// Data register: data0
always @(posedge pclk or negedge presetn)
begin
if (~presetn)
begin
data0 <= {32{1'b0}}; // Reset data 0 to 0x00000000
end
else if (wr_sel[0])
begin
if (byte_strobe[0])
data0[ 7: 0] <= wdata[ 7: 0];
if (byte_strobe[1])
data0[15: 8] <= wdata[15: 8];
if (byte_strobe[2])
data0[23:16] <= wdata[23:16];
if (byte_strobe[3])
data0[31:24] <= wdata[31:24];
end
end
// register read
always @ (read_en or addr or data0 or data1 or data2 or data3 or ecorevnum)
begin
case (read_en)
1'b1:
begin
if (addr[11:4] == 8'h00) begin
case(addr[3:2])
2'b00: rdata = data0;
2'b01: rdata = data1;
2'b10: rdata = data2;
2'b11: rdata = data3;
default: rdata = {32{1'bx}};
endcase
end
else if (addr[11:6] == 6'h3F) begin
case(addr[5:2])
// Peripheral IDs and Component IDs.
// AHB example slave has part number of 818
4'b0100: rdata = ARM_CMSDK_APB4_EG_SLAVE_PID4; // 0xFD0 : PID 4
4'b0101: rdata = ARM_CMSDK_APB4_EG_SLAVE_PID5; // 0xFD4 : PID 5
4'b0110: rdata = ARM_CMSDK_APB4_EG_SLAVE_PID6; // 0xFD8 : PID 6
4'b0111: rdata = ARM_CMSDK_APB4_EG_SLAVE_PID7; // 0xFDC : PID 7
4'b1000: rdata = ARM_CMSDK_APB4_EG_SLAVE_PID0; // 0xFE0 : PID 0 APB Example slave part number[7:0]
4'b1001: rdata = ARM_CMSDK_APB4_EG_SLAVE_PID1; // 0xFE4 : PID 1 [7:4] jep106_id_3_0. [3:0] part number [11:8]
4'b1010: rdata = ARM_CMSDK_APB4_EG_SLAVE_PID2; // 0xFE8 : PID 2 [7:4] revision, [3] jedec_used. [2:0] jep106_id_6_4
4'b1011: rdata ={ARM_CMSDK_APB4_EG_SLAVE_PID3[31:8], ecorevnum[3:0], 4'h0};
// 0xFEC : PID 3 [7:4] ECO rev number, [3:0] modification number
4'b1100: rdata = ARM_CMSDK_APB4_EG_SLAVE_CID0; // 0xFF0 : CID 0
4'b1101: rdata = ARM_CMSDK_APB4_EG_SLAVE_CID1; // 0xFF4 : CID 1 PrimeCell class
4'b1110: rdata = ARM_CMSDK_APB4_EG_SLAVE_CID2; // 0xFF8 : CID 2
4'b1111: rdata = ARM_CMSDK_APB4_EG_SLAVE_CID3; // 0xFFC : CID 3
// Note : Customer changing the design should modify
// - jep106 value (www.jedec.org)
// - part number (customer define)
// - Optional revision and modification number (e.g. rXpY)
4'b0000, 4'b0001,4'b0010,4'b0011: rdata = {32'h00000000}; // default
default: rdata = {32{1'bx}}; // x propagation
endcase
end
else begin
rdata = {32'h00000000}; // default
end
end
1'b0:
begin
rdata = {32{1'b0}};
end
default:
begin
rdata = {32{1'bx}};
end
endcase
end
APB slave mux設(shè)計(jì)
這里再給大家介紹一下APB slave mux的概念,如下圖所示,基于APB slave mux我們可以快速地將多個(gè)apb slave連接在上面。在實(shí)際的設(shè)計(jì)當(dāng)中都是采用這樣的方式,連接多個(gè)slave的。一般我們管這種模塊叫做interconnect,顧名思義,將不同的模塊連接起來。而APB的interconnect只能連接一個(gè)master,因此繼續(xù)管他叫interconnect感覺差了點(diǎn)意思。所以一般就叫它slave mux了。
其邏輯框圖如上圖所示,非常的簡單啊。就是一個(gè)master和多個(gè)slave,通過這個(gè)額外的DECODE4bit進(jìn)行16選1。其關(guān)鍵代碼如下所示- 根據(jù)PSEL是否有效以及DECODE4BIT的值,完成16選1,PSEL0~PSEL15有一個(gè)或者0個(gè)拉高。
-
PREADYm默認(rèn)為1,當(dāng)PSEL為1的時(shí)候,根據(jù)譯碼結(jié)果選擇相應(yīng)的PREADY信號(hào)(當(dāng)端口沒有使能的時(shí)候
en[x] == 0
, 對(duì)應(yīng)的PREADYx
信號(hào)不會(huì)被選擇)。 - PSLVERR和PRDATA,選中誰就取誰的。
assign PSEL0 = PSEL & dec[ 0] & en[ 0];
assign PSEL1 = PSEL & dec[ 1] & en[ 1];
assign PSEL2 = PSEL & dec[ 2] & en[ 2];
//省略3~15
assign PREADY = ~PSEL |
( dec[ 0] & (PREADY0 | ~en[ 0]) ) |
( dec[ 1] & (PREADY1 | ~en[ 1]) ) |
( dec[ 2] & (PREADY2 | ~en[ 2]) ) |
//省略3~15
assign PSLVERR = ( PSEL0 & PSLVERR0 ) |
( PSEL1 & PSLVERR1 ) |
( PSEL2 & PSLVERR2 ) |
//省略3~15
assign PRDATA = ( {32{PSEL0 }} & PRDATA0 ) |
( {32{PSEL1 }} & PRDATA1 ) |
( {32{PSEL2 }} & PRDATA2 ) |
//省略3~15
這套代碼的缺點(diǎn)或者說優(yōu)點(diǎn)是,它是用組合邏輯做的,邏輯非常的簡單。實(shí)際上就是多選1,一般來說APB的時(shí)鐘頻率很低,所以增加了一定的組合邏輯級(jí)數(shù)也不會(huì)出現(xiàn)時(shí)鐘違例。這樣做還可以節(jié)省一個(gè)時(shí)鐘周期,大家也可以用時(shí)序邏輯去做,思路是類似的。還有一個(gè)問題就是這個(gè)模塊沒有PENABLE信號(hào),這個(gè)其實(shí)挺致命,大家可以手動(dòng)加上,跟PSEL的邏輯基本是一模一樣的,非常簡單。
-
寄存器
+關(guān)注
關(guān)注
31文章
5294瀏覽量
119816 -
AMBA總線
+關(guān)注
關(guān)注
0文章
35瀏覽量
9524
原文標(biāo)題:深入理解AMBA總線 — APB slave設(shè)計(jì)
文章出處:【微信號(hào):IC修真院,微信公眾號(hào):IC修真院】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論