/*
read sequence
clk ``\____/````\____/` ..... _/````\____/````\____/` ..... _/````\____/````\____/`
| | | | | | |
start XXXX```````````\__ ....... ____________________________________________________
| | | | | | |
rnw XXXXXX```XXXXXXXXX ....... XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
| | some | | | | |
ready XXXXXXX\__________ clocks __/`````````````````` ....... ```````````\__________
before | |
rdat ------------------ ready -< cell 0 | cell 1 | ....... |last cell>-----------
| | | | | | |
stop XXXXXXX\__________ ....... _____________________ ....... ___________/``````````
^all operations stopped until next start strobe
write sequence
clk ``\____/````\____/` ..... _/````\____/````\____/````\____/````\____/````\____/````\____/````\____/
| | some | | some | | | | | |
start XXXX```````````\__ ....... _____________ .... ______________ .... ________________________________
| | clocks | | clocks | | | | | |
rnw XXXXXX___XXXXXXXXX ....... XXXXXXXXXXXXX .... XXXXXXXXXXXXXX .... XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
| | before | | before | | | | | |
ready XXXXXXX\__________ ....... _/`````````\_ .... __/`````````\_ .... __/`````````\___________________
| | first | | next | | | | | |
wdat XXXXXXXXXXXXXXXXXXXXXXXXXXXX< cell 0 >X .... XX< cell 1 >X .... XX<last cell>XXXXXXXXXXXXXXXXXXX
| | ready | | ready | | | | | |
stop XXXXXXX\__________ ....... _____________ .... ______________ .... ____________/```````````````````
| | strobe | | strobe | | | | | |
clk ``\____/````\____/````\____/````\____/````\____/````\____/````\____/````\____/````\____/````\____/````\____/````\____/``
| | | | | | | | | | | |
ready __________________/`````````\___________________/`````````\___________________/`````````\___________________/`````````\_
| | | | | | | | | | | |
wdat cell 0 | cell 1 | cell 2 | cell 3 |
| | | | | | | | | | | |
sram_adr XXXXXXXXXXXXXXXXXXXXXXXXX| 0 | 1 | 2 |
| | | | | | | | | | | |
sram_dat XXXXXXXXXXXXXXXXXXXXXXXXX| cell 0 | cell 1 | cell 2 |
| | | | | | | | | | | |
sram_we_n```````````````````````````````````\_________/```````````````````\_________/```````````````````\_________/``````````
| BEG | PRE1 | PRE2 | | | | | | | | |
| | | CYC1 | CYC2 | CYC3 | CYC1 | CYC2 | CYC3 | CYC1 | CYC2 | CYC3 |
*/
module sram_control(
clk,
clk2, //latching of SRAM data out
start, // initializing input, address=0
stop, // when all addresses are done, nothing will happen after stop is set, need another start signal
rnw, // 1 - read, 0 - write sequence (latched when start=1)
ready, // strobe. when writing, one mean that data from wdat written to the memory (2^SRAM_ADDR_SIZE strobes total)
// when reading, one mean that data read from memory is on rdat output (2^SRAM_ADDR_SIZE strobes total)
wdat, // input, data to be written to memory
rdat, // output, data last read from memory
SRAM_DQ, // sram inout databus
SRAM_ADDR, // sram address bus
SRAM_UB_N, // sram control signals
SRAM_LB_N, //
SRAM_WE_N, //
SRAM_CE_N, //
SRAM_OE_N //
);
parameter SRAM_DATA_SIZE = 16;
parameter SRAM_ADDR_SIZE = 18;
input clk;
input clk2;
input start,rnw;
output stop;
reg stop;
output ready;
reg ready;
input [SRAM_DATA_SIZE-1:0] wdat;
output [SRAM_DATA_SIZE-1:0] rdat;
reg [SRAM_DATA_SIZE-1:0] rdat;
inout [SRAM_DATA_SIZE-1:0] SRAM_DQ;
reg [SRAM_DATA_SIZE-1:0] SRAM_DQ;
output [SRAM_ADDR_SIZE-1:0] SRAM_ADDR;
wire [SRAM_ADDR_SIZE-1:0] SRAM_ADDR;
output SRAM_UB_N,SRAM_LB_N,SRAM_WE_N,SRAM_CE_N,SRAM_OE_N;
reg SRAM_UB_N,SRAM_LB_N,SRAM_WE_N,SRAM_CE_N,SRAM_OE_N;
reg [SRAM_DATA_SIZE-1:0] wdat2;
reg dbin; //data bus direction control
reg [SRAM_ADDR_SIZE:0] sram_addr_ctr; // one bit bigger to have stop flag
wire [SRAM_ADDR_SIZE:0] sram_addr_nxt; // next sram address
reg [SRAM_DATA_SIZE-1:0] rdat2;
assign SRAM_ADDR = sram_addr_ctr[SRAM_ADDR_SIZE-1:0];
assign sram_addr_nxt = sram_addr_ctr + 1;
// data bus control
always @*
begin
if( dbin )
SRAM_DQ <= 'hZ;
else // !dbin
SRAM_DQ <= wdat2;
end
always @(posedge clk2) // clk2!!!! late latching
begin
rdat2 <= SRAM_DQ;
end
always @(posedge clk)
begin
rdat <= rdat2;
end
always @(posedge clk)
begin
if( ready ) wdat2 <= wdat;
end
reg [3:0] curr_state,next_state;
parameter START_STATE = 4'd00; // reset state
parameter INIT_STATE = 4'd01; // initialization state
parameter READ_BEG = 4'd02; // read branch: prepare signals
parameter READ_PRE = 4'd13;
parameter READ_CYCLE = 4'd03; // read in progress: increment address, set ready, out data, do so until all addresses done
parameter READ_POST = 4'd14;
parameter READ_END = 4'd04; // read end: deassert some signals, go to stop state
parameter WRITE_BEG = 4'd05; // prepare signals
parameter WRITE_PRE1 = 4'd06; // assert ready
parameter WRITE_PRE2 = 4'd07; // capture wdat, negate ready, NO INCREMENT address, next state is WRITE_CYC2
parameter WRITE_CYC1 = 4'd08; // capture wdat, negate ready, increment address
parameter WRITE_CYC2 = 4'd09; // assert SRAM_WE_N, go to WRITE_END if sram_addr_nxt is out of memory region
parameter WRITE_CYC3 = 4'd10; // negate SRAM_WE_N, assert ready (wdat will be captured in WRITE_CYC1)
parameter WRITE_END = 4'd11; // deassert sram control signals, go to STOP_STATE
parameter STOP_STATE = 4'd12; // full stop state
// FSM states
always @*
begin
case( curr_state )
////////////////////////////////////////////////////////////////////////
START_STATE:
next_state = INIT_STATE;
////////////////////////////////////////////////////////////////////////
INIT_STATE:
begin
if( rnw ) // read
next_state = READ_BEG;
else // !rnw - write
next_state = WRITE_BEG;
end
////////////////////////////////////////////////////////////////////////
READ_BEG:
next_state = READ_PRE;
READ_PRE:
next_state = READ_CYCLE;
READ_CYCLE:
if( !sram_addr_ctr[SRAM_ADDR_SIZE] )
next_state = READ_CYCLE;
else
next_state = READ_POST;
READ_POST:
next_state = READ_END;
READ_END:
next_state = STOP_STATE;
////////////////////////////////////////////////////////////////////////
WRITE_BEG:
next_state = WRITE_PRE1;
WRITE_PRE1:
next_state = WRITE_PRE2;
WRITE_PRE2:
next_state = WRITE_CYC2;
WRITE_CYC1:
next_state = WRITE_CYC2;
WRITE_CYC2:
if( !sram_addr_nxt[SRAM_ADDR_SIZE] )
next_state = WRITE_CYC3;
else
next_state = WRITE_END;
WRITE_CYC3:
next_state = WRITE_CYC1;
WRITE_END:
next_state = STOP_STATE;
////////////////////////////////////////////////////////////////////////
STOP_STATE:
next_state = STOP_STATE;
////////////////////////////////////////////////////////////////////////
default:
next_state = STOP_STATE;
endcase
end
// FSM flip-flops
always @(posedge clk)
begin
if( start )
curr_state <= START_STATE;
else
curr_state <= next_state;
end
// FSM outputs
always @(posedge clk)
begin
case( next_state )
////////////////////////////////////////////////////////////////////////
INIT_STATE:
begin
stop <= 1'b0;
SRAM_UB_N <= 1'b1;
SRAM_LB_N <= 1'b1;
SRAM_CE_N <= 1'b1;
SRAM_OE_N <= 1'b1;
SRAM_WE_N <= 1'b1;
dbin <= 1'b1;
sram_addr_ctr <= 0;
ready <= 1'b0;
end
////////////////////////////////////////////////////////////////////////
READ_BEG:
begin
SRAM_UB_N <= 1'b0;
SRAM_LB_N <= 1'b0;
SRAM_CE_N <= 1'b0;
SRAM_OE_N <= 1'b0;
end
READ_PRE:
begin
sram_addr_ctr <= sram_addr_nxt;
end
READ_CYCLE:
begin
ready <= 1'b1;
sram_addr_ctr <= sram_addr_nxt;
end
READ_POST:
begin
ready <= 1'b0; // in read sequence, ready and data are 2 cycles past the actual read.
end
READ_END:
begin
SRAM_UB_N <= 1'b1;
SRAM_LB_N <= 1'b1;
SRAM_CE_N <= 1'b1;
SRAM_OE_N <= 1'b1;
ready <= 1'b0;
end
////////////////////////////////////////////////////////////////////////
WRITE_BEG:
begin
SRAM_UB_N <= 1'b0;
SRAM_LB_N <= 1'b0;
SRAM_CE_N <= 1'b0;
dbin <= 1'b0;
end
WRITE_PRE1:
begin
ready <= 1'b1;
end
WRITE_PRE2:
begin
ready <= 1'b0;
end
WRITE_CYC1:
begin
ready <= 1'b0;
sram_addr_ctr <= sram_addr_nxt;
end
WRITE_CYC2:
begin
SRAM_WE_N <= 1'b0;
end
WRITE_CYC3:
begin
SRAM_WE_N <= 1'b1;
ready <= 1'b1;
end
WRITE_END:
begin
ready <= 1'b0;
SRAM_WE_N <= 1'b1;
SRAM_UB_N <= 1'b1;
SRAM_LB_N <= 1'b1;
SRAM_CE_N <= 1'b1;
end
////////////////////////////////////////////////////////////////////////
STOP_STATE:
begin
stop <= 1'b1;
end
endcase
end
endmodule