【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)

完整程序:点击下载
官方手册:点击下载
脚  本:makefile
工  具:vcs & verdi


路 线:

  • 【verilog实战】同步FIFO的设计与功能验证(附源码)
  • 【Verilog实战】异步FIFO设计和功能验证(附源码)
  • 【Verilog实战】UART通信协议,半双工通信方式(附源码)
  • 【Verilog实战】SPI协议接口设计和功能验证(附源码)
  • 【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)
  • 【Verilog实战】AMBA AHB接口设计和功能验证(附源码)
  • 【Verilog实战】AMBA AXI接口设计和功能验证(附源码)
  • 【Verilog实战】UART2APB bridge 设计和功能验证(附源码)
  • 【Verilog实战】AHB2APB bridge 设计和功能验证(附源码)

文章目录

  • 一、APB协议
    • 1.1 简介
    • 1.2 APB2
    • 1.3 APB3
    • 1.4 APB4
  • 二、Spec
    • 2.1 Function descripton
    • 2.2 Feature list
    • 2.3 Block Diagram
    • 2.4 Interface description
    • 2.5 Timing
    • 2.6 FSM
  • 三、Design and Verification
    • 3.1 RTL
    • 3.2 Test bench
    • 3.3 Analyse
  • 四、Result
    • 4.1 Write
    • 4.2 Read
    • 4.3 Output


一、APB协议

1.1 简介

APB2 :AMBA 2 APB
APB3 :AMBA 3 APB,比 APB2 多两个信号(PREADY , PSLVERR)
APB4 :AMBA 4 APB,比 APB3 多两个信号(PPROT , PSTRB )

  APB(Advanced Peripheral Bus),高级外设总线。APB总线协议是ARM公司提出的AMBA总线结构之一,是一种片上总线结构。
  APB主要用于低带宽的周边外设之间的连接,例如UART、IIC等,它的总线架构不像AHB支持多个主模块,在APB里面没有仲裁器,APB 桥是唯一的主模块。其特点:低带宽;高性能;非流水作业,至少需要两个时钟周期传输,且数据均在时钟上升沿变化;无需等待周期和回应信号;控制逻辑简单,只有四个控制信号,且APB上的传输可采用状态机表示。


1.2 APB2

1.2.1 Interface

Signal Source Description
PCLK Clock source Clock. The rising edge of PCLK times all transfers on the APB.
PRESETn System bus equivalent Reset. The APB reset signal is active LOW. This signal is normally connected directly to the system bus reset signal.
PADDR APB bridge Address. This is the APB address bus. It can be up to 32 bits wide and is driven by the peripheral bus bridge unit.
PSELx APB bridge Select. The APB bridge unit generates this signal to each peripheral bus slave.It indicates that the slave device is selected and that a data transfer is required.There is a PSELx signal for each slave.
PENABLE APB bridge Enable. This signal indicates the second and subsequent cycles of an APB transfer.
PWRITE APB bridge Direction. This signal indicates an APB write access when HIGH and an APB read access when LOW.
PWDATA APB bridge Write data. This bus is driven by the peripheral bus bridge unit during write cycles when PWRITE is HIGH. This bus can be up to 32 bits wide.
PRDATA Slave interface Read Data. The selected slave drives this bus during read cycles when

由标准协议手册接口描述可以知道,读\写地址共用地址总线,PADDR\PWDATA\PRDATA总线的最大宽度都是32bit。


1.2.2 Timing
(1)写操作
【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第1张图片

  1. 在T0~T1阶段,所有总线处于IDLE状态。
  2. 在T1~T2阶段,第一个时钟周期,处在Setup phase状态。T1时刻,PADDR、PWRITE、PWDATA变化,PSEL拉高,即Master把这些数据发送到总线上。
  3. 在T2~T3阶段,第二个时钟周期,处在Access phase状态。T2时刻,这个时候对应的Slave接收到Master发送过来的地址和写控制命令,此时Slave得知Master要准备发数据过来了,做好准备。
  4. T3时刻,采到PENABLE为高电平,表示Master在这一时刻之前一次写操作已经完成,Master回到IDLE状态,而Slave把数据取走。

(2)读操作
【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第2张图片

  1. 在T0~T1阶段,所有总线处于IDLE状态。
  2. 在T1~T2阶段,第一个时钟周期,处在Setup phase状态。T1时刻,PADDR、PWRITE、PWDATA变化,PSEL拉高,即Master把这些数据发送到总线上。
  3. 在T2~T3阶段,第二个时钟周期,处在Access phase状态。T2时刻,这个时候对应的Slave接收到Master发送过来的地址和读控制命令,此时Slave得知自己要将这个地址反馈给Master了。
  4. T3时刻,采到PENABLE为高电平,表示Master在这一时刻之前一次读操作已经完成,Master回到IDLE状态。

1.3 APB3

1.3.1 Interface(+APB2)

Signal Source Description
PREADY Slave interface Ready. The slave uses this signal to extend an APB transfer.
PSLVERR Slave interface This signal indicates a transfer failure. APB peripherals are not required to support the PSLVERR pin. This is true for both existing and new APB peripheral designs. Where a peripheral does not include this pin then the appropriate input to the APB bridge is tied LOW.

1.3.2 Timing
- 无错误传输的情形

(1)无等待的写操作
【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第3张图片

  1. 在T0~T1阶段,所有总线处于IDLE状态。
  2. 在T1~T2阶段,第一个时钟周期,处在Setup phase状态。T1时刻,PADDR、PWRITE、PWDATA变化,PSEL拉高,即Master把这些数据发送到总线上。
  3. 在T2~T3阶段,第二个时钟周期,处在Access phase状态。T2时刻,这个时候对应的Slave接收到Master发送过来的地址和写控制命令,此时Slave得知Master要准备发数据过来了,做好准备。
  4. T3时刻,采到 PENABLE & PREADY 为高电平,表示Master这一时刻之前一次写操作已经完成,Master回到IDLE状态,而Slave把数据取走。

(2)有等待的写操作
【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第4张图片

  1. 在T0~T1阶段,所有总线处于IDLE状态。
  2. 在T1~T2阶段,第一个时钟周期,处在Setup phase状态。T1时刻,PADDR、PWRITE、PWDATA变化,PSEL拉高,即Master把这些数据发送到总线上。
  3. 在T2~T3阶段,第二个时钟周期,处在Access phase状态。T2时刻,这个时候对应的Slave接收到Master发送过来的地址和写控制命令,此时Slave得知Master要准备发数据过来了,做好准备。
  4. T3时刻,采到 PENABLE 为高电平,但是 PREADY 为低电平,表示Master数据还没准备好。
  5. T5时刻,采到 PENABLE & PREADY 为高电平,表示Master在这一时刻之前一次写操作已经完成,Master回到IDLE状态,而Slave把数据取走。

(3)无等待的读操作
【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第5张图片

  1. 在T0~T1阶段,所有总线处于IDLE状态。
  2. 在T1~T2阶段,第一个时钟周期,处在Setup phase状态。T1时刻,PADDR、PWRITE、PWDATA变化,PSEL拉高,即Master把这些数据发送到总线上。
  3. 在T2~T3阶段,第二个时钟周期,处在Access phase状态。T2时刻,这个时候对应的Slave接收到Master发送过来的地址和读控制命令,此时Slave得知自己要将这个地址反馈给Master了。
  4. T3时刻,采到PENABLE & PREADY 为高电平,表示Master这一时刻之前一次读操作已经完成,Master回到IDLE状态。

(4)有等待的读操作
【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第6张图片1. 在T0~T1阶段,所有总线处于IDLE状态。
2. 在T1~T2阶段,第一个时钟周期,处在Setup phase状态。T1时刻,PADDR、PWRITE、PWDATA变化,PSEL拉高,即Master把这些数据发送到总线上。
3. 在T2~T3阶段,第二个时钟周期,处在Access phase状态。T2时刻,这个时候对应的Slave接收到Master发送过来的地址和读控制命令,此时Slave得知自己要将这个地址反馈给Master了。
4. T3时刻,采到 PENABLE 为高电平,但是 PREADY 为低电平,表示Slave数据还没准备好。
5. T5时刻,采到 PENABLE & PREADY 为高电平,表示Master这一时刻之前一次读操作已经完成,Master回到IDLE状态。


- 错误传输的情形
(1) 写操作
【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第7张图片


(2) 读操作
【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第8张图片

可以使用PSLVERR来指示APB传输错误。当PSEL, PENABLE以及PREADY 都为高时,PSLVERR才在最后一个周期进行判断。当任何一个PSEL, PENABLE或者PREADY为低时,你可以将PSLVERR拉低,这是推荐,并不是强制要求。事物处理收到一个错误后,可能或不可能改变外围器件的状态。APB外围设备不要求必须支持PSLVERR引脚,当不使用该引脚时,应被置低。


1.4 APB4

1.4.1 Interface(+APB2)

Signal Source Description
PPROT APB bridge Protection type. This signal indicates the normal, privileged, or secure protection level of the transaction and whether the transaction is a data access or an instruction access.
PSTRB APB bridge Write strobes. This signal indicates which byte lanes to update during a write transfer. There is one write strobe for each eight bits of the write data bus. Therefore, PSTRB[n] corresponds to PWDATA[(8n + 7):(8n)]. Write strobes must not be active during a read transfer.
PREADY Slave interface Ready. The slave uses this signal to extend an APB transfer.
PSLVERR Slave interface This signal indicates a transfer failure. APB peripherals are not required to support the PSLVERR pin. This is true for both existing and new APB peripheral designs. Where a peripheral does not include this pin then the appropriate input to the APB bridge is tied LOW.

1.4.2 Write strobes
【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第9张图片

由官方手册可以看到,PSTRB信号可以使写数据总线上的数据片段化,即指示数据总线上那几个字节数据有效。由于数据位最大为32bit,即4个字节。因此PSTRB位宽为4位,每一位对应一个字节,设置为1时,指示该字节数据有效。注意的是,在读操作中,PSTRB所有位必须设置为低电平。


1.4.3 Protection unit support
【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第10张图片

为了⽀持复杂系统设计,使⽤PPROT[2:0]来标识合法的互联和传输,抢占式总线很容易被监听,因此总线保护⾮常有必要。APB总线提供三层访问保护,PPROT[0]表⽰正常或私有传输,PPROT[1]表⽰安全或不安全传输,PPROT[2]表⽰数据还是指令传输,具体如下表所⽰:

PPROT[2:0] 保护等级
[0] 1:私有传输
0:一般传输
[1] 1:不安全传输
0:安全传输
[2] 1:指令传输
0:数据传输

二、Spec

2.1 Function descripton

  apb桥实现了将上游的数据转换成AMBA 3 APB协议发送出去,并接收读到的数据。


2.2 Feature list

  1. 系统工作时钟50Mhz,异步复位。
  2. 采用 APB3 协议标准,无需错误指示。
  3. cmd_i,56bit;[55:48]:r/w;[48:32]:paddr;[31:0]:pwdata

2.3 Block Diagram

【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第11张图片


2.4 Interface description

Signal Width Direction Description
pclk_i 1 input APB时钟,50MHz
prst_n_i 1 input APB复位信号
cmd_i 56 input 上游的数据
[55:48]:读写指示位
[47:32]:地址位
[31:0]:数据数据位
cmd_vld_i 1 input 数据有效指示信号
paddr_o 16 output 地址总线,最大32位,这里规定为16位
psel_o 1 output slave片选信号,1:选中;0:不选中
penable_o 1 output 使能信号,1:使能;0:不使能
pwrite_o 1 output 读写指示,1:写操作;0:读操作
pwdata_o 32 output 写数据总线,最大为32bit,这里设定为32bit
prdata_o 32 output 读数据总线,最大为32bit,这里设定为32bit
pready_i 1 input APB转移扩展信号,低电平扩展,高电平结束
pslverr_i 1 input 错误指示信号,这里不用,接低电平

2.5 Timing

(1)Write


(2)Read


2.6 FSM

【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第12张图片


三、Design and Verification

3.1 RTL

/*-------------------------------------------------------------
-- modified by xlinxdu, 2022/05/27
-- pclk 50MHz
-- APB3,No pslverr signal
-- cmd_i:56bit;[55:48]:r/w ,8'b0 -> read,8'b1 -> write
               [47:32]:paddr ,
               [31:0]:pwdata
-------------------------------------------------------------*/
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
)(
//-- system 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

3.2 Test bench

//-- modified by xlinxdu, 2022/05/28
`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;
    #30 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

3.3 Analyse

【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第13张图片

bug1:由仿真波形可以看到,当前状态cur_state和下一个状态nxt_state、prdata_i和cmd_data_buf在同一拍变化,但是设计中两者采用的是时序逻辑,应该会错一拍更新。

【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第14张图片

由官方手册可以看到,这两个输入信号在T4时刻之后一点才拉高,而搭建的testbench中,他们是同一时刻变化,这时候,T4会采到一个亚稳态数据,导致出错,因此在tb中改一下这里即可。

 // 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;
    #30 pready_i = 0;
    #80 pready_i = 1;

更改为:pready_i多延迟1ns输入,错开和时钟同拍

 // 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;

【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第15张图片

由这张图可以看到nxt_state产生了一个中间态IDLE,这是由于三段状态机的第二段状态翻转采用的是组合逻辑,但由于cur_state和nxt_state之间是时序关系,等时钟沿来临的时候,早已经稳定,因此并未影响正确的逻辑。在硬件上的表现是波形出现毛刺


四、Result

4.1 Write

(1)有等待的写操作
【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第16张图片


4.2 Read

(1)有等待的读操作

【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第17张图片


(2)无等待的读操作

【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第18张图片


4.3 Output

【Verilog实战】AMBA 3 APB接口设计和功能验证(附源码)_第19张图片


作者:xlinxdu
版权:本文版权归作者所有
转载:未经作者允许,禁止转载,转载必须保留此段声明,必须在文章中给出原文连接。

你可能感兴趣的:(Verilog实战应用,verilog,AMBA,APB3,协议接口)