《从0开始设计和实现CPU》bus总线顶层模块设计

1.总线Code管理
  • 首先,对前面编写的代码进行一个管理创建一个文件夹命名为bus存放总线设计的代码,
    • 在此目录下创建inc文件夹来存放bus所需要的头文件,
    • 总线的实现的代码放在bus文件下。
  • 在这里插入图片描述在这里插入图片描述
2.总线设计概要

1. bus_arbiter.v :实现了总线总裁器的设计,解决了4个总线主控在请求总线时,总线该赋予哪个主控的仲裁问题。

2. bus_master_mux:实现了总线主控多路复用器的设计,这个是基于总线仲裁器的总线赋予信号:赋予信号一旦选择某个主控,该主控成为总线的使用者,该主控的有关信号将输出到总线上。

这里以举个例子,当总线赋予信号m0_grnt使能,也就是赋予信号选择了0号主控,0号主控就把相关信号输出总线上。相关信号指的是地址信号(m0_addr),地址选通(m0_as),读写信号(m0_rw)和写入的数据(m0_wr_data)。

为什么要用总线这个机制?不能每个主控与从属之间都搞一条线来进行通信吗?我的答案是:可以,前提你得很有钱!总线就像公路,是属于行人和车辆之间共享的,选择信号就像红绿灯,来选择某个时刻这条公路是属于行人还是车辆。后面的地址解码器也是这个原理。

3. bus_addr_dec.v:实现了地址解码器(亦叫做地址译码器)。是基于主控的地址信号(上面提到),这里依然以0号主控来举例。当0号主控将地址信号m0_addr输出到总线上时,地址解码器通过这个地址信号来选择0号主控所需要的几号总线从属(这里作者一共设计了7个总线从属)
在这里插入图片描述
这个过程我们称为片选过程 ,IIC通信之间的片选信号也是这个原理。

4. bus_slave_mux.v:实现了总线从属多路复用器的设计。当地址解码器片选0号总线从属时(也就是s0_cs信号使能),总线从属多路复用器将根据s0_cs信号,将来自0号总线从属输出的s0_rd_data(读出的数据)与s0_rdy(就绪信号)发送到总线上,来达到通信的目的,这就是总线的具体设计。

3.总线顶层模块源码

总线顶层模块我们命名为bus , 由总线仲裁器,总线主控多路复用器,地址解码器,总线从属多路复用器组成。这些单独模块我们在前面一个个的实现了,最后在bus这个总线顶层模块中,例化这些单独的模块。

`include "stddef.h"
`include "global_config.h"

`include "bus.h"

module bus(

      input  wire     clk,     //时钟
      input  wire     reset,   //异步复位 
      
	 /*留下一个问题,m_rd_data这里为什么是wire类型?
	 bus_slave_mux.v里面为什么是reg类型?*/
      output wire [`WordDataBus] m_rd_data,  //读出的数据 
	  output wire				      m_rdy_,	   //就绪
		
     /****0号总线主控****/
	  input  wire                 m0_req_,   //0号总线主控_请求总线
	  input  wire [`WordAddrBus]  m0_addr,   //地址
	  input  wire                 m0_as_,    //地址选通
      input  wire                 m0_rw,     //读/写
      input  wire [`WordDataBus]  m0_wr_data,//写入的数据
      output wire                 m0_grnt_,  //赋予总线 
		
		/****1号总线主控****/
	  input  wire                 m1_req_,   //1号总线主控_请求总线
	  input  wire [`WordAddrBus]  m1_addr,   //地址
	  input  wire                 m1_as_,    //地址选通
      input  wire                 m1_rw,     //读/写
      input  wire [`WordDataBus]  m1_wr_data,//写入的数据
      output wire                 m1_grnt_,  //赋予总线 
		
		/****2号总线主控****/
	  input  wire                 m2_req_,   //2号总线主控_请求总线
	  input  wire [`WordAddrBus]  m2_addr,   //地址
	  input  wire                 m2_as_,    //地址选通
      input  wire                 m2_rw,     //读/写
      input  wire [`WordDataBus]  m2_wr_data,//写入的数据
      output wire                 m2_grnt_,  //赋予总线 
		
		/****3号总线主控****/
	  input  wire                 m3_req_,   //3号总线主控_请求总线
	  input  wire [`WordAddrBus]  m3_addr,   //地址
	  input  wire                 m3_as_,    //地址选通
      input  wire                 m3_rw,     //读/写
      input  wire [`WordDataBus]  m3_wr_data,//写入的数据
      output wire                 m3_grnt_,  //赋予总线 
      /*m_grnt_相对于总线仲裁器arbiter是输出信号,
	   但相对于master_mux总线主控多路复用器是输入信号!*/
		
		
		   /****共享信号总线从属****/
		output wire [`WordAddrBus]  s_addr,    //地址 29:0
		output wire                 s_as_,     //地址选通
        output wire                 s_rw,      //读/写
        output wire [`WordDataBus]  s_wr_data,  //写入的数据 31:0
	
	      /****0号总线从属****/ 
		input  wire [`WordDataBus]  s0_rd_data, //读出的数据
		input  wire                 s0_rdy_,    //就绪
        output wire                 s0_cs_,     //片选
		
		   /****1号总线从属****/ 
		input  wire [`WordDataBus]  s1_rd_data, //读出的数据
		input  wire                 s1_rdy_,    //就绪
        output wire                 s1_cs_,     //片选
		
		   /****2号总线从属****/ 
		input  wire [`WordDataBus]  s2_rd_data, //读出的数据
		input  wire                 s2_rdy_,    //就绪
        output wire                 s2_cs_,     //片选
		
		   /****3号总线从属****/ 
		input  wire [`WordDataBus]  s3_rd_data, //读出的数据
		input  wire                 s3_rdy_,    //就绪
        output wire                 s3_cs_,     //片选
		
		   /****4号总线从属****/ 
		input  wire [`WordDataBus]  s4_rd_data, //读出的数据
		input  wire                 s4_rdy_,    //就绪
        output wire                 s4_cs_,     //片选
		
		   /****5号总线从属****/ 
		input  wire [`WordDataBus]  s5_rd_data, //读出的数据
		input  wire                 s5_rdy_,    //就绪
        output wire                 s5_cs_,     //片选
		
		   /****6号总线从属****/ 
		input  wire [`WordDataBus]  s6_rd_data, //读出的数据
		input  wire                 s6_rdy_,    //就绪
        output wire                 s6_cs_,     //片选
		
		   /****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_),   //0号总线主控_请求总线
      .m0_grnt_   (m0_grnt_),  //0号总线主控_赋予总线
     
	   .m1_req_    (m1_req_),   //1号总线主控_请求总线
      .m1_grnt_   (m1_grnt_),  //1号总线主控_赋予总线
     
	   .m2_req_    (m2_req_),   //2号总线主控_请求总线
      .m2_grnt_   (m2_grnt_),  //2号总线主控_赋予总线
	  
	   .m3_req_    (m3_req_),   //3号总线主控_请求总线
      .m3_grnt_   (m3_grnt_)   //3号总线主控_赋予总线

	);

	
	//例化bus_master_mux模块
   bus_master_mux bus_master_mux(
	
	 /****0号总线主控****/
	   .m0_addr     (m0_addr),   //地址
	   .m0_as_      (m0_as_),    //地址选通
       .m0_rw       (m0_rw),     //读/写
       .m0_wr_data  (m0_wr_data),//写入的数据
       .m0_grnt_    (m0_grnt_),  //赋予总线
		
	   .m1_addr     (m1_addr),   //地址
	   .m1_as_      (m1_as_),    //地址选通
       .m1_rw       (m1_rw),     //读/写
       .m1_wr_data  (m1_wr_data),//写入的数据
       .m1_grnt_    (m1_grnt_),  //赋予总线
		
	   .m2_addr     (m2_addr),   //地址
	   .m2_as_      (m2_as_),    //地址选通
       .m2_rw       (m2_rw),     //读/写
       .m2_wr_data  (m2_wr_data),//写入的数据
       .m2_grnt_    (m2_grnt_),  //赋予总线
		
	   .m3_addr     (m3_addr),   //地址
	   .m3_as_      (m3_as_),    //地址选通
       .m3_rw       (m3_rw),     //读/写
       .m3_wr_data  (m3_wr_data),//写入的数据
       .m3_grnt_    (m3_grnt_),  //赋予总线
		
			
		  /****共享信号总线从属****/
		  
		.s_addr      (s_addr),    //地址 29:0
		.s_as_       (s_as_),     //地址选通
        .s_rw        (s_rw),      //读/写
        .s_wr_data(s_wr_data)  //写入的数据 31:0

   );
	
	 
	 
     //例化bus_addr_dec模块
	bus_addr_dec bus_addr_dec(

     /****总线从属共享信号****/
	  .s_addr      (s_addr),    //地址 29:0
	  /****总线从属0~7号****/
	  .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 bus_slave_mux(
	 /****0号总线从属****/ 
		.s0_cs_       (s0_cs_),     //片选
	   .s0_rd_data   (s0_rd_data), //读出的数据
		.s0_rdy_      (s0_rdy_),    //就绪
		
		.s1_cs_       (s0_cs_),     //片选
	   .s1_rd_data   (s0_rd_data), //读出的数据
		.s1_rdy_      (s0_rdy_),    //就绪
		
		.s2_cs_       (s0_cs_),     //片选
	   .s2_rd_data   (s0_rd_data), //读出的数据
		.s2_rdy_      (s0_rdy_),    //就绪
		
		.s3_cs_       (s0_cs_),     //片选
	   .s3_rd_data   (s0_rd_data), //读出的数据
		.s3_rdy_      (s0_rdy_),    //就绪
		
		.s4_cs_       (s0_cs_),     //片选
	   .s4_rd_data   (s0_rd_data), //读出的数据
		.s4_rdy_      (s0_rdy_),    //就绪
		
		.s5_cs_       (s0_cs_),     //片选
	   .s5_rd_data   (s0_rd_data), //读出的数据
		.s5_rdy_      (s0_rdy_),    //就绪
		
		.s6_cs_       (s0_cs_),     //片选
	   .s6_rd_data   (s0_rd_data), //读出的数据
		.s6_rdy_      (s0_rdy_),    //就绪
		
		.s7_cs_       (s0_cs_),     //片选
	   .s7_rd_data   (s0_rd_data), //读出的数据
		.s7_rdy_      (s0_rdy_),    //就绪
      
		/****总线主控共享信号****/ 
		
      .m_rd_data    (m_rd_data),  //读出的数据
		.m_rdy_       (m_rdy_)      //就绪
		
	);
	
endmodule 

记得在bus工程中加入例化模块的具体实现.v文件和所需要的头文件
在这里插入图片描述

4.错误集锦

1.Error (10267): Verilog HDL Module Instantiation error at bus.v(155): cannot connect instance ports both by order and by name

例化模块复制粘贴时多加一个逗号,错误找了半天……

2.Error (169281): There are 526 IO input pads in the design, but only 180 IO input pad locations available on the device.

报错原因:为了验证FPGA工程中的某个模块的功能和时序的正确性,常常需要对其单独进行验证,但是这些模块通常都与内部的众多信号相连(如系统总线,中断信号线等),往往一个模块的对外接口引脚会多达几百个,对其单独仿真的话,可能会对目标FPGA造成IO资源不足的情况。即使IO资源满足,当众多内部信号变成IO信号时,模块内部的信号将增加额外的IO延时,增加了时序约束的复杂度,在编译时会出现此类报错。

【参考博客https://blog.csdn.net/qq_41109998/article/details/123824555
附上解决方式设置虚拟管脚Virtual Pin】

Error 解决方法
一:有些报错英文翻译即可找到错误之处
二:网上网友见解,效率高,但解决方法不一,需要个人甄别
三:去官网社区搜错误Error序号,解决问题强,但对初学者可能不太友好。

5.专栏目录

《从0开始设计和实现CPU》32寄存器堆_记录篇(1)
《从0开始设计和实现CPU》总线设计(一)之总线仲裁器的实现
《从0开始设计和实现CPU》总线设计(二)之总线主控多路复用器的实现
《从0开始设计和实现CPU》总线设计(三)之地址解码器的实现
《从0开始设计和实现CPU》总线设计(四)之总线从属多路复用器的实现
《从0开始设计和实现CPU》bus总线顶层模块设计
正在更新!

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式历练者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值