mirror of
https://github.com/MiSTer-devel/MemTest_MiSTer.git
synced 2026-04-19 03:04:31 +00:00
276 lines
7.3 KiB
Verilog
276 lines
7.3 KiB
Verilog
/*
|
|
read sequence
|
|
|
|
clk ``\____/````\____/` ..... _/````\____/````\____/` ..... _/````\____/````\____/`
|
|
| | | | | | |
|
|
start XXXX```````````\__ ....... ____________________________________________________
|
|
| | | | | | |
|
|
rnw XXXXXX```XXXXXXXXX ....... XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
| | some | | | | |
|
|
ready XXXXXXX\__________ clocks __/`````````````````` ....... ```````````\__________
|
|
before | |
|
|
rdat ------------------ ready -< cell 0 | cell 1 | ....... |last cell>-----------
|
|
| | | | | | |
|
|
done 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 | | | | | |
|
|
done XXXXXXXX\_________ ....... _____________ .... ______________ .... ____________/```````````````````
|
|
| | strobe | | strobe | | | | | |
|
|
|
|
*/
|
|
|
|
|
|
module sdram
|
|
(
|
|
input clk,
|
|
input rst_n, // total reset
|
|
|
|
input start, // start sequence
|
|
output reg done, // =1 when operation is done,
|
|
// also done=0 while reset SDRAM initialisation is in progress
|
|
|
|
input rnw, // 1 - read, 0 - write sequence (latched when start=1)
|
|
output reg ready, // strobe. when writing, one means that data from wdat written to the memory
|
|
// when reading, one means that data read from memory is on rdat output
|
|
|
|
input [15:0] wdat, // input, data to be written to memory
|
|
output reg [15:0] rdat, // output, data last read from memory
|
|
|
|
input [1:0] sz,
|
|
input [1:0] chip,
|
|
|
|
output DRAM_CLK,
|
|
output DRAM_LDQM,DRAM_UDQM,
|
|
output DRAM_WE_N,
|
|
output DRAM_CAS_N,
|
|
output DRAM_RAS_N,
|
|
output DRAM_CS_N,
|
|
output DRAM_BA_0,
|
|
output DRAM_BA_1,
|
|
inout reg [15:0] DRAM_DQ,
|
|
output [12:0] DRAM_ADDR
|
|
);
|
|
|
|
assign {DRAM_BA_1,DRAM_BA_0} = ba;
|
|
assign DRAM_ADDR = sdaddr;
|
|
assign DRAM_WE_N = cmd[0];
|
|
assign DRAM_CAS_N = cmd[1];
|
|
assign DRAM_RAS_N = cmd[2];
|
|
assign DRAM_CS_N = cs;
|
|
assign {DRAM_UDQM,DRAM_LDQM} = DRAM_ADDR[12:11];
|
|
|
|
reg [12:0] sdaddr, sdaddr2;
|
|
reg [1:0] ba, ba2;
|
|
reg [2:0] cmd, cmd2;
|
|
reg cs, cs2;
|
|
|
|
wire [2:0] CMD_NOP = 3'b111;
|
|
wire [2:0] CMD_ACTIVE = 3'b011;
|
|
wire [2:0] CMD_READ = 3'b101;
|
|
wire [2:0] CMD_WRITE = 3'b100;
|
|
wire [2:0] CMD_PRECHARGE = 3'b010;
|
|
wire [2:0] CMD_AUTO_REFRESH = 3'b001;
|
|
wire [2:0] CMD_LOAD_MODE = 3'b000;
|
|
|
|
|
|
reg [4:0] initstate;
|
|
reg init_done;
|
|
always @ (posedge clk) begin
|
|
if(!rst_n) begin
|
|
initstate <= 0;
|
|
init_done <= 0;
|
|
end else begin
|
|
if (state == 5) begin
|
|
if(~&initstate) initstate <= initstate + 4'd1;
|
|
else init_done <= 1;
|
|
end
|
|
end
|
|
end
|
|
|
|
reg ready2;
|
|
always @ (posedge clk) begin
|
|
ready2 <= 0;
|
|
if(wr) case(state) 3,4,5,6: ready2 <= 1; endcase
|
|
if(rd) case(state) 2,3,4,5: ready2 <= 1; endcase
|
|
end
|
|
|
|
reg [2:0] state;
|
|
reg wr,rd,wr2,done2;
|
|
always @ (posedge clk) begin
|
|
reg [9:0] cas_addr, cas_addr2;
|
|
reg [23:0] addr, addr2, addr3; // x4
|
|
reg [5:0] rcnt = 0;
|
|
reg rnw_reg;
|
|
reg [1:0] rfsh;
|
|
reg [15:0] rdat2,rdat3;
|
|
reg done3;
|
|
reg [4:0] is, is2, is3;
|
|
reg [2:0] st;
|
|
reg id;
|
|
reg [2:0] cas_cmd, cas_cmd2;
|
|
reg wdat_req;
|
|
|
|
st <= st + 1'd1;
|
|
state <= st;
|
|
|
|
DRAM_DQ <= 16'bZ;
|
|
|
|
wr <= wr2;
|
|
wdat_req <= wr2 & ready2;
|
|
if(wdat_req) DRAM_DQ <= wdat;
|
|
|
|
rdat3 <= DRAM_DQ;
|
|
rdat2 <= rdat3;
|
|
rdat <= rdat2;
|
|
cmd2 <= CMD_NOP;
|
|
|
|
is3 <= initstate;
|
|
is2 <= is3;
|
|
is <= is2;
|
|
id <= init_done;
|
|
|
|
if(!id) begin
|
|
cs2 <= is[4];
|
|
|
|
if(state == 1) begin
|
|
case(is[3:0])
|
|
2 : begin
|
|
sdaddr2[10]<= 1; // all banks
|
|
cmd2 <= CMD_PRECHARGE;
|
|
end
|
|
4,7 : begin
|
|
cmd2 <= CMD_AUTO_REFRESH;
|
|
end
|
|
10, 13 : begin
|
|
cmd2 <= CMD_LOAD_MODE;
|
|
sdaddr2 <= 13'b000_0_00_011_0_010; // WRITE BURST, LATENCY=3, BURST=4
|
|
end
|
|
endcase
|
|
end
|
|
wr2 <= 0;
|
|
wr <= 0;
|
|
rd <= 0;
|
|
rcnt <= 0;
|
|
done2<= 0;
|
|
end
|
|
else if(done2) begin
|
|
rd <= 0;
|
|
wr2 <= 0;
|
|
wr <= 0;
|
|
if (chip == 2'h2) begin
|
|
addr <= 24'h800000;
|
|
addr2 <= 24'h800000;
|
|
end else begin
|
|
addr <= 0;
|
|
addr2 <= 0;
|
|
end
|
|
st <= 0;
|
|
done3 <= 0;
|
|
if(start) begin
|
|
done2 <= 0;
|
|
rnw_reg <= rnw;
|
|
end
|
|
end
|
|
else begin
|
|
case(state)
|
|
0: begin
|
|
rcnt <= rcnt + 1'd1;
|
|
if(rcnt == 50) rcnt <= 0;
|
|
|
|
rfsh <= 0;
|
|
if(rcnt >= 49) rfsh <= {1'b1, rcnt[0]};
|
|
addr3 <= addr;
|
|
end
|
|
|
|
// RAS
|
|
1 : begin
|
|
cas_cmd2 <= CMD_NOP;
|
|
wr2 <= 0;
|
|
if(rfsh[1]) begin
|
|
cmd2 <= CMD_AUTO_REFRESH;
|
|
cs2 <= rfsh[0];
|
|
end
|
|
else if(~done3) begin
|
|
{cs2,cas_addr2[9],cas_addr2[8:2],sdaddr2,ba2,cas_addr2[1:0]} <= {addr3, 2'b00};
|
|
wr2 <= ~rnw_reg;
|
|
cas_cmd2<= rnw_reg ? CMD_READ : CMD_WRITE;
|
|
cmd2 <= CMD_ACTIVE;
|
|
addr2 <= addr + 1'd1;
|
|
end
|
|
end
|
|
|
|
2 : begin
|
|
addr <= addr2;
|
|
cas_addr <= cas_addr2;
|
|
cas_cmd <= cas_cmd2;
|
|
end
|
|
|
|
// CAS
|
|
4 : begin
|
|
sdaddr2 <= {1'b1, cas_addr}; // AUTO PRECHARGE
|
|
cmd2 <= cas_cmd;
|
|
end
|
|
|
|
7: begin
|
|
if(chip == 0 && sz == 3 && &addr[23:0]) done3 <= 1;
|
|
if(chip == 1 && sz == 3 && &addr[22:0]) done3 <= 1;
|
|
if(chip == 2 && sz == 3 && &addr[23:0]) done3 <= 1;
|
|
if(sz == 2 && &addr[22:0]) done3 <= 1;
|
|
if(sz <= 1 && &addr[21:0]) done3 <= 1;
|
|
rd <= (cas_cmd == CMD_READ);
|
|
if(done3) done2 <= 1;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
always @ (posedge clk) begin
|
|
sdaddr <= sdaddr2;
|
|
ba <= ba2;
|
|
cmd <= cmd2;
|
|
cs <= cs2;
|
|
ready <= ready2;
|
|
done <= done2;
|
|
end
|
|
|
|
altddio_out
|
|
#(
|
|
.extend_oe_disable("OFF"),
|
|
.intended_device_family("Cyclone V"),
|
|
.invert_output("OFF"),
|
|
.lpm_hint("UNUSED"),
|
|
.lpm_type("altddio_out"),
|
|
.oe_reg("UNREGISTERED"),
|
|
.power_up_high("OFF"),
|
|
.width(1)
|
|
)
|
|
sdramclk_ddr
|
|
(
|
|
.datain_h(1'b0),
|
|
.datain_l(1'b1),
|
|
.outclock(clk),
|
|
.dataout(DRAM_CLK),
|
|
.aclr(1'b0),
|
|
.aset(1'b0),
|
|
.oe(1'b1),
|
|
.outclocken(1'b1),
|
|
.sclr(1'b0),
|
|
.sset(1'b0)
|
|
);
|
|
|
|
endmodule
|