实验1:创建一个简单的BUS总线

经典AMBA总线系统:(主要是AHB和APB)

组成主要有四部分:master,slaver,arbiter,decoder
master是BUS主控部分,例如CPU
slaver是BUS从属部分,例如ROM
arbiter是BUS仲裁器,用于判断多个主控的优先级
decoder是地址解码器,用于判断控制哪个从属

AHB总线用于高性能,高时钟工作频率模块。AHB在AMBA架构中为系统的高性能运行起到了基石作用。AHB为高性能处理器,片上内存,片外内存提供接口,同时桥接慢速外设。高性能,数据传输,多总线主控制器,突发连续传输,分步传输。AHB总线协议是AMBA的新一代总线协议,支持多种高性能总线主控制器。
AHB_lite是简化版的AHB,只支持一个主控,所以不需要arbiter
其中APB只有slaver
Bridge用于AHB和APB的转化
在这里插入图片描述

实验框架:(来源《CPU自制入门》)

主体部分:
4个主控,1个仲裁器,1个地址解码器,8个从属

在这里插入图片描述
**

端口定义:

**

Part1. BUS总线
    1.bus_arbiter --轮询机制,按照请求顺序
            input wire clk,
            input wire reset,
            input wire  m0_req_,
            input wire  m1_req_,
            input wire  m2_req_,
            input wire  m3_req_, 
            output reg   m0_grnt_,
            output reg   m1_grnt_,
            output reg   m2_grnt_,
            output reg   m3_grnt_
        
    2.bus_master_mux --总线主控多路复用器
            input  wire [`WordAddrBus] m0_addr,	   // Address--30
            input  wire				   m0_as_,	   // Address strobe
            input  wire				   m0_rw,	   // Read/Write
            input  wire [`WordDataBus] m0_wr_data, // Write data--32
            input  wire				   m0_grnt_,   // Bus grant
            // Bus master 1
            input  wire [`WordAddrBus] m1_addr,	   // Address
            input  wire				   m1_as_,	   // Address strobe
            input  wire				   m1_rw,	   // Read/Write
            input  wire [`WordDataBus] m1_wr_data, // Write data
            input  wire				   m1_grnt_,   // Bus grant
            // Bus master 2
            input  wire [`WordAddrBus] m2_addr,	   // Address
            input  wire				   m2_as_,	   // Address strobe
            input  wire				   m2_rw,	   // Read/Write
            input  wire [`WordDataBus] m2_wr_data, // Write data
            input  wire				   m2_grnt_,   // Bus grant
            // Bus master 3
            input  wire [`WordAddrBus] m3_addr,	   // Address
            input  wire				   m3_as_,	   // Address strobe
            input  wire				   m3_rw,	   // Read/Write
            input  wire [`WordDataBus] m3_wr_data, // Write data
            input  wire				   m3_grnt_,   // Bus grant
            /********** Bus slave common signal **********/
            output reg	[`WordAddrBus] s_addr,	   // Address --30
            output reg				   s_as_,	   // Address strobe
            output reg				   s_rw,	   // Read/Write
            output reg	[`WordDataBus] s_wr_data   // Write data --32
            
    3.bus_addr_dec ---地址解码器
            input  wire [`WordAddrBus] s_addr, // Address
            /********** Chip select **********/
            output reg				   s0_cs_, // Bus slave 0
            output reg				   s1_cs_, // Bus slave 1
            output reg				   s2_cs_, // Bus slave 2
            output reg				   s3_cs_, // Bus slave 3
            output reg				   s4_cs_, // Bus slave 4
            output reg				   s5_cs_, // Bus slave 5
            output reg				   s6_cs_, // Bus slave 6
            output reg				   s7_cs_  // Bus slave 7
            
    4.bus_slave_mux ---总线从属多路复用器
            /********** Multiplexer **********/
            input  wire				   s0_cs_,	   // Bus slave 0
            input  wire				   s1_cs_,	   // Bus slave 1
            input  wire				   s2_cs_,	   // Bus slave 2
            input  wire				   s3_cs_,	   // Bus slave 3
            input  wire				   s4_cs_,	   // Bus slave 4
            input  wire				   s5_cs_,	   // Bus slave 5
            input  wire				   s6_cs_,	   // Bus slave 6
            input  wire				   s7_cs_,	   // Bus slave 7
            /********** Bus slave signals **********/
            // Bus slave 0
            input  wire [`WordDataBus] s0_rd_data, // Read data
            input  wire				   s0_rdy_,	   // Ready
            // Bus slave 1
            input  wire [`WordDataBus] s1_rd_data, // Read data
            input  wire				   s1_rdy_,	   // Ready
            // Bus slave 2
            input  wire [`WordDataBus] s2_rd_data, // Read data
            input  wire				   s2_rdy_,	   // Ready
            // Bus slave 3
            input  wire [`WordDataBus] s3_rd_data, // Read data
            input  wire				   s3_rdy_,	   // Ready
            // Bus slave 4
            input  wire [`WordDataBus] s4_rd_data, // Read data
            input  wire				   s4_rdy_,	   // Ready
            // Bus slave 5
            input  wire [`WordDataBus] s5_rd_data, // Read data
            input  wire				   s5_rdy_,	   // Ready
            // Bus slave 6
            input  wire [`WordDataBus] s6_rd_data, // Read data
            input  wire				   s6_rdy_,	   // Ready
            // Bus slave 7
            input  wire [`WordDataBus] s7_rd_data, // Read data
            input  wire				   s7_rdy_,	   // Ready
            /********** Bus master common signals **********/
            output reg	[`WordDataBus] m_rd_data,  // Read data
            output reg				   m_rdy_	

1.总线仲裁器的实现

采用轮询机制,实现优先级排序
主控输入req请求,输出grnt,给出总线控制权
在这里插入图片描述

在这里插入图片描述
代码如下:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/12/26 10:40:57
// Design Name: 
// Module Name: bus_arbiter
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 总线仲裁器的实现
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`include"nettype.vh"
`include"stddef.vh"
`include"global_config.vh"
`include"bus.vh"


module bus_arbiter(
    input wire clk,
    input wire reset,
    input wire  m0_req_,
    output reg   m0_grnt_,
    input wire  m1_req_,
    output reg   m1_grnt_,
    input wire  m2_req_,
    output reg   m2_grnt_,
    input wire  m3_req_,
    output reg   m3_grnt_
    );
    reg[`BusOwnerBus] owner;
    
    /************赋予总线使用权,用owner内部变量实现使用权赋予************/
    always@(*)
    begin//赋予总线使用权初始化
            m0_grnt_=`DISABLE_;
            m1_grnt_=`DISABLE_;
            m2_grnt_=`DISABLE_;
            m3_grnt_=`DISABLE_;
            case(owner)//基于总线使用者owner,设置当前总线持有者信号
            `BUS_OWNER_MASTER_0:
            begin
            m0_grnt_=`ENABLE_;
            end
             `BUS_OWNER_MASTER_1:
             begin
            m1_grnt_=`ENABLE_;
            end
             `BUS_OWNER_MASTER_2:
             begin
            m2_grnt_=`ENABLE_;
            end
             `BUS_OWNER_MASTER_3:
             begin
            m3_grnt_=`ENABLE_;
            end
            endcase
    end
    
   /***********总线仲裁器的仲裁方案********************/
    always@(posedge clk or `RESET_EDGE reset)  //`define RESET_EDGE	  negedge
    begin
                    if(reset ==`RESET_ENABLE)begin
                    //异步复位
                    owner <=#1 `BUS_OWNER_MASTER_0;
                    end
                    else begin
                     //仲裁
                    case (owner)  
    
                    //0号总线主控
                    `BUS_OWNER_MASTER_0: begin
                    if(m0_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_0;
                    end
                    else if(m1_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_1;
                    end
                    else if(m2_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_2;
                    end
                    else if(m3_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_3;
                    end
                    end
                    
                     //1号总线主控
                    `BUS_OWNER_MASTER_1: begin
                    if(m1_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_1;
                    end
                    else if(m2_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_2;
                    end
                    else if(m3_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_3;
                    end
                    else if(m0_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_0;
                    end
                    end
                    
                     //2号总线主控
                    `BUS_OWNER_MASTER_2: begin
                    if(m2_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_2;
                    end
                    else if(m3_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_3;
                    end
                    else if(m0_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_0;
                    end
                    else if(m1_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_1;
                    end
                    end
                    
                     //3号总线主控
                    `BUS_OWNER_MASTER_3: begin
                    if(m3_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_3;
                    end
                    else if(m0_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_0;
                    end
                    else if(m1_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_1;
                    end
                    else if(m2_req_==`ENABLE_)begin
                    owner<=#1 `BUS_OWNER_MASTER_2;
                    end
                    end
                    
                    endcase
                    end
  end  
endmodule

2.总线主控多路复用器

将主控信号输入给BUS总线
在这里插入图片描述
看仲裁器给谁grnt信号,哪个主控就可以把信号给BUS
例如,默认情况下,0号主控的addr地址,as_地址标志位,rw读写信号,wr_data写入数据。全都赋值给output s的对应信。
代码如下:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/12/26 16:07:16
// Design Name: 
// Module Name: bus_master_mux
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 总线主控多路复用器
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`include"nettype.vh"
`include"stddef.vh"
`include"global_config.vh"
`include"bus.vh"

module bus_master_mux(
    //Bus master 0
    input  wire [`WordAddrBus] m0_addr,	   // Address--30
	input  wire				   m0_as_,	   // Address strobe
	input  wire				   m0_rw,	   // Read/Write
	input  wire [`WordDataBus] m0_wr_data, // Write data--32
	input  wire				   m0_grnt_,   // Bus grant
	// Bus master 1
	input  wire [`WordAddrBus] m1_addr,	   // Address
	input  wire				   m1_as_,	   // Address strobe
	input  wire				   m1_rw,	   // Read/Write
	input  wire [`WordDataBus] m1_wr_data, // Write data
	input  wire				   m1_grnt_,   // Bus grant
	// Bus master 2
	input  wire [`WordAddrBus] m2_addr,	   // Address
	input  wire				   m2_as_,	   // Address strobe
	input  wire				   m2_rw,	   // Read/Write
	input  wire [`WordDataBus] m2_wr_data, // Write data
	input  wire				   m2_grnt_,   // Bus grant
	// Bus master 3
	input  wire [`WordAddrBus] m3_addr,	   // Address
	input  wire				   m3_as_,	   // Address strobe
	input  wire				   m3_rw,	   // Read/Write
	input  wire [`WordDataBus] m3_wr_data, // Write data
	input  wire				   m3_grnt_,   // Bus grant
	/********** Bus slave common signal **********/
	output reg	[`WordAddrBus] s_addr,	   // Address --30
	output reg				   s_as_,	   // Address strobe
	output reg				   s_rw,	   // Read/Write
	output reg	[`WordDataBus] s_wr_data   // Write data --32
    );
    //选择有总线控制权的主控
    always @(*)begin
                    if (m0_grnt_ == `ENABLE_) begin
                        s_addr=m0_addr;
                        s_as_=m0_as_;
                        s_rw=m0_rw;
                        s_wr_data=m0_wr_data;
                        end
               else if  (m1_grnt_ == `ENABLE_) begin
                        s_addr=m1_addr;
                        s_as_=m1_as_;
                        s_rw=m1_rw;
                        s_wr_data=m1_wr_data;
                        end  
                else if  (m2_grnt_ == `ENABLE_) begin
                        s_addr=m2_addr;
                        s_as_=m2_as_;
                        s_rw=m2_rw;
                        s_wr_data=m2_wr_data;
                        end  
                else if  (m3_grnt_ == `ENABLE_) begin
                        s_addr=m3_addr;
                        s_as_=m3_as_;
                        s_rw=m3_rw;
                        s_wr_data=m3_wr_data;
                        end           
                else begin
                //设置默认值
                        s_addr =`WORD_ADDR_W'h0;  //`define WORD_ADDR_W			30	
                        s_as_=`DISABLE_;//`define WORD_DATA_W			32		 
                        s_rw=`READ;
                        s_wr_data =`WORD_DATA_W'h0;
                        end
             end
    
endmodule

3.地址解码器

实现地址映射,根据addr来决定控制哪个从属,输出对应的cs_信号
在这里插入图片描述
在这里插入图片描述
代码如下:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/12/26 19:11:07
// Design Name: 
// Module Name: bus_addr_dec
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 地址解码器
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`include"nettype.vh"
`include"stddef.vh"
`include"global_config.vh"
`include"bus.vh"

module bus_addr_dec(
/********** Address **********/
	input  wire [`WordAddrBus] s_addr, // Address
	/********** Chip select **********/
	output reg				   s0_cs_, // Bus slave 0
	output reg				   s1_cs_, // Bus slave 1
	output reg				   s2_cs_, // Bus slave 2
	output reg				   s3_cs_, // Bus slave 3
	output reg				   s4_cs_, // Bus slave 4
	output reg				   s5_cs_, // Bus slave 5
	output reg				   s6_cs_, // Bus slave 6
	output reg				   s7_cs_  // Bus slave 7
    );
    //总线从属索引,定义内部变量
    wire [`BusSlaveIndexBus] s_index=s_addr[`BusSlaveIndexLoc];
    /*
      `define BusSlaveIndexBus   2:0	 // Status of bus slave
	`define BusSlaveIndexLoc   29:27 // Index of bus slave location
    需要三个比特位来区分8个总线从属通道,用地址(位宽30)的最高三位来识别总线从属,从而生成总线从属索引
    */
    /**************总线从属多路复用器**********************/
    always@(*)begin
    //初始化
                        s0_cs_=`DISABLE_;
                        s1_cs_=`DISABLE_;
                        s2_cs_=`DISABLE_;
                        s3_cs_=`DISABLE_;
                        s4_cs_=`DISABLE_;
                        s5_cs_=`DISABLE_;
                        s6_cs_=`DISABLE_;
                        s7_cs_=`DISABLE_;
    //选择地址对应的从属
                        case (s_index)   
                            `BUS_SLAVE_0:begin   
                                          s0_cs_ =`ENABLE_;
                                           end
                            `BUS_SLAVE_1:begin   
                                          s1_cs_ =`ENABLE_;
                                           end
                            `BUS_SLAVE_2:begin   
                                          s2_cs_ =`ENABLE_;
                                           end
                            `BUS_SLAVE_3:begin   
                                          s3_cs_ =`ENABLE_;
                                           end
                            `BUS_SLAVE_4:begin   
                                          s4_cs_ =`ENABLE_;
                                           end
                            `BUS_SLAVE_5:begin   
                                          s5_cs_ =`ENABLE_;
                                           end
                            `BUS_SLAVE_6:begin   
                                          s6_cs_ =`ENABLE_;
                                           end
                            `BUS_SLAVE_7:begin   
                                          s7_cs_ =`ENABLE_;
                                           end   
                            endcase
                end
endmodule

4.总线从属多路复用器

根据cs_信号,将对应的slaver的rd_data和rdy_信号输出
在这里插入图片描述

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/12/26 19:42:04
// Design Name: 
// Module Name: bus_slave_mux
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 总线从属多路复用器
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`include"nettype.vh"
`include"stddef.vh"
`include"global_config.vh"
`include"bus.vh"

module bus_slave_mux(
    /********** Multiplexer **********/
    input  wire				   s0_cs_,	   // Bus slave 0
	input  wire				   s1_cs_,	   // Bus slave 1
	input  wire				   s2_cs_,	   // Bus slave 2
	input  wire				   s3_cs_,	   // Bus slave 3
	input  wire				   s4_cs_,	   // Bus slave 4
	input  wire				   s5_cs_,	   // Bus slave 5
	input  wire				   s6_cs_,	   // Bus slave 6
	input  wire				   s7_cs_,	   // Bus slave 7
	/********** Bus slave signals **********/
	// Bus slave 0
	input  wire [`WordDataBus] s0_rd_data, // Read data
	input  wire				   s0_rdy_,	   // Ready
	// Bus slave 1
	input  wire [`WordDataBus] s1_rd_data, // Read data
	input  wire				   s1_rdy_,	   // Ready
	// Bus slave 2
	input  wire [`WordDataBus] s2_rd_data, // Read data
	input  wire				   s2_rdy_,	   // Ready
	// Bus slave 3
	input  wire [`WordDataBus] s3_rd_data, // Read data
	input  wire				   s3_rdy_,	   // Ready
	// Bus slave 4
	input  wire [`WordDataBus] s4_rd_data, // Read data
	input  wire				   s4_rdy_,	   // Ready
	// Bus slave 5
	input  wire [`WordDataBus] s5_rd_data, // Read data
	input  wire				   s5_rdy_,	   // Ready
	// Bus slave 6
	input  wire [`WordDataBus] s6_rd_data, // Read data
	input  wire				   s6_rdy_,	   // Ready
	// Bus slave 7
	input  wire [`WordDataBus] s7_rd_data, // Read data
	input  wire				   s7_rdy_,	   // Ready
	/********** Bus master common signals **********/
	output reg	[`WordDataBus] m_rd_data,  // Read data
	output reg				   m_rdy_	
    );
    always@(*)begin
                    if(s0_cs_==`ENABLE_)begin
                        m_rd_data=s0_rd_data;
                        m_rdy_=s0_rdy_;
                        end
               else if(s1_cs_==`ENABLE_)begin
                        m_rd_data=s1_rd_data;
                        m_rdy_=s1_rdy_;
                        end
               else if(s2_cs_==`ENABLE_)begin
                        m_rd_data=s2_rd_data;
                        m_rdy_=s2_rdy_;
                        end
               else if(s3_cs_==`ENABLE_)begin
                        m_rd_data=s3_rd_data;
                        m_rdy_=s3_rdy_;
                        end
               else if(s4_cs_==`ENABLE_)begin
                        m_rd_data=s4_rd_data;
                        m_rdy_=s4_rdy_;
                        end
               else if(s5_cs_==`ENABLE_)begin
                        m_rd_data=s5_rd_data;
                        m_rdy_=s5_rdy_;
                        end
              else if(s6_cs_==`ENABLE_)begin
                        m_rd_data=s6_rd_data;
                        m_rdy_=s6_rdy_;
                        end
              else if(s7_cs_==`ENABLE_)begin
                        m_rd_data=s7_rd_data;
                        m_rdy_=s7_rdy_;
                        end
              else begin
                        m_rd_data=`WORD_DATA_W'h0;
                        m_rdy_  =`DISABLE_;
                    end
              end
              
    
endmodule

5.TOP模块连接

在这里插入图片描述
在这里插入图片描述

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/12/26 20:22:39
// Design Name: 
// Module Name: bus
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 总线的顶层模块
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`include"nettype.vh"
`include"stddef.vh"
`include"global_config.vh"
`include"bus.vh"


module bus(
    input  wire				   clk,		   // Clock
	input  wire				   reset,	   // Asynchronous reset
	/********** Bus master signal **********/
	// Bus master common signal
	output wire [`WordDataBus] m_rd_data,  // Read data
	output wire				   m_rdy_,	   // Ready
	// Bus master 0
	input  wire				   m0_req_,	   // Bus request
	input  wire [`WordAddrBus] m0_addr,	   // Address
	input  wire				   m0_as_,	   // Address strobe
	input  wire				   m0_rw,	   // Read/Write
	input  wire [`WordDataBus] m0_wr_data, // Write data
	output wire				   m0_grnt_,  
	// Bus master 1
	input  wire				   m1_req_,
	input  wire [`WordAddrBus] m1_addr,	  
	input  wire				   m1_as_,	  
	input  wire				   m1_rw,	 
	input  wire [`WordDataBus] m1_wr_data, 
	output wire				   m1_grnt_,   
	// Bus master 2
	input  wire				   m2_req_,	   
	input  wire [`WordAddrBus] m2_addr,	  
	input  wire				   m2_as_,	   
	input  wire				   m2_rw,	  
	input  wire [`WordDataBus] m2_wr_data,
	output wire				   m2_grnt_,   
	// Bus master 3
	input  wire				   m3_req_,	   
	input  wire [`WordAddrBus] m3_addr,	  
	input  wire				   m3_as_,	   
	input  wire				   m3_rw,	  
	input  wire [`WordDataBus] m3_wr_data,
	output wire				   m3_grnt_,
	/********** Bus salve singals **********/
	// Bus slave common signals
	output wire [`WordAddrBus] s_addr,	   // Address
	output wire				   s_as_,	   // Address strobe
	output wire				   s_rw,	   // Read/Write
	output wire [`WordDataBus] s_wr_data,  // Write data
	// Bus salve 0
	input  wire [`WordDataBus] s0_rd_data, // Read data
	input  wire				   s0_rdy_,	   // Read
	output wire				   s0_cs_,	   // Chip select
	// Bus salve 1
	input  wire [`WordDataBus] s1_rd_data,
	input  wire				   s1_rdy_,	   
	output wire				   s1_cs_,	   
	// Bus salve 2
	input  wire [`WordDataBus] s2_rd_data, 
	input  wire				   s2_rdy_,	  
	output wire				   s2_cs_,	   
	// Bus salve 3
	input  wire [`WordDataBus] s3_rd_data,
	input  wire				   s3_rdy_,	   
	output wire				   s3_cs_,	   
	// Bus salve 4
	input  wire [`WordDataBus] s4_rd_data, 
	input  wire				   s4_rdy_,	   
	output wire				   s4_cs_,	   
	// Bus salve 5
	input  wire [`WordDataBus] s5_rd_data, 
	input  wire				   s5_rdy_,	   
	output wire				   s5_cs_,	   
	// Bus salve 6
	input  wire [`WordDataBus] s6_rd_data, 
	input  wire				   s6_rdy_,	   
	output wire				   s6_cs_,	   
	// Bus salve 7
	input  wire [`WordDataBus] s7_rd_data, 
	input  wire				   s7_rdy_,	   
	output wire				   s7_cs_	   
    );
    //BUS arbiter
    bus_arbiter bus_arbiter(
    .clk(clk),
    .reset(reset),
    .m0_req_(m0_req_),
    .m1_req_(m1_req_),
    .m2_req_(m2_req_),
    .m3_req_(m3_req_),
    .m0_grnt_(m0_grnt_),
    .m1_grnt_(m1_grnt_),
    .m2_grnt_(m2_grnt_),
    .m3_grnt_(m3_grnt_)
       
    );
    //bus master multiplexer
    bus_master_mux bus_master_mux (
    .m0_addr(m0_addr),
    .m1_addr(m1_addr),
    .m2_addr(m2_addr),
    .m3_addr(m3_addr),
    .m0_as_(m0_as_),
    .m1_as_(m1_as_),
    .m2_as_(m2_as_),
    .m3_as_(m3_as_),
    .m0_rw(m0_rw),
    .m1_rw(m1_rw),
    .m2_rw(m2_rw),
    .m3_rw(m3_rw),
    .m0_wr_data(m0_wr_data),
    .m1_wr_data(m1_wr_data),
    .m2_wr_data(m2_wr_data),
    .m3_wr_data(m3_wr_data),
    .m0_grnt_(m0_grnt_),
    .m1_grnt_(m1_grnt_),
    .m2_grnt_(m2_grnt_),
    .m3_grnt_(m3_grnt_),
     .s_addr(s_addr),
     .s_as_(s_as_),
     .s_rw(s_rw),
     .s_wr_data(s_wr_data)
   );  
    
   
    bus_addr_dec bus_addr_dec(
    .s_addr(s_addr),
    .s0_cs_(s0_cs_),
    .s1_cs_(s1_cs_),
    .s2_cs_(s2_cs_),
    .s3_cs_(s3_cs_),
    .s4_cs_(s4_cs_),
    .s5_cs_(s5_cs_),
    .s6_cs_(s6_cs_),
    .s7_cs_(s7_cs_)
     );
    bus_slave_mux bus_slave_mux (
		/********** Chip select **********/
		.s0_cs_		(s0_cs_),	  // Bus slave 0
		.s1_cs_		(s1_cs_),	  // Bus slave 1
		.s2_cs_		(s2_cs_),	  // Bus slave 2
		.s3_cs_		(s3_cs_),	  // Bus slave 3
		.s4_cs_		(s4_cs_),	  // Bus slave 4
		.s5_cs_		(s5_cs_),	  // Bus slave 5
		.s6_cs_		(s6_cs_),	  // Bus slave 6
		.s7_cs_		(s7_cs_),	  // Bus slave 7
		/********** Bus slave signal **********/
		// Bus slave 0
		.s0_rd_data (s0_rd_data), // Read data
		.s0_rdy_	(s0_rdy_),	  // Ready
		// Bus slave 1
		.s1_rd_data (s1_rd_data), 
		.s1_rdy_	(s1_rdy_),	  
		// Bus slave 2
		.s2_rd_data (s2_rd_data), 
		.s2_rdy_	(s2_rdy_),	  
		// Bus slave 3
		.s3_rd_data (s3_rd_data), 
		.s3_rdy_	(s3_rdy_),	 
		// Bus slave 4
		.s4_rd_data (s4_rd_data), 
		.s4_rdy_	(s4_rdy_),	  
		// Bus slave 5
		.s5_rd_data (s5_rd_data), 
		.s5_rdy_	(s5_rdy_),	  
		// Bus slave 6
		.s6_rd_data (s6_rd_data), 
		.s6_rdy_	(s6_rdy_),	  
		// Bus slave 7
		.s7_rd_data (s7_rd_data), 
		.s7_rdy_	(s7_rdy_),	  
		/********** Bus master common signal **********/
		.m_rd_data	(m_rd_data),  // Read data
		.m_rdy_		(m_rdy_)	  // Ready
	);  
    
endmodule

回顾上文的端口定义,我们可以得到几个模块间的相互关系
在这里插入图片描述
1.arbiter模块,基本输入clk,reset,
将m0-m4的req信号根据轮询机制输出对应的grnt信号,只有得到grnt信号才可以得到BUS的控制权。
2.master_mux模块,根据arbiter给出的grnt信号,将得到控制权的主控相关信号输出,如s_addr,,s_as_,,s_rw,,s_wr_data 。
3.addr_dec模块,根据master_mux输出的s_addr,将地址前三位取出,判断哪个slaver被控制,被控制的slaver得到cs_标志位
4.slave_mux模块,根据地址编码器的cs_标志位,将对应的slaver的信号,如rd_data,rdy_,输出给output—m_rd_data, m_rdy_

6.建立ROM,作为slaver0

在验证模块中,我们将用主控0号控制从属0号,读取从属0的数据,我们将用只读存储器ROM接入0号总线从属。
代码如下:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/01/22 16:55:53
// Design Name: 
// Module Name: rom
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// Read Only Memory
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`include"nettype.vh"
`include"stddef.vh"
`include"global_config.vh"
`include"rom.vh"



module rom(
/********** Clock & Reset **********/
	input  wire				   clk,		// Clock
	input  wire				   reset,	// Asynchronous reset
	/********** Bus interface **********/
	input  wire				   cs_,		// Chip select
	input  wire				   as_,		// Address strobe
	input  wire [`RomAddrBus] addr,	    // Address
	output wire [`WordDataBus] rd_data, // Read data
	output reg				   rdy_		// Ready
  );
  /********** Xilinx FPGA Block RAM : Single port ROM **********/
	x_s3e_sprom x_s3e_sprom (
		.clka  (clk),					// Clock
		.addra (addr),					// Address
		.douta (rd_data)				// Read data
	);

	/********** Generate ready **********/
	always @(posedge clk or `RESET_EDGE reset) begin
		if (reset == `RESET_ENABLE) begin
			/* Asynchronous reset */
			rdy_ <= #1 `DISABLE_;
		end else begin
			/* Generate ready */
			if ((cs_ == `ENABLE_) && (as_ == `ENABLE_)) begin
				rdy_ <= #1 `ENABLE_;
			end else begin
				rdy_ <= #1 `DISABLE_;
			end
		end
	end  
endmodule

rom的端口:
part2.single port  Read Only Memory
1.rom
        input  wire				   clk,		// Clock
        input  wire				   reset,	// Asynchronous reset
        /********** Bus interface **********/
        input  wire				   cs_,		// Chip select
        input  wire				   as_,		// Address strobe
        input  wire [`RomAddrBus] addr,	    // Address
        output wire [`WordDataBus] rd_data, // Read data
        output reg				   rdy_		// Ready

将addr地址输入,得到对应地址的数据输出。
实例化–Xilinx FPGA Block RAM : Single port ROM

/*
 -- ============================================================================
 -- FILE NAME	: x_s3e_sprom.v
 -- DESCRIPTION : Xilinx Spartan-3E Single Port ROM psuedo module
 -- ----------------------------------------------------------------------------
 -- Revision  Date		  Coding_by	 Comment
 -- 1.0.0	  2011/06/27  suito		 Created
 -- ============================================================================
*/

/********** Global header **********/
`include "nettype.vh"
`include "stddef.vh"
`include "global_config.vh"

/********** Local header **********/
`include "rom.vh"

/********** Module **********/
module x_s3e_sprom (
	input wire				  clka,	 // Clock
	input wire [`RomAddrBus]  addra, // Address
	output reg [`WordDataBus] douta	 // Read data
);
/*
 `define ROM_SIZE   8192	// ROM's size
	`define ROM_DEPTH  2048	// ROM's depth
	`define ROM_ADDR_W 11	// Address width
	`define RomAddrBus 10:0 // Address bus
	`define RomAddrLoc 10:0 // Address location
	`define WordDataBus			31:0	 	 // Data bus
	
*/
	/********** Memory **********/
	reg [`WordDataBus] mem [0:`ROM_DEPTH-1];
	
	initial begin
      $readmemb("memdata.mem", mem, 0, 99);
      $display("memdata[0]=%b",mem[0]);
       $display("memdata[1]=%b",mem[1]);
        $display("memdata[2]=%b",mem[2]);
    end
    
	/********** Read access **********/
	always @(posedge clka) begin
		douta <= #1 mem[addra];
	end

endmodule

要注意在目录下建立memdata.mem文件,里面放2进制代码,如下:

00100000000000000000000000000000
00011000000000110000000000000000
01111000010000100000000000100000
00011000000001000000000000000100
01001000100001000000000000000010
10111000010001000000000000001000
01001000000001100000000000010100
00111000110001111111111111111110
10001000000001111111111111111100
00000000000000000000000000000000
10000000000000011111111111110010
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000

7.测试模块

注意s_addr的位宽为30,ROM需要的addr位宽为11位,这里选取了{{11’b00000_000001}}号的ROM内存地址。取出其数据。m0_rw<=`READ;读写信号设置为读取。
代码如下

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/12/26 21:23:23
// Design Name: 
// Module Name: bus_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`include"nettype.vh"
`include"stddef.vh"
`include"global_config.vh"
`include"bus.vh"
`include"rom.vh"

module bus_test(

    );
    reg	    	   clk;	   // Clock
	reg			   reset;   // Asynchronous reset
	/********** Bus master signal **********/
	// Bus master common signal
	 wire [`WordDataBus] m_rd_data; // Read data
	 wire				   m_rdy_;   // Ready
	// Bus master 0
	  reg			   m0_req_;   // Bus request
	reg [`WordAddrBus] m0_addr;   // Address
	reg			   m0_as_;   // Address strobe
	reg			   m0_rw;   // Read/Write
	reg [`WordDataBus] m0_wr_data;// Write data
	 wire				   m0_grnt_;  
	// Bus master 1
	reg			   m1_req_;
	reg [`WordAddrBus] m1_addr;  
	reg			   m1_as_;  
	reg			   m1_rw; 
	reg [`WordDataBus] m1_wr_data; 
	 wire				   m1_grnt_;   
	// Bus master 2
	reg			   m2_req_;   
	reg [`WordAddrBus] m2_addr;  
	reg			   m2_as_;   
	reg			   m2_rw;  
	reg [`WordDataBus] m2_wr_data;
	 wire				   m2_grnt_;   
	// Bus master 3
	reg			   m3_req_;   
	 reg [`WordAddrBus] m3_addr;  
	reg			   m3_as_;   
	reg			   m3_rw;  
	 reg [`WordDataBus] m3_wr_data;
	 wire				   m3_grnt_;
	/********** Bus salve singals **********/
	// Bus slave common signals
	 wire [`WordAddrBus] s_addr;   // Address
	 wire				   s_as_;   // Address strobe
	 wire				   s_rw;   // Read/Write
	 wire [`WordDataBus] s_wr_data; // Write data
	// Bus salve 0
	wire [`WordDataBus] s0_rd_data; // Read data
	wire			   s0_rdy_;   // Read
	 wire				   s0_cs_;   // Chip select
	// Bus salve 1
	reg [`WordDataBus] s1_rd_data;
	reg			   s1_rdy_;   
	 wire				   s1_cs_;   
	// Bus salve 2
	reg [`WordDataBus] s2_rd_data;
	reg			   s2_rdy_;  
	 wire				   s2_cs_;   
	// Bus salve 3
	reg [`WordDataBus] s3_rd_data;
	reg			   s3_rdy_;   
	 wire				   s3_cs_;   
	// Bus salve 4
	reg [`WordDataBus] s4_rd_data;
	reg			   s4_rdy_;   
	 wire				   s4_cs_;   
	// Bus salve 5
	 reg [`WordDataBus] s5_rd_data; 
	reg			   s5_rdy_;   
	 wire				   s5_cs_;   
	// Bus salve 6
	 reg [`WordDataBus] s6_rd_data; 
	reg			   s6_rdy_;   
	 wire				   s6_cs_;   
	// Bus salve 7
	 reg [`WordDataBus] s7_rd_data; 
	reg			   s7_rdy_;   
	 wire				   s7_cs_;	
	 //产生时钟激励
    integer i;
    parameter STEP=100;
    
    always#(STEP/2)begin
    clk<=~clk;
    end
    
   //实例化
  bus bus(
     .clk(clk),
    .reset(reset),
    .m0_req_(m0_req_),
    .m1_req_(m1_req_),
    .m2_req_(m2_req_),
    .m3_req_(m3_req_),
    .m0_grnt_(m0_grnt_),
    .m1_grnt_(m1_grnt_),
    .m2_grnt_(m2_grnt_),
    .m3_grnt_(m3_grnt_),
     .m0_addr(m0_addr),
    .m1_addr(m1_addr),
    .m2_addr(m2_addr),
    .m3_addr(m3_addr),
    .m0_as_(m0_as_),
    .m1_as_(m1_as_),
    .m2_as_(m2_as_),
    .m3_as_(m3_as_),
    .m0_rw(m0_rw),
    .m1_rw(m1_rw),
    .m2_rw(m2_rw),
    .m3_rw(m3_rw),
    .m0_wr_data(m0_wr_data),
    .m1_wr_data(m1_wr_data),
    .m2_wr_data(m2_wr_data),
    .m3_wr_data(m3_wr_data),
     .s_addr(s_addr),
     .s_as_(s_as_),
     .s_rw(s_rw),
     .s_wr_data(s_wr_data),
    .s0_cs_(s0_cs_),
    .s1_cs_(s1_cs_),
    .s2_cs_(s2_cs_),
    .s3_cs_(s3_cs_),
    .s4_cs_(s4_cs_),
    .s5_cs_(s5_cs_),
    .s6_cs_(s6_cs_),
    .s7_cs_(s7_cs_),
    .s0_rd_data (s0_rd_data), // Read data
    .s0_rdy_	(s0_rdy_),	  // Ready
    // Bus slave 1
    .s1_rd_data (s1_rd_data), 
    .s1_rdy_	(s1_rdy_),	  
    // Bus slave 2
    .s2_rd_data (s2_rd_data), 
    .s2_rdy_	(s2_rdy_),	  
    // Bus slave 3
    .s3_rd_data (s3_rd_data), 
    .s3_rdy_	(s3_rdy_),	 
    // Bus slave 4
    .s4_rd_data (s4_rd_data), 
    .s4_rdy_	(s4_rdy_),	  
    // Bus slave 5
    .s5_rd_data (s5_rd_data), 
    .s5_rdy_	(s5_rdy_),	  
    // Bus slave 6
    .s6_rd_data (s6_rd_data), 
    .s6_rdy_	(s6_rdy_),	  
    // Bus slave 7
    .s7_rd_data (s7_rd_data), 
    .s7_rdy_	(s7_rdy_),	  
    /********** Bus master common signal **********/
    .m_rd_data	(m_rd_data),  // Read data
    .m_rdy_		(m_rdy_)
   
    );
    rom rom (
		/********** Clock & Reset **********/
		.clk			 (clk),					  // Clock
		.reset			 (reset),				  // Asynchronous reset
		/********** Bus Interface **********/
		.cs_			 (s0_cs_),				  // Chip select
		.as_			 (s_as_),				  // Address strobe
		.addr			 (s_addr[`RomAddrLoc]),	  // Address
		.rd_data		 (s0_rd_data),			  // Read data
		.rdy_			 (s0_rdy_)				  // Ready
	);

     //测试总线仲裁器的轮询
    initial begin
    #10 begin
    clk<=1;
    reset<=`RESET_ENABLE;
    end
    #(STEP*3/4)
    #STEP begin
    reset<=`RESET_DISABLE;
   
    #STEP
     m0_req_<=`DISABLE_;
     m2_req_<=`DISABLE_;
     m3_req_<=`DISABLE_;
     m1_req_<=`ENABLE_;
      #STEP
     m0_req_<=`DISABLE_;
     m1_req_<=`DISABLE_;
     m3_req_<=`DISABLE_;
     m2_req_<=`ENABLE_;
      #STEP
     m0_req_<=`DISABLE_;
     m1_req_<=`DISABLE_;
     m2_req_<=`DISABLE_;
     m3_req_<=`ENABLE_;
     
      #STEP
     m3_req_<=`DISABLE_;
     m1_req_<=`DISABLE_;
     m2_req_<=`DISABLE_;
     m0_req_<=`ENABLE_;
   /*
     #STEP
     m0_addr<=`WORD_ADDR_W'h0;
     m0_as_ <=`ENABLE_;
     m0_rw<=`WRITE;
     m0_wr_data<=32'hffff;
     s0_rd_data<=32'h0000;
     s0_rdy_<=`ENABLE_;
     */
      #STEP
           m0_addr<={{{3'b000}},{16'b0},{{11'b00000_000001}}};
           m0_as_ <=`ENABLE_;
           m0_rw<=`READ;
         m0_wr_data<=32'hffff_ffff;
        
    end
    #STEP
    $finish;
    
  end
    
    
    
endmodule

测试结果:
先显示
先显示ROM的0-2号地址的数据,我们testbench这边控制的是memdata[1]输出
在这里插入图片描述
其中m0_addr选取的为1号地址,m_rd_data为输出数据
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
输出对应的为memdata[1],
仿真验证成功.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值