经典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,给出总线控制权
2.总线主控多路复用器
将主控信号输入给BUS总线 看仲裁器给谁grnt信号,哪个主控就可以把信号给BUS 例如,默认情况下,0号主控的addr地址,as_地址标志位,rw读写信号,wr_data写入数据。全都赋值给output s的对应信。
3.地址解码器
实现地址映射,根据addr来决定控制哪个从属,输出对应的cs_信号
4.总线从属多路复用器
根据cs_信号,将对应的slaver的rd_data和rdy_信号输出
5.TOP模块连接
回顾上文的端口定义,我们可以得到几个模块间的相互关系 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号总线从属。
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
x_s3e_sprom x_s3e_sprom (
.clka (clk), // Clock
.addra (addr), // Address
.douta (rd_data) // Read data
);
定义ROM
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);
end
/********** Read access **********/
always @(posedge clka) begin
douta <= #1 mem[addra];
end
endmodule
要注意建立memdata.mem文件,里面放2进制代码
7.测试模块
注意s_addr的位宽为30,ROM需要的addr位宽为11位,这里选取了{{11’b00000_000001}}号的ROM内存地址。取出其数据。m0_rw<=`READ;读写信号设置为读取
//产生时钟激励
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<={{{3'b000}},{16'b0},{{11'b00000_000001}}};
m0_as_ <=`ENABLE_;
m0_rw<=`READ;
end
#STEP
$finish;
end
测试结果: 先显示ROM的0-2号地址的数据,我们testbench这边控制的是memdata[1]输出 其中m0_addr选取的为1号地址,m_rd_data为输出数据 输出对应的为memdata[1],验证成功.
|