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总线顶层模块设计
正在更新!