VERDVANA'S BLOG Verdvana

CPU设计之总线


1 前言

        总线负责将CPU、内存、IO等相互连接的共享通道。

  • 开发环境:
    • Quartus Prime Standard 18.1
  • 操作系统:
    • Windows 10 Pro 1903

2 总线总体规划

        本设计的总线主控为4通道,总线从属为8通道。结构如图所示:

img1

        总线控制器的左边的接口接总线主控,右边的接口接从属设备。两边接口的浅色部分为接多条总线设备,深色部分为接常用的总线,也就是选中后的总线。红色虚线上半部分负责主控选通,下半部分负责从属设备选通。

        接口信号如下:

信号名 位宽        方向 含义
clk 1 input 时钟
rst_n 1 input 异步复位
m*_req_ 1×4 input 总线使用请求信号
m*_grnt_ 1×4 output 总线使用许可信号
m*_as_ 1×4 input 主控设备访问有效信号
m*_rw 1×4 input 主控设备读写控制信号
m*_wr_data        32×4 input 写入数据
m*_addr 30×4 input 主控设备要访问的地址
m_rdy_ 1 output 访问结束信号
m_rd_data 32 output 读取数据
s_as_ 1 output 访问从属设备有效信号
s_rw 1 output 控制从属设备读写信号
s_wr_data 32 output        写入从属设备数据
s_addr 30 output 访问从属设备地址
s*_cs_ 1×8 output 从属设备访问有效信号
s*_rdy_ 1×8 input 从属设备访问结束信号
s*_rd_data 32×8 input 从属设备读取数据

        其中,总线仲裁器根据四个主控发来的请求信号来判断当前许可哪条主控使用总线。一旦总线主控被许可使用总线,即可以开始总线访问。总线主机多路复用器根据仲裁后的结果选通那一组主机总线。地址解码器通过选通后的主机访问地址判断访问哪一个从机。总线从属多路复用器根据解码后的结果选通那一组从机总线。


3 总线仲裁器

3.1 接口

        总线仲裁器要根据四个主控的请求信号生成四个主控的许可信号,所以有以下信号接口:

信号名        位宽        方向 含义
clk 1 input 时钟
rst_n 1 input 异步复位
m0_req_ 1 input 0号主控请求信号
m0_grnt_ 1 output 0号总线使用许可信号
m1_req_ 1 input 1号主控请求信号
m1_grnt_ 1 output        1号总线使用许可信号
m2_req_ 1 input 2号主控请求信号
m2_grnt_ 1 output 2号总线使用许可信号
m3_req_ 1 input 3号主控请求信号
m3_grnt_ 1 output 3号总线使用许可信号

3.2 实现

        四个请求信号是有优先级的,默认情况下许可0号主控。

        当前总线所有者为0号时,优先顺序为:0>1>2>3。也就是如果0号还在请求,那么总线所有者保持为0号总线;如果0号没有请求,1号请求,当前总线所有者变为1号;如果0号、1号没请求,2号请求,那么当前总线所有者变为2号;如果0号、1号、2号没请求,3号请求,那么当前总线所有者变为3号;如果都不请求,则恢复默认状态,即许可0号主控。

        当前总线所有者为1号时,优先顺序为:1>2>3>0;当前总线所有者为2号时,优先顺序为:2>3>0>1;当前总线所有者为3号时,优先顺序为:3>0>1>2。

        所以用状态机来完成:

//------------------------------------------------------------------------------
//
//Module Name:					bus_arbiter.sv
//Department:					Xidian University
//Function Description:	        总线仲裁器 
//
//------------------------------------------------------------------------------
//
//Version 	Design		Coding		Simulata	  Review		Rel data
//V1.0		Verdvana	Verdvana	Verdvana		  			2020-1-31
//
//-----------------------------------------------------------------------------------
//
//Version	Modified History
//V1.0		
//
//-----------------------------------------------------------------------------------

`timescale 1ns/1ns

module bus_arbiter (
	/**********时钟&复位**********/
	input           clk,	    //时钟
	input      	    rst_n,	    //异步复位
	/**********仲裁信号***********/
	// 0号总线主控
	input      	    m0_req_,    //请求信号
	output reg      m0_grnt_,   //总线使用许可信号
	// 1号总线主控
	input      	    m1_req_,    //请求信号
	output reg	    m1_grnt_,   //总线使用许可信号
	// 2号总线主控
	input      	    m2_req_,    //请求信号
	output reg	    m2_grnt_,   //总线使用许可信号
	// 3号总线主控
	input      	    m3_req_,    //请求信号
	output reg	    m3_grnt_    //总线使用许可信号
);

    //=========================================================
    //仲裁状态机(三段式)

    //---------------------------------------------------------
    //枚举所有状态(reg四状态)

    enum reg [1:0] {
        BUS_OWNER_MASTER_0,         //总线所有者:0号总线主控
        BUS_OWNER_MASTER_1,         //总线所有者:1号总线主控
        BUS_OWNER_MASTER_2,         //总线所有者:2号总线主控
        BUS_OWNER_MASTER_3          //总线所有者:3号总线主控
    } state,next_state;

    //---------------------------------------------------------
    //第一段 状态译码

    always_comb begin
        case (state)
            BUS_OWNER_MASTER_0: begin                   //当前总线所有者为0号时,优先顺序为:0>1>2>3
                if(!m0_req_)                            //如果0号仍在请求
                    next_state = BUS_OWNER_MASTER_0;    //当前总线所有者继续为0号
                else if(!m1_req_)                       //0号没有请求,1号请求
                    next_state = BUS_OWNER_MASTER_1;    //当前总线所有者变为1号
                else if(!m2_req_)                       //0号、1号没请求,2号请求
                    next_state = BUS_OWNER_MASTER_2;    //当前总线所有者变为2号
                else if(!m3_req_)                       //0号、1号、2号没请求,3号请求
                    next_state = BUS_OWNER_MASTER_3;    //当前总线所有者变为3号
                else                                    //都不请求
                    next_state = BUS_OWNER_MASTER_0;    //恢复为默认状态
            end

            BUS_OWNER_MASTER_1: begin                   //当前总线所有者为1号时,优先顺序为:1>2>3>0
                if(!m1_req_)
                    next_state = BUS_OWNER_MASTER_1;    
                else if(!m2_req_)
                    next_state = BUS_OWNER_MASTER_2;
                else if(!m3_req_)
                    next_state = BUS_OWNER_MASTER_3;
                else if(!m0_req_)
                    next_state = BUS_OWNER_MASTER_0;
                else
                    next_state = BUS_OWNER_MASTER_0;
            end

            BUS_OWNER_MASTER_2: begin                   //当前总线所有者为2号时,优先顺序为:2>3>0>1
                if(!m2_req_)
                    next_state = BUS_OWNER_MASTER_2;
                else if(!m3_req_)
                    next_state = BUS_OWNER_MASTER_3;
                else if(!m0_req_)
                    next_state = BUS_OWNER_MASTER_0;
                else if(!m1_req_)
                    next_state = BUS_OWNER_MASTER_1;
                else
                    next_state = BUS_OWNER_MASTER_0;
            end

            BUS_OWNER_MASTER_3: begin                   //当前总线所有者为3号时,优先顺序为:3>0>1>2
                if(!m3_req_)
                    next_state = BUS_OWNER_MASTER_3;
                else if(!m0_req_)
                    next_state = BUS_OWNER_MASTER_0;
                else if(!m1_req_)
                    next_state = BUS_OWNER_MASTER_1;
                else if(!m2_req_)
                    next_state = BUS_OWNER_MASTER_2;
                else
                    next_state = BUS_OWNER_MASTER_0;
            end

            default: begin                              //恢复默认
                next_state = BUS_OWNER_MASTER_0;
            end
        endcase
    end

    //---------------------------------------------------------
    //第二段 更新状态寄存器

    always_ff@(posedge clk, negedge rst_n)begin
        if(!rst_n)
            state <= BUS_OWNER_MASTER_0;
        else
            state <= next_state;
    end

    //---------------------------------------------------------
    //第三段 利用状态寄存器输出控制结果

    always_comb begin
        {m0_grnt_,m1_grnt_,m2_grnt_,m3_grnt_} = '1;     //产生默认值,防止产生锁存器
        case (state)
            BUS_OWNER_MASTER_0: {m0_grnt_,m1_grnt_,m2_grnt_,m3_grnt_} = 4'b0111;
            BUS_OWNER_MASTER_1: {m0_grnt_,m1_grnt_,m2_grnt_,m3_grnt_} = 4'b1011;
            BUS_OWNER_MASTER_2: {m0_grnt_,m1_grnt_,m2_grnt_,m3_grnt_} = 4'b1101;
            BUS_OWNER_MASTER_3: {m0_grnt_,m1_grnt_,m2_grnt_,m3_grnt_} = 4'b1110;
            default:            {m0_grnt_,m1_grnt_,m2_grnt_,m3_grnt_} = 4'b0111;
        endcase
    end

endmodule


4 总线主控用多路复用器

4.1 接口

        其实就是一个多路选择器,控制信号为上一节中产生的许可信号,四个主控的各种信号被选通为一组:

信号名 位宽        方向 含义
m0_grnt_ 1 input 0号总线使用许可信号
m0_as_ 1 input 0号主控设备访问有效信号
m0_rw 1 input 0号主控设备读写控制信号
m0_wr_data        32 input 0号主控写入数据
m0_addr 30 input 0号主控设备要访问的地址
m1_grnt_ 1 input 1号总线使用许可信号
m1_as_ 1 input 1号主控设备访问有效信号
m1_rw 1 input 1号主控设备读写控制信号
m1_wr_data        32 input 1号主控写入数据
m1_addr 30 input 1号主控设备要访问的地址
m2_grnt_ 1 input 2号总线使用许可信号
m2_as_ 1 input 2号主控设备访问有效信号
m2_rw 1 input 2号主控设备读写控制信号
m2_wr_data        32 input 2号主控写入数据
m2_addr 30 input 2号主控设备要访问的地址
m3_grnt_ 1 input 3号总线使用许可信号
m3_as_ 1 input 3号主控设备访问有效信号
m3_rw 1 input 3号主控设备读写控制信号
m3_wr_data        32 input 3号主控写入数据
m3_addr 30 input 3号主控设备要访问的地址
s_as_ 1 output 访问从属设备有效信号
s_rw 1 output 控制从属设备读写信号
s_wr_data 32 output        写入从属设备数据
s_addr 30 output 访问从属设备地址

4.2 实现

        控制信号在上一模块(主控仲裁器)生成,通过判断这四个信号就可以知道选通哪一路:

//------------------------------------------------------------------------------
//
//Module Name:					bus_master_mux.sv
//Department:					Xidian University
//Function Description:	        总线主控用多路复用器 
//
//------------------------------------------------------------------------------
//
//Version 	Design		Coding		Simulata	  Review		Rel data
//V1.0		Verdvana	Verdvana	Verdvana		  			2020-1-29
//
//-----------------------------------------------------------------------------------
//
//Version	Modified History
//V1.0		
//
//-----------------------------------------------------------------------------------

`timescale 1ns/1ns

module bus_master_mux #(
    parameter   DATA_W =   32,        	//数据宽度
				ADDR_W =   30			//地址宽度
)(
	/********** 总线主信号 **********/
	// 0号总线主控
	input      [ADDR_W-1:0] m0_addr,   	//访问地址
	input  				   	m0_as_,    	//从属访问选择信号
	input  				   	m0_rw,	    //读/写表示信号
	input      [DATA_W-1:0] m0_wr_data,	//写入数据
	input  				   	m0_grnt_,  	//总线使用许可信号
	// 1号总线主控
	input      [ADDR_W-1:0] m1_addr,	//访问地址
	input  				   	m1_as_,    	//从属访问选择信号
	input  					m1_rw,	    //读/写表示信号
	input      [DATA_W-1:0] m1_wr_data,	//写入数据
	input  				   	m1_grnt_,  	//总线使用许可信号
	// 2号总线主控
	input      [ADDR_W-1:0] m2_addr,   	//访问地址
	input  				   	m2_as_,    	//从属访问选择信号
	input  				  	m2_rw,	    //读/写表示信号
	input      [DATA_W-1:0] m2_wr_data,	//写入数据
	input  					m2_grnt_,  	//总线使用许可信号
	// 3号总线主控
	input      [ADDR_W-1:0] m3_addr,   	//访问地址
	input  					m3_as_,    	//从属访问选择信号
	input  				  	m3_rw,		//读/写表示信号
	input      [DATA_W-1:0] m3_wr_data,	//写入数据
	input  				  	m3_grnt_,  	//总线使用许可信号
	/********** 总线从机常用信号 **********/
	output reg [ADDR_W-1:0] s_addr,    	//访问地址
	output reg				s_as_,	 	//从属访问选择信号
	output reg				s_rw,	   	//读/写表示信号
	output reg [DATA_W-1:0]	s_wr_data  	//写入数据
);

	always_comb begin
		case ({m0_grnt_,m1_grnt_,m2_grnt_,m3_grnt_})
			4'b0111: begin			 // 0号总线主控
				s_addr	  	= m0_addr;
				s_as_	  	= m0_as_;
				s_rw	  	= m0_rw;
				s_wr_data 	= m0_wr_data;
			end 
			4'b1011: begin 	// 1号总线主控
				s_addr	  	= m1_addr;
				s_as_	  	= m1_as_;
				s_rw	  	= m1_rw;
				s_wr_data 	= m1_wr_data;
			end 
			4'b1101: begin 	// 2号总线主控
				s_addr	  	= m2_addr;
				s_as_	  	= m2_as_;
				s_rw	  	= m2_rw;
				s_wr_data 	= m2_wr_data;
			end 
			4'b1110: begin 	// 3号总线主控
				s_addr	  	= m3_addr;
				s_as_	  	= m3_as_;
				s_rw	  	= m3_rw;
				s_wr_data 	= m3_wr_data;
			end 
			default: begin				// 默认值
				s_addr	  	= '0;
				s_as_	  	= '1;
				s_rw	  	= '1;   //1是写,0是读
				s_wr_data 	= '0;
			end
		endcase
	end

endmodule


5 地址解码器

5.1 接口

        因为要连接八个从属设备,所以将地址空间八等分,地址映射如下表:

总线从属        地址 地址最高3位        分配
0 0x0000_0000 ~ 0x1FFF_FFFF        3’b000 ROM
1 0x2000_0000 ~ 0x3FFF_FFFF 3’b001 SPM
2 0x4000_0000 ~ 0x5FFF_FFFF 3’b010 Timer
3 0x6000_0000 ~ 0x7FFF_FFFF 3’b011 UART
4 0x8000_0000 ~ 0x9FFF_FFFF 3’b100 GPIO
5 0xA000_0000 ~ 0xBFFF_FFFF 3’b101 没想好
6 0xC000_0000 ~ 0xDFFF_FFFF 3’b110 ……
7 0xE000_0000 ~ 0xFFFF_FFFF 3’b111 ……

        可以看出每一种设备地址的前三位是相同的,既在总线主控用多路复用器选通后的信号组里的地址的最高三位为选通从机的地址:

        所以接口为:

信号名 位宽        方向 含义
s_addr        30 input 访问从属设备地址
s0_cs_ 1 output        从属设备0访问有效信号
s1_cs_ 1 output 从属设备1访问有效信号
s2_cs_ 1 output 从属设备2访问有效信号
s3_cs_ 1 output 从属设备3访问有效信号
s4_cs_ 1 output 从属设备4访问有效信号
s5_cs_ 1 output 从属设备5访问有效信号
s6_cs_ 1 output 从属设备6访问有效信号
s7_cs_ 1 output 从属设备7访问有效信号

5.2 实现

        就是根据地址的高三位来判断八个片选信号哪一个是低电平:

//------------------------------------------------------------------------------
//
//Module Name:					bus_addr_dec.sv
//Department:					Xidian University
//Function Description:	        地址解码器 
//
//------------------------------------------------------------------------------
//
//Version 	Design		Coding		Simulata	  Review		Rel data
//V1.0		Verdvana	Verdvana	Verdvana		  			2020-1-30
//
//-----------------------------------------------------------------------------------
//
//Version	Modified History
//V1.0		
//
//-----------------------------------------------------------------------------------

`timescale 1ns/1ns

/********** 模块 **********/
module bus_addr_dec #(
    parameter   ADDR_W =   30      	//地址宽度
)(
	/********** 地址 **********/
	input    [ADDR_W-1:0]	s_addr,	//地址
	/********** 片选 **********/
	output reg				s0_cs_, //0号总线从机
	output reg				s1_cs_, //1号总线从机
	output reg				s2_cs_, //2号总线从机
	output reg				s3_cs_, //3号总线从机
	output reg				s4_cs_, //4号总线从机
	output reg				s5_cs_, //5号总线从机
	output reg				s6_cs_, //6号总线从机
	output reg				s7_cs_  //7号总线从机
);


	wire [2:0] s_index = s_addr[ADDR_W-1-:3];	//总线从机索引

	always_comb begin
		{s0_cs_,s1_cs_,s2_cs_,s3_cs_,s4_cs_,s5_cs_,s6_cs_,s7_cs_} = '1;	//初始化
		case (s_index)
			3'h0: begin // 0号总线从机
				{s0_cs_,s1_cs_,s2_cs_,s3_cs_,s4_cs_,s5_cs_,s6_cs_,s7_cs_} = 8'b0111_1111;
			end
			3'h1: begin // 1号总线从机
				{s0_cs_,s1_cs_,s2_cs_,s3_cs_,s4_cs_,s5_cs_,s6_cs_,s7_cs_} = 8'b1011_1111;
			end
			3'h2: begin // 2号总线从机
				{s0_cs_,s1_cs_,s2_cs_,s3_cs_,s4_cs_,s5_cs_,s6_cs_,s7_cs_} = 8'b1101_1111;
			end
			3'h3: begin // 3号总线从机
				{s0_cs_,s1_cs_,s2_cs_,s3_cs_,s4_cs_,s5_cs_,s6_cs_,s7_cs_} = 8'b1110_1111;
			end
			3'h4: begin // 4号总线从机
				{s0_cs_,s1_cs_,s2_cs_,s3_cs_,s4_cs_,s5_cs_,s6_cs_,s7_cs_} = 8'b1111_0111;
			end
			3'h5: begin // 5号总线从机
				{s0_cs_,s1_cs_,s2_cs_,s3_cs_,s4_cs_,s5_cs_,s6_cs_,s7_cs_} = 8'b1111_1011;
			end
			3'h6: begin // 6号总线从机
				{s0_cs_,s1_cs_,s2_cs_,s3_cs_,s4_cs_,s5_cs_,s6_cs_,s7_cs_} = 8'b1111_1101;
			end
			3'h7: begin // 7号总线从机
				{s0_cs_,s1_cs_,s2_cs_,s3_cs_,s4_cs_,s5_cs_,s6_cs_,s7_cs_} = 8'b1111_1110;
			end
			default: begin	//默认
				{s0_cs_,s1_cs_,s2_cs_,s3_cs_,s4_cs_,s5_cs_,s6_cs_,s7_cs_} = 8'b0111_1111;
			end
		endcase
	end

endmodule

6 总线从属用多路复用器

6.1 接口

        和总线主控用多路复用器类似,通过从属设备的片选信号选择当前选通哪一路从属设备信号组,接口:

信号名 位宽        方向 含义
m_rdy_ 1 output        访问结束信号
m_rd_data        32 output 读取数据
s0_cs_ 1 input 从属设备0访问有效信号
s0_rdy_ 1 input 从属设备0访问结束信号
s0_rd_data 32 input 从属设备0读取数据
s1_cs_ 1 input 从属设备1访问有效信号
s1_rdy_ 1 input 从属设备1访问结束信号
s1_rd_data 32 input 从属设备1读取数据
s2_cs_ 1 input 从属设备2访问有效信号
s2_rdy_ 1 input 从属设备2访问结束信号
s2_rd_data 32 input 从属设备2读取数据
s3_cs_ 1 input 从属设备3访问有效信号
s3_rdy_ 1 input 从属设备3访问结束信号
s3_rd_data 32 input 从属设备3读取数据
s4_cs_ 1 input 从属设备4访问有效信号
s4_rdy_ 1 input 从属设备4访问结束信号
s4_rd_data 32 input 从属设备4读取数据
s5_cs_ 1 input 从属设备5访问有效信号
s5_rdy_ 1 input 从属设备5访问结束信号
s5_rd_data 32 input 从属设备5读取数据
s6_cs_ 1 input 从属设备6访问有效信号
s6_rdy_ 1 input 从属设备6访问结束信号
s6_rd_data 32 input 从属设备6读取数据
s7_cs_ 1 input 从属设备7访问有效信号
s7_rdy_ 1 input 从属设备7访问结束信号
s7_rd_data 32 input 从属设备7读取数据

6.2 实现

        和总线主控用多路复用器类似:

//------------------------------------------------------------------------------
//
//Module Name:					bus_slave_mux.sv
//Department:					Xidian University
//Function Description:	        总线从属用多路复用器 
//
//------------------------------------------------------------------------------
//
//Version 	Design		Coding		Simulata	  Review		Rel data
//V1.0		Verdvana	Verdvana	Verdvana		  			2020-1-29
//
//-----------------------------------------------------------------------------------
//
//Version	Modified History
//V1.0		
//
//-----------------------------------------------------------------------------------

`timescale 1ns/1ns

/********** 模块 **********/
module bus_slave_mux #(
    parameter   DATA_W =   32          	//数据宽度
)(
	/********** 片选 **********/
	input  				   	s0_cs_,		//0号总线从机
	input  				   	s1_cs_,		//1号总线从机
	input  				   	s2_cs_,		//2号总线从机
	input  				   	s3_cs_,		//3号总线从机
	input  				   	s4_cs_,		//4号总线从机
	input  				   	s5_cs_,		//5号总线从机
	input  				   	s6_cs_,		//6号总线从机
	input  				   	s7_cs_,		//7号总线从机
	/********** 总线从机信号 **********/
	// 0号总线从机
	input      [DATA_W-1:0] s0_rd_data,	//读出数据
	input  				   	s0_rdy_,   	//访问结束表示信号
	// 1号总线从机
	input      [DATA_W-1:0] s1_rd_data,	//读出数据
	input  				   	s1_rdy_,	//访问结束表示信号
	// 2号总线从机
	input      [DATA_W-1:0] s2_rd_data,	//读出数据
	input  				   	s2_rdy_,	//访问结束表示信号
	// 3号总线从机
	input      [DATA_W-1:0] s3_rd_data,	//读出数据
	input  				   	s3_rdy_,   	//访问结束表示信号
	// 4号总线从机
	input      [DATA_W-1:0] s4_rd_data,	//读出数据
	input  				   	s4_rdy_,	//访问结束表示信号
	// 5号总线从机
	input      [DATA_W-1:0] s5_rd_data,	//读出数据
	input  				   	s5_rdy_,   	//访问结束表示信号
	// 6号总线从机
	input      [DATA_W-1:0] s6_rd_data,	//读出数据
	input  				   	s6_rdy_,   	//访问结束表示信号
	// 7号总线从机
	input      [DATA_W-1:0] s7_rd_data,	//读出数据
	input  				  	s7_rdy_,   	//访问结束表示信号
	/********** 总线主控通用信号 **********/
	output reg [DATA_W-1:0]	m_rd_data, 	//读出数据
	output reg				m_rdy_	    //访问结束表示信号
);


	always_comb begin
		case ({s0_cs_,s1_cs_,s2_cs_,s3_cs_,s4_cs_,s5_cs_,s6_cs_,s7_cs_}) 
			8'b0111_1111: begin	//0号总线从机
				m_rd_data = s0_rd_data;
				m_rdy_	  = s0_rdy_;
			end 
        	8'b1011_1111: begin //1号总线从机
				m_rd_data = s1_rd_data;
				m_rdy_	  = s1_rdy_;
			end 
        	8'b1101_1111: begin //2号总线从机
				m_rd_data = s2_rd_data;
				m_rdy_	  = s2_rdy_;
			end 
        	8'b1110_1111: begin //3号总线从机
				m_rd_data = s3_rd_data;
				m_rdy_	  = s3_rdy_;
			end 
        	8'b1111_0111: begin //4号总线从机
				m_rd_data = s4_rd_data;
				m_rdy_	  = s4_rdy_;
			end 
        	8'b1111_1011: begin //5号总线从机
				m_rd_data = s5_rd_data;
				m_rdy_	  = s5_rdy_;
			end 
        	8'b1111_1101: begin //6号总线从机
				m_rd_data = s6_rd_data;
				m_rdy_	  = s6_rdy_;
			end 
        	8'b1111_1110: begin //7号总线从机
				m_rd_data = s7_rd_data;
				m_rdy_	  = s7_rdy_;
			end 
        	default:	  begin	//默认值
				m_rd_data = '0;
				m_rdy_	  = '1;
			end
		endcase
	end

endmodule

7 总线顶层

        按照总体规划那一节设计接口,然后将以上四个模块连起来即可:

//------------------------------------------------------------------------------
//
//Module Name:					bus.sv
//Department:					Xidian University
//Function Description:	        总线顶层模块 
//
//------------------------------------------------------------------------------
//
//Version 	Design		Coding		Simulata	  Review		Rel data
//V1.0		Verdvana	Verdvana	Verdvana		  			2020-1-31
//
//-----------------------------------------------------------------------------------
//
//Version	Modified History
//V1.0		
//
//-----------------------------------------------------------------------------------

`timescale 1ns/1ns

module bus #(
    parameter   DATA_W =   32,       //数据宽度
				ADDR_W =   30        //地址宽度
)(
	/********** 时钟 & 复位 **********/
	input  			    clk,	    //时钟
	input  			    rst_n,	    //异步复位
	/********** 总线主信号 **********/
	// 总线主通用信号
	output [DATA_W-1:0] m_rd_data,  //读数据
	output 			    m_rdy_,	    //访问结束表示信号
	// 0号总线主控
	input  			    m0_req_,    //总线请求
	input  [ADDR_W-1:0] m0_addr,    //访问地址
	input  				m0_as_,	    //从属访问选择信号
	input  			    m0_rw,	    //读/写表示信号
	input  [DATA_W-1:0] m0_wr_data, //写入数据
	output 			    m0_grnt_,   //总线使用许可信号
	// 1号总线主控
	input  			    m1_req_,    //总线请求
	input  [ADDR_W-1:0] m1_addr,    //访问地址
	input  			    m1_as_,	    //从属访问选择信号
	input  			    m1_rw,	    //读/写表示信号
	input  [DATA_W-1:0] m1_wr_data, //写入数据
	output 			    m1_grnt_,   //总线使用许可信号
	// 2号总线主控
	input  			    m2_req_,    //总线请求
	input  [ADDR_W-1:0] m2_addr,    //访问地址
	input  			    m2_as_,	    //从属访问选择信号
	input  			    m2_rw,	    //读/写表示信号
	input  [DATA_W-1:0] m2_wr_data, //写入数据
	output 			    m2_grnt_,   //总线使用许可信号
	// 3号总线主控
	input  			    m3_req_,    //总线请求
	input  [ADDR_W-1:0] m3_addr,    //访问地址
	input  			    m3_as_,	    //从属访问选择信号
	input  			    m3_rw,	    //读/写表示信号
	input  [DATA_W-1:0] m3_wr_data, //写入数据
	output 			    m3_grnt_,   //总线使用许可信号
	/********** 总线从机信号 **********/
	// 总线从机常用信号
	output [ADDR_W-1:0] s_addr,	    //地址
	output 			    s_as_,	    //从属访问选择信号
	output 			    s_rw,	   	//读/写表示信号
	output [DATA_W-1:0] s_wr_data,  //写入数据
	// 0号总线从属
	input  [DATA_W-1:0] s0_rd_data, //读取数据
	input  			    s0_rdy_,    //访问结束表示信号
	output 			    s0_cs_,	    //从属访问选择信号
	// 1号总线从属
	input  [DATA_W-1:0] s1_rd_data, //读取数据
	input  			    s1_rdy_,    //访问结束表示信号
	output 			    s1_cs_,	    //从属访问选择信号
	// 2号总线从属
	input  [DATA_W-1:0] s2_rd_data, //读取数据
	input  			    s2_rdy_,    //访问结束表示信号
	output 			    s2_cs_,	    //从属访问选择信号
	// 3号总线从属
	input  [DATA_W-1:0] s3_rd_data, //读取数据
	input  			    s3_rdy_,    //访问结束表示信号
	output 			    s3_cs_,	    //从属访问选择信号
	// 4号总线从属
	input  [DATA_W-1:0] s4_rd_data, //读取数据
	input  			    s4_rdy_,    //访问结束表示信号
	output 			    s4_cs_,	    //从属访问选择信号
	// 5号总线从属
	input  [DATA_W-1:0] s5_rd_data, //读取数据
	input  			    s5_rdy_,    //访问结束表示信号
	output 			    s5_cs_,	    //从属访问选择信号
	// 6号总线从属
	input  [DATA_W-1:0] s6_rd_data, //读取数据
	input  			    s6_rdy_,    //访问结束表示信号
	output 			    s6_cs_,	    //从属访问选择信号
	// 7号总线从属
	input  [DATA_W-1:0] s7_rd_data, //读取数据
	input  			    s7_rdy_,    //访问结束表示信号
	output 			    s7_cs_	    //从属访问选择信号
);

	//=================================================
    //总线仲裁器
	bus_arbiter u_bus_arbiter (.*);

	//=================================================
	//总线主机多路复用器
	bus_master_mux #(
        .DATA_W(DATA_W),
        .ADDR_W(ADDR_W)
    )u_bus_master_mux (.*);

	//=================================================
	//地址解码器
	bus_addr_dec #(
        .ADDR_W(ADDR_W)
    )u_bus_addr_dec (.*);

	//=================================================
	//总线从属多路复用器
	bus_slave_mux #(
        .DATA_W(DATA_W)
    )u_bus_slave_mux (.*);

endmodule

        告辞。