AHB-SRAMC Design-02

AHB-SRAMC Design

SRAMC(另外一种代码风格)解析

SRAM集成,顶层模块尽量不要写交互逻辑


module ahb_slave_if(
	input hclk,
	input hrestn,
	
	input hwrite,
	input hsel,
	input hready,
	
	input [2:0] hsize,
	input [1:0] htrans,
	input [2:0] hburst,
	input [31:0] haddr
	input [31:0] hwdata,
	
	
	input [7:0] sram_q0;
	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 hready_resp,
	output [1:0] hresp,
	output [31:0] hrdata,
	
	output sram_w_en,
	output [3:0] bank0_csn,
	output [3:0] bank1_csn,
	
	output [31:0] sram_wdata,
	output [12:0] sram_addr_out
);

	// 定义一些内部信号
	wire [1:0] haddr_sel;
	
	wire [1:0] hsize_sel;
	
	wire bank_sel;  // bank选择信号,拉高选择bank0,拉低选择bank1
	
	wire sram_csn_en; // sram选择信号
	
	wire sram_read;
	wire sram_write; // sram读写信号
	
	wire [15:0] sram_addr;
	wire [31:0] sram_data_out;
	
	
	
 	parameter		IDLE = 2'b00,
				BUSY = 2'b01,
				NONSEQ = 2'b10,
				SEQ = 2'b11;

	
	assign hready_resp = 1'b1;
	assign hresp = 2'b00;
	
	// 从sram中读取的数据
	hrdata = sram_data_out;
	
	
	// 根据bank_sel进行选择bank中的mem读取,bank_sel == 1 选择bank0,bank_sel == 0选择bank1
	assign sram_data_out = bank_sel ? {sram_q7,sram_q6,sram_q5,sram_q4}:
								{sram_q3,sram_q2,sram_q1,sram_q0};
					
	assign sram_write = hwrite && ((htrans_r == NONSEQ) || (htrans_r == SEQ));
	assign sram_read = (!hwrite) && ((htrans_r == NONSEQ) || (htrans_r == SEQ));
	
	// 产生写信号,低有效
	assign sram_w_en = !sram_write;
	
	assign sram_addr = haddr[15:0];
	assign sram_addr_out = sram_addr[14:2];
	
	// 写或读的时候进行片选
	assign sram_csn_en = (sram_write || sram_read);
	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;
	
	assign haddr_sel = sram_addr[1:0];
	assign hsize_sel = hszie_r[1:0];
	
	assign sram_wdata = hwdata;
	
	
	always @(hsize_sel or haddr_sel)
	begin
		if(hsize_sel == 2‘b10)
			sram_csn = 4’b0;
		else if(haddr_sel == 2'b01)
		begin
			if(!haddr_sel[1] = 1'b0)
				sram_csn = 4'b1100;
			else 
				sram_csn = 4'b0011;
		end
		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总线控制信号进行打拍处理
	always@(posedge hclk or negedge hrestn)
	begin
		if(!hrestn) 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
			hwrite_r <= hwrite;
			hsize_r  <= hsize;
			hburst_r <= hburst;
			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

1.将ahb总线地址和控制信号进行打拍

always@(posedge hclk or negedge hrestn)
	begin
		if(!hrestn) begin
			hwrite_r <= 1'b0;
			hsize_r  <= 3'b0;
			hburst_r <= 3'b0;
			htrans_r <= 2'b0;
			haddr_r  <= 32'b0;
		end 
                // 被选择之后并且hready了,进行信号打拍
		else if(hsel && hready) begin
			hwrite_r <= hwrite;
			hsize_r  <= hsize;
			hburst_r <= hburst;
			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

2.定义parameter(htrans状态和hsize)

parameter	IDLE = 2'b00,
		BUSY = 2'b01,
		NONSEQ = 2'b10,
		SEQ = 2'b11;

// 还可以定义hsize的状态

3.hready_resp拉高并且hresp是okay状态

assign hready_resp = 1'b1;
assign hresp = 2'b00;

4.产生读写使能信号,明确什么时候读数据,什么时候写数据?

根据打拍之后的htrans和hwrite进行组合得到读写信号,由于sram_w_en是低有效的,所以在根据ahb信号产生读写信号之后,将写信号进行取反就可以得到sram_w_en = !sram_write = !hwrite_r,直接使用hwrite_r信号取反也可以表示写使能
注意:为了表示读写信号,定义了sram_write和sram_read两个内部信号
5.产生片选信号(分为sram中的mem选择信号和bank选择信号)
(1)产生片选使能--表示什么时候进行片选
sram_csn -- 表示选择哪几个mem
sram_csn_en --表示什么时候进行片选,在进行读写的时候进行片选--这也是一个中间信号

// 下面两种都是可以的
assign sram_csn_en = sram_write || sram_read;
assign sram_csn_en = (htrans_r == NONSEQ || htrans_r == SEQ);

(2)处理地址信号

  • 根据haddr [31:0]的低16位作为sram_addr
  • sram_addr的最高位表示选择bank
  • sram_addr的低低两位表示选择的mem
  • sram_addr中间的十三位表示读取的写入的地址
assign sram_addr = haddr[15:0];
assign sram_addr_out = sram_addr[14:2];
assign haddr_sel = sram_addr[1:0];

(3)hsize_sel
定义hsize的大小,使用打拍之后的信号低两位

assign hsize_sel = hsize_r[1:0];

(4)产生片选信号

// sram_csn --选择mem的信号

always @(hsize_sel or haddr_sel)
	begin
                // hsize--word的时候,四个mem全部选中
		if(hsize_sel == 2‘b10)
			sram_csn = 4’b0;
                // hsize--halfword的时候,判断地址的第二位是0,选择低两个,是1选择高两个mem
		else if(haddr_sel == 2'b01)
		begin
			if(!haddr_sel[1] = 1'b0)
				sram_csn = 4'b1100;
			else 
				sram_csn = 4'b0011;
		end
                // hsize--byte的时候,情况是任意的四个mem都可能被选到,四种情况
		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

//选择bank的信号--在片选使能的作用下,根据sram_addr最高位选择mem
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;

6.sram的写数据就是hwdata

assign sram_wdata = hwdata;

7.sram_data_out根据选择的bank输出其中mem中的数据

选择bank的标志可以使用sram_addr的最高位还可以设置一个内部信号bank_sel

assign bank_sel = (sram_csn_en && (sram_addr[15]) == 1'b0) ? 1‘b1:1’b0;
// 根据bank_sel进行选择bank中的mem读取,bank_sel == 1 选择bank0,bank_sel == 0选择bank1
assign sram_data_out = bank_sel ? {sram_q7,sram_q6,sram_q5,sram_q4}:
				{sram_q3,sram_q2,sram_q1,sram_q0};

assign sram_data_out = sram_addr[15] ? {sram_q7,sram_q6,sram_q5,sram_q4}:
				{sram_q3,sram_q2,sram_q1,sram_q0};

SRAM_CORE(了解)

将8个mem进行集成,主要是将slave_if输入的信号广播到端口上

posted @ 2023-04-02 15:42  Icer_Newer  阅读(160)  评论(0编辑  收藏  举报