module ahb_slave_if(
// input import from master to slave
input hclk,
input hresetn,
input hsel,
input hready,
input hwrite,
input [31:0] haddr,
input [31:0] hwdata,
input [1:0] htrans,
input [2:0] hburst,
input [2:0] hsize,
// output import from slave to bus
output hready_resp,
output [1:0] resp,
output [31:0] hrdata,
// input import from sram to slave
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 import from slave to sram
output sram_w_en,
output [12:0] sram_addr_out,
output [31:0] sram_wdata,
output [3:0] bank1_csn,
output [3:0] bank0_csn
);
// internal wire var
wire [31:0] sram_data_out;
wire bank_sel;
wire sram_csn_en;
wire sram_write;
wire sram_read;
wire [15:0] sram_addr; //64K, 8 * 8k
// internal reg var
reg hwrite_r;
reg [1:0] htrans_r;
reg [2:0] hsize_r;
reg [31:0] haddr_r;
reg [3:0] sram_csn;
// trans參數(shù)
parameter IDLE = 2'b00,
BUSY = 2'b01,
NONSEQ = 2'b10,
SEQ = 2'b11;
//step 1: 保證單周期讀寫
assign hready_resp = 1;
assign resp = 2'b00;
//step 2: data from sram to slave
assign hrdata = sram_data_out;
//step 3: 確定sram_data_out
assign sram_data_out = bank_sel ? {sram_q7, sram_q6, sram_q5, sram_q4} :
{sram_q3, sram_q2, sram_q1, sram_q0} ;
// step 4: 確定bank_sel
assign bank_sel = (sram_csn_en && sram_addr[15] == 1) ? 0 : 1;
// step 5: 確定sram_csn_en
assign sram_csn_en = (sram_write || sram_read);
// step 6: 確定sram_read 和 sram_write
assign sram_read = ((htrans_r == SEQ || htrans_r == NONSEQ) && !hwrite_r);
assign sram_write = ((htrans_r == SEQ || htrans_r == NONSEQ) && hwrite_r);
assign sram_w_en = !sram_write;
// step 7:確定片選的哪些sram
assign bank0_csn = (sram_csn_en && sram_addr[15] == 0) ? sram_csn : 4'b1111;
assign bank1_csn = (sram_csn_en && sram_addr[15] == 1) ? sram_csn : 4'b1111;
// step 8: 確定sram_addr
assign sram_addr = haddr_r[15:0];
assign sram_addr_out = sram_addr[14:2]; //一個(gè) word 32bit
// step 9: 確定sram_csn,用到兩個(gè)新變量 hsize_sel haddr_sel
wire [1:0] hsize_sel;
wire [1:0] haddr_sel;
assign hsize_sel = hsize_r[1:0];
assign haddr_sel = sram_addr[1:0];
always @ (hsize_sel or haddr_sel) begin
if(hsize_sel == 2'b10) //word
sram_csn = 4'b0000;
else if(hsize_sel == 2'b01) begin //halfword
if(haddr_sel[1] == 0)
sram_csn = 4'b1100;
else
sram_csn = 4'b0011;
end
else if(hsize_sel == 2'b00) begin //byte
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
end
//step 10:打拍延時(shí)
always @ (posedge hclk or negedge hresetn) begin
if(!resetn) begin
haddr_r <= 0;
hsize_r <= 0;
htrans_r <= 0;
hwrite_r <= 0;
end
else if(hsel && hready)begin
haddr_r <= haddr;
hsize_r <= hsize;
htrans_r <= htrans;
hwrite_r <= hwrite;
end
else begin
haddr_r <= 0;
hsize_r <= 0;
htrans_r <= 0;
hwrite_r <= 0;
end
end
//step 11:data from slave to sram
assign sram_wdata = hwdata;
endmodule
top文件
module sramc_top(
//input signals
input wire hclk,
input wire sram_clk,
input wire hresetn,
input wire hsel,
input wire hwrite,
input wire hready,
input wire [2:0] hsize ,
input wire [2:0] hburst,
input wire [1:0] htrans,
input wire [31:0] hwdata,
input wire [31:0] haddr,
//Signals for BIST and DFT test mode
//When signal"dft_en" or "bist_en" is high, sram controller enters into test mode.
input wire dft_en,
input wire bist_en,
//output signals
output wire hready_resp,
output wire [1:0] hresp,
output wire [31:0] hrdata,
//When "bist_done" is high, it shows BIST test is over.
output wire bist_done,
//"bist_fail" shows the results of each sram funtions.There are 8 srams in this controller.
output wire [7:0] bist_fail
);
//Select one of the two sram blocks according to the value of sram_csn
wire [3:0] bank0_csn;
wire [3:0] bank1_csn;
//Sram read or write signals: When it is high, read sram; low, writesram.
wire sram_w_en;
//Each of 8 srams is 8kx8, the depth is 2^13, so the sram's address width is 13 bits.
wire [12:0] sram_addr;
//AHB bus data write into srams
wire [31:0] sram_wdata;
//sram data output data which selected and read by AHB bus
wire [7:0] sram_q0;
wire [7:0] sram_q1;
wire [7:0] sram_q2;
wire [7:0] sram_q3;
wire [7:0] sram_q4;
wire [7:0] sram_q5;
wire [7:0] sram_q6;
wire [7:0] sram_q7;
// Instance the two modules:
// ahb_slave_if.v and sram_core.v
ahb_slave_if ahb_slave_if_u(
//-----------------------------------------
// AHB input signals into sram controller
//-----------------------------------------
.hclk (hclk),
.hresetn (hresetn),
.hsel (hsel),
.hwrite (hwrite),
.hready (hready),
.hsize (hsize),
.htrans (htrans),
.hburst (hburst),
.hwdata (hwdata),
.haddr (haddr),
//-----------------------------------------
//8 sram blcoks data output into ahb slave
//interface
//-----------------------------------------
.sram_q0 (sram_q0),
.sram_q1 (sram_q1),
.sram_q2 (sram_q2),
.sram_q3 (sram_q3),
.sram_q4 (sram_q4),
.sram_q5 (sram_q5),
.sram_q6 (sram_q6),
.sram_q7 (sram_q7),
//---------------------------------------------
//AHB slave(sram controller) output signals
//---------------------------------------------
.hready_resp (hready_resp),
.hresp (hresp),
.hrdata (hrdata),
//---------------------------------------------
//sram control signals and sram address
//---------------------------------------------
.sram_w_en (sram_w_en),
.sram_addr_out(sram_addr),
//data write into sram
.sram_wdata (sram_wdata),
//choose the corresponding sram in a bank, active low
.bank0_csn (bank0_csn),
.bank1_csn (bank1_csn)
);
sram_core sram_core_u(
//AHB bus signals
.hclk (hclk ),
.sram_clk (sram_clk),
.hresetn (hresetn ),
//-------------------------------------------
//sram control singals from ahb_slave_if.v
//-------------------------------------------
.sram_addr (sram_addr ),
.sram_wdata_in(sram_wdata),
.sram_wen (sram_w_en ),
.bank0_csn (bank0_csn ),
.bank1_csn (bank1_csn ),
//test mode enable signals
.bist_en (bist_en ),
.dft_en (dft_en ),
//-------------------------------------------
//8 srams data output into AHB bus
//-------------------------------------------
.sram_q0 (sram_q0),
.sram_q1 (sram_q1),
.sram_q2 (sram_q2),
.sram_q3 (sram_q3),
.sram_q4 (sram_q4),
.sram_q5 (sram_q5),
.sram_q6 (sram_q6),
.sram_q7 (sram_q7),
//test results output when in test mode
.bist_done (bist_done),
.bist_fail (bist_fail)
);
endmodule
tb文件
module sramc_tb;
reg hclk;
reg sram_clk;
reg hresetn;
reg hsel;
reg hwrite;
reg hready;
reg [2:0] hsize;
reg [2:0] hburst;
reg [1:0] htrans;
reg [31:0] hwdata;
reg [31:0] haddr;
reg dft_en;
reg bist_en;
wire hready_resp;
wire [1:0] hresp;
wire [31:0] hrdata;
wire bist_done;
wire [7:0] bist_fail;
reg [31:0] rdata;
sramc_top u_top(
.hclk (hclk),
.sram_clk (sram_clk),
.hresetn (hresetn),
.hsel (hsel),
.hwrite (hwrite),
.hready (hready),
.hsize (hsize),
.hburst (hburst),
.htrans (htrans),
.hwdata (hwdata),
.haddr (haddr),
.dft_en (dft_en),
.bist_en (bist_en),
.hready_resp (hready_resp),
.hresp (hresp),
.hrdata (hrdata),
.bist_done (bist_done),
.bist_fail (bist_fail)
);
//HCLK 50M
parameter period=20;
initial begin
hclk = 0;
forever begin
//#10 hclk = ~hclk;
#10 hclk = ~hclk;
end
end
//不推薦 always
initial begin
sram_clk = 0;
forever begin
#10 sram_clk = ~sram_clk;
end
end
initial begin
$vcdpluson(); //vcs dump waveform
end
parameter IDLE = 2'b00,
BUSY = 2'b10,
NONSEQ = 2'b10,
SEQ = 2'b11;
initial begin
// ...x-delay
hresetn = 0;
dft_en = 0;
bist_en = 0;//work in model mode
htrans = IDLE;
hsize = 2'b00;
hwrite = 0;
hsel = 0;
hready = 0;
haddr = 0;
#200;
hresetn = 1;
//write_read bank0
#10;
sram_write(32'h0000_0050,32'ha0b0c0d0);
#10
sram_read(32'h0000_0050,rdata);
//write_read bank1
#100;
sram_write(32'h0000_f010,32'h0a0b0c0d);
#10;
sram_read(32'h0000f010,rdata);
#1000;
$finish;
end
//direct test
task sram_write(input [31:0] addr,input [31:0] wdata);
begin
@(posedge hclk);
hsize = 2'b10;
htrans = NONSEQ;
hwrite = 1;
hsel = 1;
hready = 1;
haddr = addr;
@(posedge hclk);
hwdata = wdata;
end
endtask
//分兩拍,符合協(xié)議要求
task sram_read(input [31:0] addr,output [31:0] rdata);
begin
@(posedge hclk);
haddr = addr;
hsize = 2'b10;
htrans = NONSEQ;
hwrite = 0;
hsel =1;
@(posedge hclk);
rdata = hrdata;
end
endtask
endmodule