这部分的代码在最后,本来打算刚开始就直接上代码,可是200多行,有点占篇幅。我们就先分析下这部分!
推荐一篇硕士论文,可以自行搜索下载,或点击免费下载:基于AHB总线SRAM控制器 的设计及优化.caj。
就这么说,市面上arm公司的架构比较受众,最基本的就是AMBA协议。芯片设计公司要把东西(ram、sram、uart等等)按照协议集联起来,所以要考虑的就是如何把他们连接到AMBA里面去!所以就产生了与模块对应的控制单元。
在这里有点迷惑:下面这部分是论文里的,也是参考博客中完全复现的部分!
这部分提到的sram控制器,不是AHB总线控制单元的部分吗?顶层模块只是将两个子模块例化连接起来就行了!难道他们是将这部分单独放了一个模块,然后例化在了ahb_slave_if.v中?
SRAM 的工作原理很简单,SRAM 控制单元根据接受到的总线控制信号,将这些信号处理转化为 SRAM 存储器可以识别的信号,发送到 SRAM 存储器;之后,将经过地址译码的物理地址传送到存储器的地址总线,并将数据路径处理的数据送到SRAM 存储器的数据总线。最后,SRAM 存储器进行相应的读写访问。如果是写操作,SRAM 控制单元的任务就完成了,SRAM 存储器已将数据信息按照要求写入。如果是读操作,SRAM 控制单元需要接收返回的读数据,将其送到数据路径,由数据路径将信息传输给 AHB 总线,最终实现总线对 SRAM 的读操作。
这里设计的SRAM控制器的作用就是实现SRAM存储器与AHB总线的数据信息交换。
声明:下面分析的这部分照搬前言提到的硕士论文 !!!!!!!!
/*选用单周期读写SRAM且SRAM一直处于“OK”状态*/
assign hready_resp =1’b1;
assign hresp =2’b00;
/*数据从SRAM传输到AHB总线 */
assign hrdata = sram_data_out
/* 根据AHB总线协议,只有当TRANS信号为NONSEQ或者SEQ时,数据读写才有效,
因此,需要保证SRAM读写时,TRANS信号有效。SRAM进行写操时,hwrite信号为高;
SRAM进行读操作时,hwrite信号为低 */
assign sram_write = ((htrans_r == NONSEQ) || (htrans_r == SEQ)) && hwrite_r;
assign sram_read = ((htrans_r == NONSEQ) || (htrans_r == SEQ)) && (!hwrite_r);
/*写使能信号低有效*/
assign sram_w_en = !sram_write;
/*只有当SRAM进行读写操作时,片选使能信号才为高电平,主要是节省功耗*/
assign sram_csn_en = (sram_write || sram_read);
/*当片选信号为1时,选中bank0;当片选信号为0时,选中bank1*/
assign sram_data_out = (bank_sel) ? {
sram_q3, sram_q2, sram_q1, sram_q0} :
{
sram_q7, sram_q6, sram_q5, sram_q4} ;
/*这一部分片选操作时,低32K空间选择bank0,在高32K空间选择bank1*/
assign bank_sel = (sram_csn_en && (sram_addr[15] == 1'b0)) ? 1'b1 : 1'b0;
assign bank0_csn= (sram_csn_en && (sram_addr[15] == 1'b0)) ? sram_csn : 4'b1111;
assign bank1_csn= (sram_csn_en && (sram_addr[15] == 1'b1)) ? sram_csn : 4'b1111;
/*数据从AHB总线写入SRAM */
assign sram_wdata = hwdata;
/*每个bank有4片SRAM,每一片SRAM有一个片选信号 */
always@(hsize_sel or haddr_sel)
begin
if(hsize_sel == 2'b10)
sram_csn = 4'b0;
/*一次片选两片SRAM */
else if(hsize_sel == 2'b01)
begin
if(haddr_sel[1] == 1'b0)
sram_csn = 4'b1100;
else
sram_csn = 4'b0011;
end
/*选择一片SRAM,具体到4片中的某一片*/
else if(hsize_sel == 2'b00)
begin
case(haddr_sel)
2'b00 : sram_csn = 4'b1110;
2'b01 : sram_csn = 4'b1101;
2'b10 : sram_csn = 4'b1011;
2'b11 : sram_csn = 4'b0111;
default : sram_csn = 4'b1111;
endcase
end
else
sram_csn = 4'b1111;
end
module ahb_slave_if(
//input signals
input hclk,
input hresetn,
input hsel,
input hwrite,
input hready,
input [2:0] hsize,
input [1:0] htrans,
input [2:0] hburst, // hard code -> parameter
input [31:0] hwdata,
input [31:0] haddr,
//output signals
output hready_resp,
output [1:0] hresp,
output [31:0] hrdata,
//sram output
input [7:0] sram_q0, // 8bits
input [7:0] sram_q1,
input [7:0] sram_q2,
input [7:0] sram_q3,
input [7:0] sram_q4,
input [7:0] sram_q5,
input [7:0] sram_q6,
input [7:0] sram_q7,
output sram_w_en, // 0:write, 1:read
output [12:0] sram_addr_out,
output [31:0] sram_wdata, //写sram数据
output [3:0] bank0_csn, //四字节可以单独写入
output [3:0] bank1_csn
);
//-------------------------------------------------------
//internal registers used for temp the input ahb signals
//-------------------------------------------------------
//temperate all the AHB input signals
reg hwrite_r;
reg [2:0] hsize_r ;
reg [2:0] hburst_r;
reg [1:0] htrans_r;
reg [31:0] haddr_r;
reg [3:0] sram_csn;
//------------------------------------------------------
//Internal signals
//------------------------------------------------------
//"haddr_sel " and "hsize_sel" used to generate banks of
//sram: "bank0_sel" and "bank1_sel".
wire [1:0] haddr_sel;
wire [1:0] hsize_sel;
wire bank_sel;
wire sram_csn_en; //sram chip select enable
wire sram_write; //sram write enable signal from AHB bus
wire sram_read; //sram read enable signal from AHB bus
wire [15:0] sram_addr; //sram address from AHB bus
wire [31:0] sram_data_out; //data read from sram and send to AHB bus
parameter IDLE = 2'b00,
BUSY = 2'b01,
NONSEQ = 2'b10,
SEQ = 2'b11;
//---------------------------------------------------------
// Combinatorial portion
//---------------------------------------------------------
//assign the response and read data of the ahb slave
//In order to implement the sram function-writing or reading
//in one cycle, the value of hready_resp is always "1".
assign hready_resp = 1'b1; // Singal Cycle
assign hresp = 2'b00; // OK
//---------------------------------------------------------
//sram data output to AHB bus
//---------------------------------------------------------
assign hrdata = sram_data_out; //组合逻辑读,CPU读SRAM,地址有效则立即读
//Choose the right data output of the two banks(bank0, bank1) according
//to the value of bank_sel. If bank_sel = 1'b1, bank0 sleceted, or
//bank1 selected.
assign sram_data_out = (bank_sel) ?
{
sram_q3, sram_q2, sram_q1, sram_q0} :
{
sram_q7, sram_q6, sram_q5, sram_q4} ;
//Generate sram write and read enable signals.
assign sram_write = ((htrans_r == NONSEQ) || (htrans_r == SEQ)) && hwrite_r;
assign sram_read = ((htrans_r == NONSEQ) || (htrans_r == SEQ)) && (!hwrite_r);
assign sram_w_en = !sram_write;
//generate sram address
//SRAM总寻址64K 0x0--0xffff
assign sram_addr = haddr_r [15:0];//64K 8*8K
assign sram_addr_out = sram_addr[14:2]; // word
//Generate bank select signals by the value of sram_addr[15].
//Each bank(32kx32) comprises of four sram block(8kx8), and
//the width of the address of the bank is 15 bits(14~0), so
//the sram_addr[15] is the minimun of the next bank. If its
//value is "1", it means the next bank is selcted.
assign sram_csn_en = (sram_write || sram_read);
//低32K bank0 高32K bank1
assign bank_sel = (sram_csn_en && (sram_addr[15] == 1'b0)) ? 1'b1 : 1'b0;
assign bank0_csn = (sram_csn_en && (sram_addr[15] == 1'b0)) ? sram_csn : 4'b1111;
assign bank1_csn = (sram_csn_en && (sram_addr[15] == 1'b1)) ? sram_csn : 4'b1111;
//signals used to generating sram chip select signal in one bank.
assign haddr_sel = sram_addr[1:0];
assign hsize_sel = hsize_r [1:0];
//-------------------------------------------------------
//data from ahb writing into sram
//-------------------------------------------------------
assign sram_wdata = hwdata;
//-------------------------------------------------------
//Generate the sram chip selecting signals in one bank.
//The resluts show the AHB bus write or read how many data
//once a time: byte, halfword or word.
//---------------------------------------------------------
always@(hsize_sel or haddr_sel) begin
if(hsize_sel == 2'b10)//32bit
sram_csn = 4'b0;
else if(hsize_sel == 2'b01) begin//16bit
if(haddr_sel[1] == 1'b0) //little-endian
sram_csn = 4'b1100;
else
sram_csn = 4'b0011;
end
else if(hsize_sel == 2'b00) begin//8bit
case(haddr_sel)
2'b00 : sram_csn = 4'b1110;
2'b01 : sram_csn = 4'b1101;
2'b10 : sram_csn = 4'b1011;
2'b11 : sram_csn = 4'b0111;
default : sram_csn = 4'b1111;
endcase
end
else
sram_csn = 4'b1111;
end
//--------------------------------------------------------
// Sequential portion
//--------------------------------------------------------
//tmp the ahb address and control signals
always@(posedge hclk , negedge hresetn) begin
if(!hresetn) begin
hwrite_r <= 1'b0 ;
hsize_r <= 3'b0 ;
hburst_r <= 3'b0 ;
htrans_r <= 2'b0 ;
haddr_r <= 32'b0 ;
end
else if(hsel && hready) begin //hsel要片选,否则信号一直在翻转,可能会功能错误,并且功耗大
hwrite_r <= hwrite ;//写SRAM时,把控制信号寄存。因为写操作时,要把地址打一拍,和数据对齐
hsize_r <= hsize ;
// hburst_r <= hburst ;//AHB中master会把burst传输所有地址传递过来,AXI只传递起始地址。此处用处不大。减少一个REG
htrans_r <= htrans ;
haddr_r <= haddr ;
end else begin
hwrite_r <= 1'b0 ;
hsize_r <= 3'b0 ;
hburst_r <= 3'b0 ;
htrans_r <= 2'b0 ;
haddr_r <= 32'b0 ;
end
end
endmodule
这是AHB-SRAM项目中,总线控制单元ahb_slave_if.v的所有文件,如果需要跳转到查看此项目的架构,请点击跳转
AHB-SRAM简单设计之架构图解
笔者是小白,自学输出过程中,难免有错误,请大家指正!