0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

SoC入門:APBmaster設(shè)計(jì)主站設(shè)計(jì)原理與實(shí)踐

ruikundianzi ? 來(lái)源:知乎 ? 2024-01-24 14:33 ? 次閱讀

大家不要以為APB的master和slave很簡(jiǎn)單,不需要了解。這是大錯(cuò)特錯(cuò),為什么呢?

不過(guò)設(shè)計(jì)什么模塊,你都要讓它掛在標(biāo)準(zhǔn)總線上,比如你設(shè)計(jì)DMA,你就同時(shí)需要了解AMBA的master和slave設(shè)計(jì)。又比如你是設(shè)計(jì)算法計(jì)算模塊,你的數(shù)據(jù)肯定要放到sram,你當(dāng)然也要了解AMBA的master設(shè)計(jì),將數(shù)據(jù)傳輸?shù)絚rossbar上,進(jìn)而放到指定memory。又比如SOC設(shè)計(jì),肯定需要各種bridge,假設(shè)一個(gè)AHB2APB,你就同時(shí)需要了解AHB slave和APB master。

以APB為例,還是因?yàn)锳PB簡(jiǎn)單,但是我們可以從它學(xué)到設(shè)計(jì)的方法和思路。

既然是設(shè)計(jì)就需要spec和狀態(tài)機(jī)。

設(shè)計(jì)spec如下

1、模塊規(guī)劃

5dfad054-ba6e-11ee-8b88-92fbcf53809c.jpg

模塊diagram

2、接口描述

5e0c910e-ba6e-11ee-8b88-92fbcf53809c.jpg

接口描述

3、時(shí)序描述

讀時(shí)序

5e32259a-ba6e-11ee-8b88-92fbcf53809c.jpg

讀時(shí)序

寫(xiě)時(shí)序

5e4577c6-ba6e-11ee-8b88-92fbcf53809c.jpg

寫(xiě)時(shí)序

4、FSM

就是之前講的APB協(xié)議狀態(tài)機(jī)。如下圖

5e5a7360-ba6e-11ee-8b88-92fbcf53809c.png

APB FSM

模塊規(guī)劃有了,接口有了,時(shí)序有了,狀態(tài)機(jī)有了,就可以開(kāi)始設(shè)計(jì)coding了,代碼如下:

module apb
#(
  parameter RD_FLAG        = 8'b0           ,
  parameter WR_FLAG        = 8'b1           ,
  parameter CMD_RW_WIDTH   = 8              ,
  parameter CMD_ADDR_WIDTH = 16             ,
  parameter CMD_DATA_WIDTH = 32             ,
  parameter CMD_WIDTH      = CMD_RW_WIDTH   + 
                             CMD_ADDR_WIDTH + 
                             CMD_DATA_WIDTH
)(
//-- clkrst signal
  input                           pclk_i       ,
  input                           prst_n_i     ,


//-- cmd_in
  input      [CMD_WIDTH-1:0]      cmd_i        ,
  input                           cmd_vld_i    ,
  output reg [CMD_DATA_WIDTH-1:0] cmd_rd_data_o,


//-- apb interface
  output reg [CMD_ADDR_WIDTH-1:0] paddr_o      ,
  output reg                      pwrite_o     ,
  output reg                      psel_o       ,
  output reg                      penable_o    ,
  output reg [CMD_DATA_WIDTH-1:0] pwdata_o     ,
  input      [CMD_DATA_WIDTH-1:0] prdata_i     ,
  input                           pready_i     ,
  input                           pslverr_i
);


//-- FSM state
parameter IDLE   = 3'b001;
parameter SETUP  = 3'b010;
parameter ACCESS = 3'b100;


//-- current state and next state
reg [2:0] cur_state;
reg [2:0] nxt_state;


//-- data buf
reg                      start_flag     ;
reg [CMD_WIDTH-1:0]      cmd_in_buf     ;
reg [CMD_DATA_WIDTH-1:0] cmd_rd_data_buf;




/*-----------------------------------------------
 --             update cmd_in_buf              --
-----------------------------------------------*/
always @ (posedge pclk_i or negedge prst_n_i) begin
  if (!prst_n_i) begin
    cmd_in_buf <= {(CMD_WIDTH){1'b0}};
  end
  else if (cmd_vld_i && pready_i) begin
    cmd_in_buf <= cmd_i;
  end
end


/*-----------------------------------------------
 --             start flag of transfer         --
-----------------------------------------------*/
always @ (posedge pclk_i or negedge prst_n_i) begin
  if (!prst_n_i) begin
    start_flag <= 1'b0;
  end
  else if (cmd_vld_i && pready_i) begin
    start_flag <= 1'b1;
  end
  else begin
    start_flag <= 1'b0;
  end
end


/*-----------------------------------------------
 --           update current state             --
-----------------------------------------------*/
always @ (posedge pclk_i or negedge prst_n_i) begin
  if (!prst_n_i) begin
    cur_state <= IDLE;
  end
  else begin
    cur_state <= nxt_state;
  end
end


/*-----------------------------------------------
 --               update next state            --
-----------------------------------------------*/
always @ (*) begin
  case(cur_state)
    IDLE  :if(start_flag)begin
             nxt_state = SETUP;
           end
           else begin
             nxt_state = IDLE;
           end


    SETUP :nxt_state = ACCESS;
          
    ACCESS:if (!pready_i)begin
             nxt_state = ACCESS;
           end
           else if(start_flag)begin
             nxt_state = SETUP;
           end
           else if(!cmd_vld_i && pready_i)begin
             nxt_state = IDLE;
           end
  endcase
end


/*-----------------------------------------------
 --         update signal of output            --
-----------------------------------------------*/
always @ (posedge pclk_i or negedge prst_n_i) begin
  if (!prst_n_i) begin
    pwrite_o  <= 1'b0;
    psel_o    <= 1'b0;
    penable_o <= 1'b0;
    paddr_o   <= {(CMD_ADDR_WIDTH){1'b0}};
    pwdata_o  <= {(CMD_DATA_WIDTH){1'b0}};
  end
  
  else if (nxt_state == IDLE) begin
    psel_o    <= 1'b0;
    penable_o <= 1'b0;
  end


  else if(nxt_state == SETUP)begin
    psel_o    <= 1'b1;
    penable_o <= 1'b0;
    paddr_o   <= cmd_in_buf[CMD_WIDTH-CMD_RW_WIDTH-1:CMD_DATA_WIDTH];
    //-- read
    if(cmd_in_buf[CMD_WIDTH-1:CMD_WIDTH-8] == RD_FLAG)begin
      pwrite_o <= 1'b0;
    end
    //-- write
    else begin
      pwrite_o  <= 1'b1;
      pwdata_o  <= cmd_in_buf[CMD_DATA_WIDTH-1:0];
    end
  end


  else if(nxt_state == ACCESS)begin
    penable_o <= 1'b1;
  end
end


/*-----------------------------------------------
 --            update cmd_rd_data_buf          --
-----------------------------------------------*/
always @ (posedge pclk_i or negedge prst_n_i) begin
  if (!prst_n_i) begin
    cmd_rd_data_buf <= {(CMD_DATA_WIDTH){1'b0}};
  end
  else if (pready_i && psel_o && penable_o) begin
    cmd_rd_data_buf <= prdata_i;
  end
end


/*-----------------------------------------------
 --            update cmd_rd_data_o            --
-----------------------------------------------*/
always @ (posedge pclk_i or negedge prst_n_i) begin
  if (!prst_n_i) begin
    cmd_rd_data_o <= {(CMD_DATA_WIDTH){1'b0}};
  end
  else begin
    cmd_rd_data_o <= cmd_rd_data_buf;
  end
end


endmodule

模塊設(shè)計(jì)的比較簡(jiǎn)單,只是實(shí)現(xiàn)APB的基本功能。下面講一下設(shè)計(jì)重點(diǎn):

·一定要做好功課在開(kāi)始coding。

·Flow control,APB的上級(jí)模塊,需要給到流控信號(hào),告知APB master什么時(shí)候開(kāi)始傳輸,什么時(shí)候結(jié)束。

·FSM,必須完全遵循AMBA的datasheet。

·時(shí)序?qū)R,和FSM一樣,接口時(shí)序要和APB協(xié)議對(duì)齊。

·重點(diǎn)中的重點(diǎn),pready的反壓一定要逐級(jí)反壓,不能直接送到APB master的上次模塊,這樣會(huì)丟數(shù)據(jù)。

testbench如下

`timescale 1ns/1ns
module tb_apb;
  reg         pclk_i       ;
  reg         prst_n_i     ;
                          
  reg  [55:0] cmd_i        ;
  reg         cmd_vld_i    ;
  wire [31:0] cmd_rd_data_o;
                          
  wire [15:0] paddr_o      ;
  wire        pwrite_o     ;
  wire        psel_o       ;
  wire        penable_o    ;
  wire [31:0] pwdata_o     ;
  reg  [31:0] prdata_i     ;
  reg         pready_i     ;
  reg         pslverr_i    ;


initial begin
 // rst; 
  pclk_i   = 0;
  prst_n_i = 1;
  pslverr_i = 0;
  cmd_i = 56'b0;
  cmd_vld_i = 0;
  prdata_i = 32'b0;
  pready_i = 1;
  #20 prst_n_i = 0;
  #20 prst_n_i = 1;


 // cmd_in_wr(cmd_i,56'h01_FF_EE_DD_CC_BB_AA);
    cmd_i     = 56'h01_FF_EE_DD_CC_BB_AA;
    cmd_vld_i = 1   ;
    #20 cmd_vld_i = 0;
    #31 pready_i = 0;
    #80 pready_i = 1;


  #90;
  //cmd_in_rd(cmd_i,56'h00_AA_BB_CC_DD_EE_FF,prdata_i,32'h12_34_56_78);
    cmd_i = 56'h00_AA_BB_CC_DD_EE_FF;
    cmd_vld_i = 1;
    #20 cmd_vld_i = 0;
    #30 pready_i = 0;


    #60 pready_i = 1;
        prdata_i = 32'h12_34_56_78;


    cmd_i = 56'h00_AA_BB_CC_DD_EE_FF;
    cmd_vld_i = 1;
    #20 cmd_vld_i = 0;
    #30 pready_i = 0;


    #50 pready_i = 1;
        prdata_i = 32'h11_22_33_44;




end


always #10 pclk_i = ~pclk_i;


//-- RST
task rst;
  begin
    pclk_i   = 1;
    prst_n_i = 1;
    pslverr_i = 0;
    cmd_i = 56'b0;
    cmd_vld_i = 0;
    prdata_i = 32'b0;
    pready_i = 1;
    #20 prst_n_i = 0;
    #10 prst_n_i = 1;
    //cmd_i = 56'h01_FF_EE_DD_CC_BB_Ab;
  end
endtask


//-- write
task cmd_in_wr;
  output [55:0] cmd;
  input  [55:0] data;


  begin
    cmd     = data;
    cmd_vld_i = 1   ;
    #20 cmd_vld_i = 0;
    #20 pready_i = 0;
    #40 pready_i = 1;
  end
endtask


//-- read
task cmd_in_rd;
  output [55:0] cmd;
  input  [55:0] data ;
  output [31:0] prdata;
  input  [31:0] rd_data;


  begin
    cmd = data;
    cmd_vld_i = 1;
    #20 cmd_vld_i = 0;
    #20 pready_i = 0;
    #40 pready_i = 1;
        prdata = rd_data;
  end
endtask
initial begin
  #1000 $finish;
end
apb tb_apb(
            .pclk_i       (pclk_i       ),
            .prst_n_i     (prst_n_i     ),
            .cmd_i        (cmd_i        ),
            .cmd_vld_i    (cmd_vld_i    ),
            .cmd_rd_data_o(cmd_rd_data_o),
            .paddr_o      (paddr_o      ),
            .pwrite_o     (pwrite_o     ),
            .psel_o       (psel_o       ),
            .penable_o    (penable_o    ),
            .pwdata_o     (pwdata_o     ),
            .prdata_i     (prdata_i     ),
            .pready_i     (pready_i     ),
            .pslverr_i    (pslverr_i    )
          );




initial begin
  $fsdbDumpfile("apb.fsdb");
  $fsdbDumpvars            ;
  $fsdbDumpMDA             ;
end


endmodule

makefile如下:

LAB_DIR = /home/*/apb




DFILES = $(LAB_DIR)/*.v 


all:clean elab rung
elab:
  vcs -full64 -LDFLAGS -Wl,-no-as-needed -debug_acc+all -timescale=1ns/1ns 
  -fsdb -sverilog -l comp.log 
  ${DFILES}


run:
  ./simv -l run.log


rung:
  ./simv -gui -l run.log


verdi:
  verdi ${DFILES} 
  -ssf ./*.fsdb &


clean:
  rm -rf  AN.DB 
  rm -rf  DVEfiles 
  rm -rf  csrc 
  rm -rf  simv.* 
  rm -rf  *simv 
  rm -rf  inter.vpd 
  rm -rf  ucli.key 
  rm -rf  *.log 
  rm -rf  verdiLog 
  rm -rf  novas* 
rm-rf*.fsdb

下面是仿真結(jié)果

5e7808da-ba6e-11ee-8b88-92fbcf53809c.jpg

好了,今天講的主要就這么多,這個(gè)是基礎(chǔ),但也是干貨,對(duì)以后設(shè)計(jì)AHB,AXI乃至NOC都非常有幫助。

審核編輯:黃飛

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)傳輸
    +關(guān)注

    關(guān)注

    9

    文章

    1896

    瀏覽量

    64615
  • soc
    soc
    +關(guān)注

    關(guān)注

    38

    文章

    4166

    瀏覽量

    218281
  • 狀態(tài)機(jī)
    +關(guān)注

    關(guān)注

    2

    文章

    492

    瀏覽量

    27541

原文標(biāo)題:SoC設(shè)計(jì)入門 - APB master設(shè)計(jì)(接口類基礎(chǔ)思維)

文章出處:【微信號(hào):IP與SoC設(shè)計(jì),微信公眾號(hào):IP與SoC設(shè)計(jì)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Modbus多問(wèn)題

    ModbusRTU兩之間如何交互數(shù)據(jù)? 工業(yè)控制中,一般都是主從通訊方式居多,有時(shí)也會(huì)碰到兩個(gè)之間通訊。例如某工作站上位機(jī)(
    發(fā)表于 11-24 16:36

    PLC和從分享

    總站是主控制單元,含有CPU,從可以不加CPU,可以作為遠(yuǎn)程,用控制。
    發(fā)表于 07-02 08:20

    CAN與從的功能是什么

    基于 STM32 和 CAN總線的溫度監(jiān)控系統(tǒng)的設(shè)計(jì),通過(guò)上位機(jī)與下位機(jī)的通信,實(shí)現(xiàn)對(duì)溫度數(shù)據(jù)的監(jiān)控,并經(jīng)初步實(shí)驗(yàn)達(dá)到了設(shè)計(jì)的要求。1 系統(tǒng)總體方案概述系統(tǒng)總體框圖如圖 1 所示,本系統(tǒng)采用+從
    發(fā)表于 08-19 07:47

    PLC和從具有哪些功能

    PLC具有哪些功能?PLC從具有哪些功能?
    發(fā)表于 09-29 07:22

    通過(guò)Mbus給從發(fā)送信息,無(wú)法收到信息怎么解決?

    通過(guò)Mbus給從發(fā)送信息,無(wú)法收到信息怎么解決?
    發(fā)表于 01-20 06:42

    lightech mbus完整指令庫(kù)

    lightech mbus完整指令庫(kù)
    發(fā)表于 10-09 06:20

    Profibus-DP通信平臺(tái)的設(shè)計(jì)方案

    Profibus協(xié)議的結(jié)構(gòu)以O(shè)SI為參考模型,DP使用第1層、第2層和用戶接口,第3層到第7層未加以描述。一個(gè)DP系統(tǒng)既可以是一個(gè)單結(jié)構(gòu),也可以是一個(gè)多結(jié)構(gòu),本文涉及的是多
    的頭像 發(fā)表于 12-30 10:04 ?5949次閱讀
    Profibus-DP<b class='flag-5'>主</b><b class='flag-5'>站</b>通信平臺(tái)的設(shè)計(jì)方案

    GitHub入門實(shí)踐

    GitHub入門實(shí)踐
    發(fā)表于 11-21 10:40 ?0次下載

    MELSEC iQ R CC Link系統(tǒng)/本地模塊用戶手冊(cè)(入門篇)

    MELSEC iQ-R CC-link系統(tǒng)/本地模塊用戶手冊(cè)(入門篇) 產(chǎn)品規(guī)格書(shū)
    發(fā)表于 08-25 09:30 ?0次下載
    MELSEC iQ R CC Link系統(tǒng)<b class='flag-5'>主</b><b class='flag-5'>站</b>/本地<b class='flag-5'>站</b>模塊用戶手冊(cè)(<b class='flag-5'>入門</b>篇)

    MELSEC iQ R AnyWireASlink模塊用戶手冊(cè)(入門篇)

    MELSEC iQ-R AnyWireASlink模塊用戶手冊(cè)(入門篇) 產(chǎn)品規(guī)格書(shū)
    發(fā)表于 08-26 15:26 ?0次下載
    MELSEC iQ R AnyWireASlink<b class='flag-5'>主</b><b class='flag-5'>站</b>模塊用戶手冊(cè)(<b class='flag-5'>入門</b>篇)

    MELSEC iQ R DeviceNet/從模塊用戶手冊(cè)(入門篇)

    MELSEC iQ-R DeviceNet /從模塊用戶手冊(cè)(入門篇) 產(chǎn)品規(guī)格書(shū)
    發(fā)表于 08-26 12:01 ?0次下載
    MELSEC iQ R DeviceNet<b class='flag-5'>主</b><b class='flag-5'>站</b>/從<b class='flag-5'>站</b>模塊用戶手冊(cè)(<b class='flag-5'>入門</b>篇)

    EtherCAT 方案橫向?qū)Ρ?/a>

    函數(shù)庫(kù)即可快速架構(gòu)。 使用對(duì)象 強(qiáng)研發(fā)能力的團(tuán)隊(duì) ? 對(duì)成本考量不多,但對(duì)穩(wěn)定性和售后服務(wù)看重的使用者。 ? 想快速入門EtherCAT的初學(xué)者; 驅(qū)動(dòng)器廠商,想降低
    的頭像 發(fā)表于 04-25 16:01 ?1916次閱讀

    EtherCAT方案之橫向比較

    眾所周知,EtherCAT是開(kāi)源協(xié)議,使用者可以根據(jù)倍福提供的相關(guān)資料做產(chǎn)品開(kāi)發(fā),而目前主流的EtherCAT解決方案包括:軟,系統(tǒng)型
    的頭像 發(fā)表于 05-29 09:38 ?4449次閱讀
    EtherCAT<b class='flag-5'>主</b><b class='flag-5'>站</b>方案之橫向比較

    linmodbus RTU程序

    linmodbus RTU 程序
    發(fā)表于 08-09 15:37 ?0次下載

    通過(guò)Profinet轉(zhuǎn)EtherCAT協(xié)議網(wǎng)關(guān)把profient從設(shè)備接入到EtherCAT設(shè)備中

    遠(yuǎn)創(chuàng)智控YC-PNM-ECT,一款基于西門子1200PLC的PROFINET通訊網(wǎng)關(guān)。 遠(yuǎn)創(chuàng)智控YC-PNM-ECT網(wǎng)關(guān)的主要功能是將ETHERCAT總線和PROFINET網(wǎng)絡(luò)連接起來(lái)。它
    的頭像 發(fā)表于 10-10 17:54 ?688次閱讀
    通過(guò)Profinet<b class='flag-5'>主</b><b class='flag-5'>站</b>轉(zhuǎn)EtherCAT協(xié)議網(wǎng)關(guān)把profient從<b class='flag-5'>站</b>設(shè)備接入到EtherCAT<b class='flag-5'>主</b><b class='flag-5'>站</b>設(shè)備中