AHB-SRAM简单设计之总线控制单元 ahb_slave_if.v

前言

这部分的代码在最后,本来打算刚开始就直接上代码,可是200多行,有点占篇幅。我们就先分析下这部分!

推荐一篇硕士论文,可以自行搜索下载,或点击免费下载:基于AHB总线SRAM控制器 的设计及优化.caj。
AHB-SRAM简单设计之总线控制单元 ahb_slave_if.v_第1张图片

AHB总线控制单元 ahb_slave_if.v

就这么说,市面上arm公司的架构比较受众,最基本的就是AMBA协议。芯片设计公司要把东西(ram、sram、uart等等)按照协议集联起来,所以要考虑的就是如何把他们连接到AMBA里面去!所以就产生了与模块对应的控制单元。

在这里有点迷惑:下面这部分是论文里的,也是参考博客中完全复现的部分!
这部分提到的sram控制器,不是AHB总线控制单元的部分吗?顶层模块只是将两个子模块例化连接起来就行了!难道他们是将这部分单独放了一个模块,然后例化在了ahb_slave_if.v中?
AHB-SRAM简单设计之总线控制单元 ahb_slave_if.v_第2张图片
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 

ahb_slave_if.v

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简单设计之架构图解

笔者是小白,自学输出过程中,难免有错误,请大家指正!

你可能感兴趣的:(AHB-SRAM,ahb,sram)