TailCorr/spi_tx_rx/tx/tx_sram.v

252 lines
5.9 KiB
Verilog

// Relese History
// Version Date Author Description
// 0.3 2024-05-29 ZYZ
//-----------------------------------------------------------------------------------------------------------------
// Keywords : connect spi-master
//
//-----------------------------------------------------------------------------------------------------------------
// Parameter :
// cmd[31:0] form:
// form-v0.2 {WR ,RSV ,ID ,ADDR}
// [31] [30] [29:25] [24:0]
//
// form-v0.3 {WR ,ADDR ,ID ,RSV}
// [31] [30:6] [5:1] [0]
//
// form-v0.2 is defined by design , it has len[31:0];
// form-v0.3 is produced by spi interface ,it doesn't have len[31:0];
//
// size : 256K
//-----------------------------------------------------------------------------------------------------------------
// Purpose :
//
//-----------------------------------------------------------------------------------------------------------------
// Target Device:
// Tool versions:
//-----------------------------------------------------------------------------------------------------------------
// Reuse Issues
// Reset Strategy:
// Clock Domains:
// Critical Timing:
// Asynchronous I/F:
// Synthesizable (y/n):
// Other:
//-FHDR--------------------------------------------------------------------------------------------------------
module tx_sram(
input clk,
input rstn,
(* mark_debug="true" *)input [31:0] dina,
(* mark_debug="true" *)input [15:0] data_length,
output [31:0] Nlen,
output [4 :0] chip_ID,
output [24:0] address,
output [31:0] data_out,
(* mark_debug="true" *)output wr_en,
(* mark_debug="true" *)output rd_en,
(* mark_debug="true" *)input WREADY,
(* mark_debug="true" *)input RREADY,
output data_done_all,
output data_out_per
);
parameter width = 32 ;
parameter depth = 65536 ;
//=================================================
function integer clog2(input integer depth);
begin
for(clog2=0;depth>0;clog2=clog2+1)
depth =depth>>1;
end
endfunction
//=================================================
localparam aw = clog2(depth-1);
//=================================================
//wr&rd address
(* mark_debug="true" *) reg [aw-1:0]cnta ;
(* mark_debug="true" *) reg [aw-1:0]cntb ;
(* mark_debug="true" *) wire ena ;
(* mark_debug="true" *) wire enb ;
(* mark_debug="true" *) wire full ;
(* mark_debug="true" *) wire [31:0] doutb;
//current len of data ,initial value is 0
(* mark_debug="true" *) reg [31:0]len_current ;
//cmd
(* mark_debug="true" *) reg cmd_s ;
(* mark_debug="true" *) reg [4:0] chip_ID_reg ;
(* mark_debug="true" *)reg [24:0]address_reg ;
always@(posedge clk or negedge rstn)begin
if(!rstn)begin
cmd_s <= 1'b0;
chip_ID_reg <= 5'b0;
address_reg <= 25'b0;
end
else if(cntb == len_current + 2'd1)begin
cmd_s <= doutb[31];
chip_ID_reg <= doutb[5:1];
address_reg <= doutb[30:6];
end
else begin
cmd_s <= cmd_s;
chip_ID_reg <= chip_ID_reg;
address_reg <= address_reg;
end
end
assign chip_ID = chip_ID_reg;
assign address = address_reg;
//len of data_out
(* mark_debug="true" *) reg [31:0]len_reg ;
always@(posedge clk or negedge rstn)begin
if(!rstn)begin
len_reg <= 32'b0;
end
else if(cntb == len_current + 2'd2)begin
len_reg <= doutb ;
end
else begin
len_reg <= len_reg;
end
end
assign Nlen = len_reg;
//data_out
(* mark_debug="true" *) reg [31:0]data_out_reg ;
(* mark_debug="true" *) wire data_out_en ;
always@(posedge clk or negedge rstn)begin
if(!rstn)begin
data_out_reg <= 32'b0;
end
else if(data_out_en)begin
data_out_reg <= doutb ;
end
else begin
data_out_reg <= 32'b0;
end
end
reg data_out_en_r1;
always@(posedge clk or negedge rstn)begin
if(!rstn)begin
data_out_en_r1 <= 1'b0;
end
else begin
data_out_en_r1 <= data_out_en;
end
end
assign data_out = data_out_reg;
assign data_out_en = (cntb >= len_current + 2'd3) & (cntb <= len_current + len_reg + 2'd2);
//signal send to spi_master
assign wr_en = !cmd_s & data_out_en_r1;
assign rd_en = cmd_s & data_out_en_r1;
//signal send to PC
assign data_out_per = (cntb == len_current + 3'd3 ) ? 1'b1 : 1'b0;
assign data_done_all = (cntb == data_length-1'b1 | cnta == data_length - 1'b1) ? 1'b1 : 1'b0;
//the time ready for writing data and updata len_current
reg [2:0] wready_reg;
always @(posedge clk or negedge rstn)
begin
if(!rstn ) begin
wready_reg <= 3'b0;
end
else begin
wready_reg <= {wready_reg[1:0],WREADY};
end
end
assign wready_posedge = wready_reg[1:0] == 2'b01 ? 1'b1 : 1'b0;
//updata len_current and cntb
always@(posedge clk or negedge rstn)begin
if(!rstn)begin
len_current <= 32'b0;
end
else if( wready_posedge & len_reg != 0)begin
len_current <= len_current + len_reg + 2'd2 ;
end
else begin
len_current <= len_current;
end
end
//write address: addra
//read address: addrb
always @(posedge clk or negedge rstn)
begin
if(!rstn) begin
cnta <= 'hffff;
end
else if(ena) begin
cnta <= cnta + 1'b1;
end
else
cnta <= cnta ;
end
always @(posedge clk or negedge rstn)
begin
if(!rstn ) begin
cntb <= 'h0 ;
end
else if(enb) begin
cntb <= cntb + 1'b1;
end
else if(wready_posedge & len_reg != 0) begin
cntb <= cntb - 1'b1 ; // better solution?
end
else begin
cntb <= cntb;
end
end
assign full = (cnta+1'b1 <= data_length )? 1'b0 : 1'b1 ;
assign ena = !full;
assign enb = full & (cntb <= data_length ) & WREADY & (cntb <= len_current + len_reg + 2'd2);
/*
blk_mem_gen_0 blk_mem_gen_0_inst(
.clka(clk),
.ena(1'b1),
.wea(ena),
.dina(dina),
.addra(cnta),
.clkb(clk),
.enb(enb),
.doutb(doutb),
.addrb(cntb)
);
*/
spram_model #(
.width(width),
.depth(depth)
)spram_inst(
.clka(clk),
.ena(~ena),
.dina(dina),
.addra(cnta),
.clkb(clk),
.enb(~enb),
.doutb(doutb),
.addrb(cntb)
);
endmodule