一、AHB總線學習
1. AHB總線結構
如圖所示,AHB總線系統(tǒng)利用中央多路選擇機制實現(xiàn)主機與從機的互聯(lián)問題。從圖中可以看出,AHB總線結構主要可分為三部分:主機、從機、控制部分??刂撇糠钟芍俨闷?、數(shù)據(jù)多路選擇、地址和數(shù)據(jù)多路選擇及地址譯碼器組成。主機首先需要向仲裁器提出使用總線的請求hbusreq信號,仲裁器通過仲裁(多主機使用總線的優(yōu)先級)授權(hgrant)給某一主機(注意:一個周期內只能有一個主機接入總線),此時,主機就可以開始進行AHB傳輸了。主機首先發(fā)出地址和控制信號。這些信號主要提供地址信息、傳輸方向、帶寬及burst類型(burst傳輸并非本文重點,故不作討論)。由于AHB總線統(tǒng)一給每個從機分配地址,譯碼器可以根據(jù)主機發(fā)出的地址選擇哪個主機與從機進行互聯(lián)。
2、AHB總線基本傳輸
AHB總線的一次傳輸主要由兩部分組成:地址段(開始傳輸?shù)牡谝粋€周期)和數(shù)據(jù)段(傳輸開始后的周期)。在hclk上升沿來臨時,獲得授權的主機驅動地址和控制信號到AHB總線上,在hclk下一周期的上升沿時,slave開始采樣地址和控制信息。獲取地址和控制信息的slave會返回hresp(回應信號)給master,而在hclk的第三個時鐘上升沿hresp被master采樣,與此同時,master與slave間完成數(shù)據(jù)的第一次讀寫操作。
在進行數(shù)據(jù)傳輸時,若從機沒有準備好接收下一個數(shù)據(jù)iketongg將hready信號拉低來插入一個空閑周期,等下一周期hready重新為高時再接收數(shù)據(jù)。主機在當前周期發(fā)送完部分數(shù)據(jù),而在下一周期沒有準備好發(fā)后面的數(shù)據(jù),可通過加入BUSY狀態(tài)來延緩傳輸。
二、基于AHB總線的讀寫設計
1、輸入輸出接口
在設計某個模塊時,首先需要理清它有哪些輸入輸出,從而對設計進行一個整體了解。由于本文的讀寫模塊設計屬于比較基礎的AHB傳輸,不涉及突發(fā)傳輸、鎖定傳輸和從機的分塊傳輸。本設計的輸入有:hclk_i、irst_n、hgrant_i、hrdata_i、hready_i,輸出有:hwdata_o、htrans_o、hwrite_o、haddr_o、hbusreq_o。
1、狀態(tài)機設計
狀態(tài)機的設計比較重要,本設計的主狀態(tài)機是:空閑狀態(tài)、讀狀態(tài)、寫狀態(tài),從狀態(tài)機分為讀狀態(tài)機(rd_fsm_r)和寫狀態(tài)機(wr_fsm_r),讀狀態(tài)機和寫狀態(tài)機的狀態(tài)轉移圖如圖所示。
根據(jù)AHB總線地址段和數(shù)據(jù)段的特性,可將其分為:空閑狀態(tài)、請求總線狀態(tài)、地址段狀態(tài)、讀/寫數(shù)據(jù)狀態(tài)和讀/寫最后一個字節(jié)狀態(tài)。注意:在狀態(tài)機中,何時有效很重要,從圖中可以看出,各狀態(tài)的觸發(fā)條件都有hready_i信號(由于hready_i信號是一直在變化的,可能前一個狀態(tài)hready_i信號為高,但后一個狀態(tài)會變低,不能使用軟件思維去思考。),其次,何時開始讀/寫數(shù)據(jù),何時數(shù)據(jù)讀/寫完成,這都是由計數(shù)器計數(shù)來決定的。
2、設計時序圖
讀寫過程比較類似,時序圖如圖所示:
從圖中可以看出,地址與數(shù)據(jù)并非在同一周期(AHB總線的特性)。當前周期的地址,存儲的數(shù)據(jù)在下一周期才會出現(xiàn)。這種地址和數(shù)據(jù)交疊出現(xiàn)使總線能進行高性能操作的同時,給從機也提供了足夠的時間來響應傳輸。
3、基本代碼
(1)狀態(tài)機邏輯
- module ahb_test(hbusreq_o,haddr_o,htrans_o,hwdata_o,hwrite_o,
- hclk_i,irst_n,hgrant_i,hready_i,hrdata_i,we_i,re_i);
-
- input hclk_i,irst_n,we_i,re_i,hgrant_i,hready_i;
- input [:] hrdata_i;
- output hbusreq_o,hwrite_o;
- output [:] hwdata_o;
- output [:] htrans_o;
- output [:] haddr_o;
-
- reg [:] main_fsm_r;
- reg [:] rd_fsm_r;
- reg [:] wr_fsm_r;
- reg [: haddr_r;
- reg [:] rd_cnt_r;
- reg [:] wr_cnt_r;
-
- parameter data_size = ; //讀寫4個字節(jié)數(shù)據(jù)
- parameter rd_base_addr = 'h1A00;
- parameter wr_base_addr = 'h1B00;
-
- //the status of main fsm
- parameter S0 = 'd0;
- parameter S1 = 'd1;
- parameter S2 = 'd2;
-
- //the status of read fsm
- parameter RD_IDLE = 'b000;
- parameter RD_BUSREQ = 'b001;
- parameter RD_ADDR = 'b010;
- parameter RD_RD = 'b011;
- parameter RD_LRD = 'b100;
-
- wire fsm_rd_idle = rd_fsm_r == RD_IDLE;
- wire fsm_rd_busreq = rd_fsm_r == RD_BUSREQ;
- wire fsm_rd_addr = rd_fsm_r ==RD_ADDR;
- wire fsm_rd_rd = rd_fsm_r == RD_RD;
- wire fsm_rd_lrd = rd_fsm_r === RD_LRD;
- wire rd_last_data = rd_cnt_r == data_size - 'd1;
-
- //the status of write fsm
- parameter WR_IDLE = 'b000;
- parameter WR_BUSREQ = 'b001;
- parameter WR_ADDR = 'b010;
- parameter WR_WD = 'b011;
- parameter WR_LWD = 'b100;
-
- wire fsm_wr_idle = wr_fsm_r == WR_IDLE;
- wire fsm_wr_busreq = wr_fsm_r == WR_BUSREQ;
- wire fsm_wr_addr = wr_fsm_r ==WR_ADDR;
- wire fsm_wr_wd = wr_fsm_r == WR_WD;
- wire fsm_wr_lwd = wr_fsm_r === WR_LWD;
- wire wr_last_data = wr_cnt_r == data_size - 'd1;
-
- //Main FSM
- wire rd_done;
- wire wr_done;
- reg we_r,re_r;
- reg [:] main_fsm_r;
-
- always @(posedge hclk_i)
- if(~irst_n)
- main_fsm_r <=S0;
- else
- case(main_fsm_r)
- S0: if(we_r | re_r)
- main_fsm_r <= S1;
- S1: if(rd_done)
- main_fsm_r <=S2;
- S2: if(wr_done)
- main_fsm_r <=S0;
- default:
- main_fsm_r <= S0;
- endcase
-
- //Sub Read FSM
- always @(posedge hclk_i)
- if(~irst_n)
- rd_fsm_r <= RD_IDLE;
- else
- case(rd_fsm_r)
- RD_IDLE : if((we_r | re_r) | (rd_done))
- rd_fsm_r <= RD_BUSREQ;
- RD_BUSREQ : if(hgrant_i & hready_i)
- rd_fsm_r <= RD_ADDR;
- RD_ADDR : if(hready_i)
- rd_fsm_r <= RD_RD;
- RD_RD : if(rd_cnt_r == data_size- & hready_i)
- rd_fsm_r <= RD_LRD;
- RD_LRD : if(hready_i & rd_last_data)
- rd_fsm_r <= RD_IDLE;
- default:
- rd_fsm_r <= RD_IDLE;
- endcase
-
- //Sub Write FSM
- always @(posedge hclk_i)
- if(~irst_n)
- wr_fsm_r <= WR_IDLE;
- else
- case(wr_fsm_r)
- WR_IDLE : if(rd_done)
- wr_fsm_r <= WR_BUSREQ;
- WR_BUSREQ : if(hgrant_i & hready_i)
- wr_fsm_r <= WR_ADDR;
- WR_ADDR : if(hready_i)
- wr_fsm_r <= WR_WD;
- WR_WD : if(wr_cnt_r == data_size- & hready_i)
- wr_fsm_r <= WR_LWD;
- WR_LWD : if(hready_i & wr_last_data)
- wr_fsm_r <= WR_IDLE;
- default:
- wr_fsm_r <= WR_IDLE;
- endcase
(2)寄存器邏輯
- //we_r
- always @(posedge hclk_i)
- if(~irst_n | we_r)
- we_r <= 'b0;
- else(we_i)
- we_r <='b1;
-
- //re_r
- always @(posedge hclk_i)
- if(~irst_n | re_r)
- re_r <= 'b0;
- else(re_i)
- re_r <='b1;
-
- assign rd_done = main_fsm_r == S1 & hready_i & rd_last_data;
-
- assign wr_done = main_fsm_r == S2 & hready_i & wr_last_data;
-
- assign hwrite_o = (main_fsm_r == S2) ? 'd1 : 'd0;
-
- assign hbusreq_o = (fsm_rd_busreq || fsm_wr_busreq) ? 'd1 : 'd0;
-
- //rd_done_r
- always @(posedge hclk_i)
- if(~irst_n || rd_done_r)
- rd_done_r <= 'd0;
- else if(rd_done)
- rd_done_r <= 'd1;
-
- //wr_done_r
- always @(posedge hclk_i)
- if(~irst_n || wr_done_r)
- wr_done_r <= 'd0;
- else if(wr_done)
- wr_done_r <= 'd1;
-
- assign htrans_o = (fsm_rd_addr || fsm_wr_addr) ? 'b10 : 2'b11;
- wire addr_add_en = (main_fsm_r == S1 || main_fsm_r == S2) &&
- (fsm_rd_addr || fsm_rd_rd || fsm_wr_addr || fsm_wr_wd);
-
- //haddr_r
- always @(posedge hclk_i)
- if(~irst_n)
- haddr_r <= 'd0;
- else if(main_fsm_r == S1 & fsm_rd_busreq & hready_i)
- haddr_r <= rd_base_addr;
- else if(main_fsm_r == S2 & fsm_wr_busreq & hready_i)
- haddr_r <= wr_base_addr;
- else if(addr_add_en)
- haddr_r <= haddr_r + 'd4;
-
- //rd_cnt_r
- always @(posedge hclk_i)
- if (~irst_n)
- rd_cnt_r <= 'd0;
- else if (hready_i & fsm_rd_addr)
- rd_cnt_r <= 'd0;
- else if (hready_i & fsm_rd_rd)
- rd_cnt_r <= rd_cnt_r + 'd1;
- else if (hready_i & rd_last_data)
- rd_cnt_r <= 'd0;
-
- //wr_cnt_r
- always @(posedge hclk_i)
- if (~irst_n)
- wr_cnt_r <= 'd0;
- else if (hready_i & fsm_wr_addr)
- wr_cnt_r <= 'd0;
- else if (hready_i & fsm_wr_wd)
- wr_cnt_r <= wr_cnt_r + 'd1;
- else if (hready_i & wr_last_data)
- wr_cnt_r <= 'd0;
-
- reg [:] rd_data_r [ : data_size-];
- //rd_data_r
- always @(posedge hclk_i)
- if(~irst_n)
- {rd_data_r[],rd_data_r[],rd_data_r[],rd_data_r[]} <= 'd0;
- else if(main_fsm_r == S1 & (fsm_rd_rd || fsm_rd_lrd) & hready_i)
- rd_data_r <= hrdata_i;
-
- assign hwdata_o = (main_fsm_r == S2 & (fsm_wr_wd || fsm_wr_lwd) & hready_i) ? rd_data_r[wr_cnt_r] : 'b0;
- assign haddr_o = haddr_r;
-
- endmodule
至此,本文基于AHB總線的master讀寫設計就完成了。在設計過程中,重要的是畫出狀態(tài)機,并理解每個狀態(tài)的邏輯及狀態(tài)與狀態(tài)間跳轉的觸發(fā)條件。需要理解阻塞賦值和非阻塞賦值。在這里說一下我對阻塞賦值和非阻塞賦值的理解:
(1)非阻塞賦值(需要使用寄存器將值存儲起來,使用always塊賦值):當前周期時鐘上升沿時存儲值,下一周期時鐘上升沿才會進行賦值操作。(和下一周期的時序也有關系)。使用非阻塞賦值,各個賦值語句在塊結束后(下一周期)同步賦值。
(2)阻塞賦值(組合邏輯,assign賦值):當前周期時鐘上升沿賦值生效,不存儲值。使用assign能實時給wire型信號賦值。(在當前周期完成操作)。阻塞語句是順序執(zhí)行的。在當前周期,前一個賦值語句執(zhí)行完才能執(zhí)行下一個賦值語句,即前一賦值語句的結果能影響下一賦值語句的值。
模塊輸入輸出一般都是wire型,內部邏輯可以是wire也可以是reg,一般先對一些內部邏輯信號進行各種操作,最后再將其賦值給輸出信號。如本文assign haddr_o = haddr_r;中間對haddr_r進行操作,最后將其賦值給haddr_o。
- AHB總線協(xié)議
https://blog.t/linton1/article/details/79649249 1. 簡介 AHB(Advanced High Performance Bus)總線規(guī)范是 ...
- SOA實踐之基于服務總線的設計
在上文中,主要介紹了SOA的概念,什么叫做“服務”,“服務”應該具備哪些特性.本篇中,我將介紹SOA的一種很常見的設計實踐--基于服務總線的設計. 基于服務總線的設計 基于總線的設計,借鑒了計算機內部 ...
- AHB總線和APB總線
AHB主要用于高性能模塊(如CPU.DMA和DSP等)之間的連接,作為SoC的片上系統(tǒng)總線,它包括以下一些特性:單個時鐘邊沿操作:非三態(tài)的實現(xiàn)方式:支持突發(fā)傳輸:支持分段傳輸:支持多個主控制器:可配置 ...
- 基于FPGA的XPT2046觸摸控制器設計
基于FPGA的XPT2046觸摸控制器設計 小梅哥編寫,未經(jīng)許可,文章內容和所涉及代碼不得用于其他商業(yè)銷售的板卡 本實例所涉及代碼均可通過向 xiaomeige_fpga@foxmail.com 發(fā) ...
- AHB 總線問答(轉)
AHB總線問答 http://blog.163.com/huanhuan_hdu/blog/static/1352981182011625916845/ 仲裁:主設備可以在一個突發(fā)傳輸中解除HLOCK ...
- 基于 EntityFramework 的數(shù)據(jù)庫主從讀寫分離架構(1) - 原理概述和基本功能實現(xiàn)
回到目錄,完整代碼請查看(https://github.com/cjw0511/NDF.Infrastructure)中的目錄: src\ NDF.Data.EntityFramew ...
- 基于ZigBee的家居控制系統(tǒng)的設計與應用
基于ZigBee的家居控制系統(tǒng)的設計與應用 PPT簡介:http://pan.baidu.com/s/1i38PC6D 摘 要 智能家居是未來家居的發(fā)展方向,其利用先進的網(wǎng)絡技術.計算機技術和無線通 ...
- 基于SMB協(xié)議的共享文件讀寫 博客分類: Java
基于SMB協(xié)議的共享文件讀寫 博客分類: Java 一.SMB協(xié)議 SMB協(xié)議是基于TCP-NETBIOS下的,一般端口使用為139,445. 服務器信息塊(SMB)協(xié)議是一種IBM協(xié)議,用于在計 ...
- 1.3 PCI總線的存儲器讀寫總線事務
總線的基本任務是實現(xiàn)數(shù)據(jù)傳送,將一組數(shù)據(jù)從一個設備傳送到另一個設備,當然總線也可以將一個設備的數(shù)據(jù)廣播到多個設備.在處理器系統(tǒng)中,這些數(shù)據(jù)傳送都要依賴一定的規(guī)則,PCI總線并不例外. PCI總線使用單 ...
隨機推薦
- Cannot create PoolableConnectionFactory (null, message from server: "Host 'admin-PC' is not allowed to connect to this MySQL server")
1.別人在用自己的tomcat訪問我留的查詢接口時,出現(xiàn)Cannot create PoolableConnectionFactory (null, message from server: &qu ...
- MyBatis的發(fā)展和選型
xlecho編輯整理,歡迎轉載,轉載請聲明文章來源.歡迎添加echo微信(微信號:t2421499075)交流學習. 百戰(zhàn)不敗,依不自稱常勝,百敗不頹,依能奮力前行.--這才是真正的堪稱強大!! 參考 ...
- [大數(shù)據(jù)學習研究] 3. hadoop分布式環(huán)境搭建
1. Java安裝與環(huán)境配置 Hadoop是基于Java的,所以首先需要安裝配置好java環(huán)境.從官網(wǎng)下載JDK,我用的是1.8版本. 在Mac下可以在終端下使用scp命令遠程拷貝到虛擬機linux中 ...
- NGUI_基礎入門學習
目錄 1. Control Widgets 控制部件2. Anchors 錨3. Interaction 交互4. Menu 菜單5. Controller Input 控制器的輸入6. Lights ...
- Redis繼續(xù)學習
1.Redis一共16個數(shù)據(jù)庫 # Set the number of databases. The , you can select # a different one on a per-conne ...
- Hadoop&Hbase 雙機熱備--Pacemaker&DRBD部署
相關文章 DRBD的介紹請參考http://blog.t/rzhzhz/article/details/7103772 DRBD的部署請參考http://blog. ...
- jmeter運行第三方java項目
自己寫了個簡化系統(tǒng)操作的小工具,因為不想給別人用的時候占用本地資源于是寫的是純java項目,后面放到jmeter中通過beanshell sampler調用. java源碼不貼了,把寫好的項目導出成可 ...
- php裝上sqlserver驅動后仍然顯示Call to undefined function sqlsrv_connect()問題
今天老師要求本來的php+mysql改為php+sqlserver,在網(wǎng)上搜索了相應的教程,說是“需要下載安裝Microsoft Drivers for PHP for SQL Server驅動”,下 ...
- 快速獲取dom到body左側和頂部的距離,簡單粗暴無bug-getBoundingClientRect
獲取dom到body左側和頂部的距離-getBoundingClientRect 平時在寫js的時候,偶爾會需要用js來獲取當前div到 body 左側.頂部的距離.網(wǎng)上查一查,有很多都是通過offs ...
- Python連載39-生成器、next函數(shù)、yield返回值
?一.生成器 1.定義(generator):一邊循環(huán)一邊計算下一個元素的機制/算法 2.滿三個條件 (1)每次調用都能產(chǎn)生出for循環(huán)需要的下一個元素 (2)如果達到最后一個后,能夠爆出StopIt ...
|