经典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],
仿真验证成功.