mirror of
https://github.com/garrettsworkshop/RAM2GS.git
synced 2024-11-18 15:07:12 +00:00
Added source files
This commit is contained in:
parent
f7be442af2
commit
903413e89e
406
Hardware/src/RAM4GS-AGM.v
Executable file
406
Hardware/src/RAM4GS-AGM.v
Executable file
@ -0,0 +1,406 @@
|
||||
module RAM4GS(PHI2, MAin, CROW, Din, Dout,
|
||||
nCCAS, nCRAS, nFWE,
|
||||
RBA, RA, RD, nRCS, RCLK, RCKE,
|
||||
nRWE, nRRAS, nRCAS, RDQMH, RDQML,
|
||||
nUFMCSout, UFMCLKout, UFMSDIout, UFMSDOout,
|
||||
nUFMCSin , UFMCLKin , UFMSDIin , UFMSDOin);
|
||||
|
||||
/* 65816 Phase 2 Clock */
|
||||
input PHI2;
|
||||
|
||||
/* Async. DRAM Control Inputs */
|
||||
input nCCAS, nCRAS;
|
||||
|
||||
/* Synchronized PHI2 and DRAM signals */
|
||||
reg PHI2r, PHI2r2, PHI2r3;
|
||||
reg RASr, RASr2, RASr3;
|
||||
reg CASr, CASr2, CASr3;
|
||||
reg FWEr;
|
||||
reg CBR;
|
||||
|
||||
/* 65816 Data */
|
||||
input [7:0] Din;
|
||||
output [7:0] Dout = RD[7:0];
|
||||
|
||||
/* Latched 65816 Bank Address */
|
||||
reg [7:0] Bank;
|
||||
|
||||
/* Async. DRAM Address Bus */
|
||||
input [1:0] CROW;
|
||||
input [9:0] MAin;
|
||||
input nFWE;
|
||||
reg n8MEGEN = 0;
|
||||
reg XOR8MEG = 0;
|
||||
|
||||
/* SDRAM Clock */
|
||||
input RCLK;
|
||||
|
||||
/* SDRAM */
|
||||
reg RCKEEN;
|
||||
output reg RCKE = 0;
|
||||
output reg nRCS = 1, nRRAS = 1, nRCAS = 1, nRWE = 1;
|
||||
output reg [1:0] RBA;
|
||||
reg nRowColSel;
|
||||
reg RA11;
|
||||
reg RA10;
|
||||
reg [9:0] RowA;
|
||||
output [11:0] RA;
|
||||
assign RA[11] = RA11;
|
||||
assign RA[10] = RA10;
|
||||
assign RA[9:0] = ~nRowColSel ? RowA[9:0] : MAin[9:0];
|
||||
output RDQML = ~nRowColSel ? 1'b1 : ~MAin[9];
|
||||
output RDQMH = ~nRowColSel ? 1'b1 : MAin[9];
|
||||
reg [7:0] WRD;
|
||||
inout [7:0] RD = (~nCCAS & ~nFWE) ? WRD[7:0] : 8'bZ;
|
||||
|
||||
/* UFM Interface */
|
||||
reg nUFMCS = 1;
|
||||
reg UFMCLK = 0;
|
||||
reg UFMSDI = 0;
|
||||
wire UFMSDO;
|
||||
wire UFMOsc;
|
||||
alta_ufms u_alta_ufms (
|
||||
.i_ufm_set (1'b1),
|
||||
.i_osc_ena (1'b1),
|
||||
.i_ufm_flash_csn (nUFMCS),
|
||||
.i_ufm_flash_sclk (UFMCLK),
|
||||
.i_ufm_flash_sdi (UFMSDI),
|
||||
.o_ufm_flash_sdo (UFMSDO),
|
||||
.o_osc (UFMOsc)
|
||||
);
|
||||
|
||||
/* UFM Command Interface */
|
||||
reg C1Submitted = 0;
|
||||
reg ADSubmitted = 0;
|
||||
reg CmdEnable = 0;
|
||||
reg CmdSubmitted = 0;
|
||||
reg Cmdn8MEGEN = 0;
|
||||
reg CmdUFMCLK = 0;
|
||||
reg CmdUFMSDI = 0;
|
||||
reg CmdUFMCS = 0;
|
||||
wire ADWR = Bank[7:0]==8'hFB & MAin[7:0]==8'hFF & ~nFWE;
|
||||
wire C1WR = Bank[7:0]==8'hFB & MAin[7:0]==8'hFE & ~nFWE;
|
||||
wire CMDWR = Bank[7:0]==8'hFB & MAin[7:0]==8'hFD & ~nFWE;
|
||||
|
||||
/* State Counters */
|
||||
reg InitReady = 0; // 1 if ready for init sequence
|
||||
reg Ready = 0; // 1 if done with init sequence
|
||||
reg [1:0] S = 0; // post-RAS State counter
|
||||
reg [17:0] FS = 0; // Fast init state counter
|
||||
reg [3:0] IS = 0; // Init state counter
|
||||
reg WriteDone;
|
||||
|
||||
/* Synchronize PHI2, RAS, CAS */
|
||||
always @(posedge RCLK) begin
|
||||
PHI2r <= PHI2; PHI2r2 <= PHI2r; PHI2r3 <= PHI2r2;
|
||||
RASr <= ~nCRAS; RASr2 <= RASr; RASr3 <= RASr2;
|
||||
CASr <= ~nCCAS; CASr2 <= CASr; CASr3 <= CASr2;
|
||||
end
|
||||
|
||||
/* Latch 65816 bank when PHI2 rises */
|
||||
always @(posedge PHI2) begin
|
||||
if (Ready) RA11 <= (Din[6] & ~n8MEGEN) ^ XOR8MEG; // Set RA11
|
||||
else RA11 <= 1'b0; // Reserved in mode register
|
||||
Bank[7:0] <= Din[7:0]; // Latch bank
|
||||
end
|
||||
|
||||
/* Latch bank address, row address, WE, and CAS when RAS falls */
|
||||
always @(negedge nCRAS) begin
|
||||
if (Ready) begin
|
||||
RBA[1:0] <= CROW[1:0];
|
||||
RowA[9:0] <= MAin[9:0];
|
||||
end else begin
|
||||
RBA[1:0] <= 2'b00; // Reserved in mode register
|
||||
RowA[9] <= 1'b1; // "1" for single write mode
|
||||
RowA[8] <= 1'b0; // Reserved
|
||||
RowA[7] <= 1'b0; // "0" for not test mode
|
||||
RowA[6:4] <= 3'b010; // "2" for CAS latency 2
|
||||
RowA[3] <= 1'b0; // "0" for sequential burst (not used)
|
||||
RowA[2:0] <= 3'b000; // "0" for burst length 1 (no burst)
|
||||
end
|
||||
FWEr <= ~nFWE;
|
||||
CBR <= ~nCCAS;
|
||||
end
|
||||
|
||||
/* Latch write data when CAS falls */
|
||||
always @(negedge nCCAS) begin
|
||||
WRD[7:0] <= Din[7:0];
|
||||
end
|
||||
|
||||
/* State counter from RAS */
|
||||
always @(posedge RCLK) begin
|
||||
if (~RASr2) S <= 0;
|
||||
else if (S==2'h3) S <= 2'h3;
|
||||
else S <= S+1;
|
||||
end
|
||||
/* Init state counter */
|
||||
always @(posedge RCLK) begin
|
||||
// Wait ~4.178ms (at 62.5 MHz) before starting init sequence
|
||||
FS <= FS+1;
|
||||
if (FS[17:10] == 8'hFF) InitReady <= 1'b1;
|
||||
end
|
||||
|
||||
/* SDRAM CKE */
|
||||
always @(posedge RCLK) begin
|
||||
// Only 1 LUT4 allowed for this function!
|
||||
RCKE <= ((RASr | RASr2) & RCKEEN) | (~RASr2 & RASr3);
|
||||
end
|
||||
|
||||
/* SDRAM command */
|
||||
always @(posedge RCLK) begin
|
||||
if (Ready) begin
|
||||
if (S==0) begin
|
||||
if (RASr2) begin
|
||||
if (CBR) begin
|
||||
// AREF
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end else begin
|
||||
// ACT
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // Bank RA10 consistently "1"
|
||||
end
|
||||
// Enable clock only for reads
|
||||
RCKEEN <= ~CBR & ~FWEr;
|
||||
end else if (RCKE) begin
|
||||
// PCall
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b0;
|
||||
RA10 <= 1'b1; // "all"
|
||||
RCKEEN <= 1'b1;
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
RCKEEN <= 1'b1;
|
||||
end
|
||||
nRowColSel <= 1'b0; // Select registered row addres
|
||||
end else if (S==1) begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
nRowColSel <= 1'b1; // Select asynchronous column address
|
||||
RCKEEN <= ~CBR; // Disable clock if refresh cycle
|
||||
end else if (S==2) begin
|
||||
if (~FWEr & ~CBR) begin
|
||||
// RD
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // Auto-precharge
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end
|
||||
nRowColSel <= 1'b1; // Select asynchronous column address
|
||||
RCKEEN <= ~CBR & FWEr; // Enable clock only for writes
|
||||
end else if (S==3) begin
|
||||
if (CASr2 & ~CASr3 & ~CBR & FWEr) begin
|
||||
// WR
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b0;
|
||||
RA10 <= 1'b1; // Auto-precharge
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end
|
||||
nRowColSel <= ~(~FWEr | CASr3 | CBR);
|
||||
RCKEEN <= ~(~FWEr | CASr2 | CBR);
|
||||
end
|
||||
end else if (InitReady) begin
|
||||
if (S==0 & RASr2) begin
|
||||
if (IS==0) begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end else if (IS==1) begin
|
||||
// PC all
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b0;
|
||||
RA10 <= 1'b1; // "all"
|
||||
end else if (IS==9) begin
|
||||
// Load mode register
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b0;
|
||||
RA10 <= 1'b0; // Reserved in mode register
|
||||
end else begin
|
||||
// AREF
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end
|
||||
IS <= IS+1;
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end
|
||||
if (S==3 & ~RASr2 & IS==15) Ready <= 1'b1;
|
||||
nRowColSel <= 1'b0; // Select registered row address
|
||||
RCKEEN <= 1'b1;
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
nRowColSel <= 1'b0; // Select registered row address
|
||||
RCKEEN <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
/* Submit command when PHI2 falls */
|
||||
always @(negedge PHI2) begin
|
||||
// Magic number check
|
||||
if (C1WR & Din[7:0]==8'hC1) begin // "C1" magic number
|
||||
if (ADSubmitted) begin
|
||||
CmdEnable <= 1'b1;
|
||||
end
|
||||
C1Submitted <= 1'b1;
|
||||
ADSubmitted <= 1'b0;
|
||||
end else if (ADWR & Din[7:0]==8'hAD) begin // "AD" magic number
|
||||
if (C1Submitted) begin
|
||||
CmdEnable <= 1'b1;
|
||||
end
|
||||
ADSubmitted <= 1'b1;
|
||||
C1Submitted <= 1'b0;
|
||||
end else if (C1WR | ADWR) begin // wrong magic number submitted
|
||||
CmdEnable <= 1'b0;
|
||||
C1Submitted <= 1'b0;
|
||||
ADSubmitted <= 1'b0;
|
||||
end else if (CMDWR) CmdEnable <= 1'b0;
|
||||
|
||||
// Submit command
|
||||
if (CMDWR & CmdEnable) begin
|
||||
if (Din[7:4]==4'h0) begin
|
||||
XOR8MEG <= Din[0];
|
||||
end else if (Din[7:4]==4'h1) begin
|
||||
Cmdn8MEGEN <= ~Din[0];
|
||||
CmdSubmitted <= 1'b1;
|
||||
end else if (Din[7:4]==4'h3) begin
|
||||
Cmdn8MEGEN <= n8MEGEN;
|
||||
CmdUFMCS <= Din[2];
|
||||
CmdUFMCLK <= Din[1];
|
||||
CmdUFMSDI <= Din[0];
|
||||
CmdSubmitted <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
/* UFM Control */
|
||||
output nUFMCSout = nUFMCS;
|
||||
output UFMCLKout = UFMCLK;
|
||||
output UFMSDIout = UFMSDI;
|
||||
output UFMSDOout = UFMSDO;
|
||||
input nUFMCSin;
|
||||
input UFMCLKin;
|
||||
input UFMSDIin;
|
||||
input UFMSDOin;
|
||||
always @(posedge RCLK) begin
|
||||
if (~InitReady && FS[17:10]==8'h00) begin
|
||||
nUFMCS <= 1'b1;
|
||||
UFMCLK <= 1'b0;
|
||||
UFMSDI <= 1'b0;
|
||||
end else if (~InitReady && FS[17:10]==8'h01) begin
|
||||
nUFMCS <= 1'b0;
|
||||
UFMCLK <= 1'b0;
|
||||
UFMSDI <= 1'b0;
|
||||
end else if (~InitReady && FS[17:10]==8'h02) begin
|
||||
nUFMCS <= 1'b0;
|
||||
UFMCLK <= FS[4];
|
||||
case (FS[9:5]) // Shift out read data command (0x03)
|
||||
5'h00: UFMSDI <= 1'b0; // command bit 7 (0)
|
||||
5'h01: UFMSDI <= 1'b0; // command bit 6 (0)
|
||||
5'h02: UFMSDI <= 1'b0; // command bit 5 (0)
|
||||
5'h03: UFMSDI <= 1'b0; // command bit 4 (0)
|
||||
5'h04: UFMSDI <= 1'b0; // command bit 3 (0)
|
||||
5'h05: UFMSDI <= 1'b0; // command bit 2 (0)
|
||||
5'h06: UFMSDI <= 1'b1; // command bit 1 (1)
|
||||
5'h07: UFMSDI <= 1'b1; // command bit 0 (1)
|
||||
5'h08: UFMSDI <= 1'b0; // address bit 23 (0)
|
||||
5'h09: UFMSDI <= 1'b0; // address bit 22 (0)
|
||||
5'h0A: UFMSDI <= 1'b0; // address bit 21 (0)
|
||||
5'h0B: UFMSDI <= 1'b0; // address bit 20 (0)
|
||||
5'h0C: UFMSDI <= 1'b0; // address bit 19 (0)
|
||||
5'h0D: UFMSDI <= 1'b0; // address bit 18 (0)
|
||||
5'h0E: UFMSDI <= 1'b0; // address bit 17 (0)
|
||||
5'h0F: UFMSDI <= 1'b0; // address bit 16 (0)
|
||||
5'h10: UFMSDI <= 1'b0; // address bit 15 (0)
|
||||
5'h11: UFMSDI <= 1'b0; // address bit 14 (0)
|
||||
5'h12: UFMSDI <= 1'b0; // address bit 13 (0)
|
||||
5'h13: UFMSDI <= 1'b1; // address bit 12 (0)
|
||||
5'h14: UFMSDI <= 1'b0; // address bit 11 (0)
|
||||
5'h15: UFMSDI <= 1'b0; // address bit 10 (0)
|
||||
5'h16: UFMSDI <= 1'b0; // address bit 09 (0)
|
||||
5'h17: UFMSDI <= 1'b0; // address bit 08 (0)
|
||||
5'h18: UFMSDI <= 1'b0; // address bit 07 (0)
|
||||
5'h19: UFMSDI <= 1'b0; // address bit 06 (0)
|
||||
5'h1A: UFMSDI <= 1'b0; // address bit 05 (0)
|
||||
5'h1B: UFMSDI <= 1'b0; // address bit 04 (0)
|
||||
5'h1C: UFMSDI <= 1'b0; // address bit 03 (0)
|
||||
5'h1D: UFMSDI <= 1'b0; // address bit 02 (0)
|
||||
5'h1E: UFMSDI <= 1'b0; // address bit 01 (0)
|
||||
5'h1F: UFMSDI <= 1'b0; // address bit 00 (0)
|
||||
endcase
|
||||
end else if (~InitReady && FS[17:10]==8'h03) begin
|
||||
nUFMCS <= 1'b0;
|
||||
UFMCLK <= 1'b0;
|
||||
UFMSDI <= 1'b0;
|
||||
// Latch n8MEGEN
|
||||
if (FS[9:4]==6'h00 && FS[3:0]==4'hF) n8MEGEN <= ~UFMSDO;
|
||||
end else if (~InitReady && FS[17:10]!=8'hFE && FS[17:10]!=8'hFF) begin
|
||||
nUFMCS <= 1'b0;
|
||||
UFMCLK <= FS[1];
|
||||
UFMSDI <= 1'b0;
|
||||
end else if (~InitReady) begin
|
||||
nUFMCS <= 1'b1;
|
||||
UFMCLK <= 1'b0;
|
||||
UFMSDI <= 1'b0;
|
||||
end else if (~PHI2r2 & PHI2r3 & CmdSubmitted) begin
|
||||
// Set user command signals after PHI2 falls
|
||||
// Cmdn8MEGEN, CmdUFMCS, CmdUFMCLK, CmdUFMSDI
|
||||
n8MEGEN <= Cmdn8MEGEN;
|
||||
nUFMCS <= ~CmdUFMCS;
|
||||
UFMCLK <= CmdUFMCLK;
|
||||
UFMSDI <= CmdUFMSDI;
|
||||
end
|
||||
end
|
||||
endmodule
|
406
Hardware/src/RAM4GS-ExtSPI.v
Executable file
406
Hardware/src/RAM4GS-ExtSPI.v
Executable file
@ -0,0 +1,406 @@
|
||||
module RAM4GS(PHI2, MAin, CROW, Din, Dout,
|
||||
nCCAS, nCRAS, nFWE,
|
||||
RBA, RA, RD, nRCS, RCLK, RCKE,
|
||||
nRWE, nRRAS, nRCAS, RDQMH, RDQML,
|
||||
nUFMCSout, UFMCLKout, UFMSDIout, UFMSDOout,
|
||||
nUFMCSin , UFMCLKin , UFMSDIin , UFMSDOin);
|
||||
|
||||
/* 65816 Phase 2 Clock */
|
||||
input PHI2;
|
||||
|
||||
/* Async. DRAM Control Inputs */
|
||||
input nCCAS, nCRAS;
|
||||
|
||||
/* Synchronized PHI2 and DRAM signals */
|
||||
reg PHI2r, PHI2r2, PHI2r3;
|
||||
reg RASr, RASr2, RASr3;
|
||||
reg CASr, CASr2, CASr3;
|
||||
reg FWEr;
|
||||
reg CBR;
|
||||
|
||||
/* 65816 Data */
|
||||
input [7:0] Din;
|
||||
output [7:0] Dout = RD[7:0];
|
||||
|
||||
/* Latched 65816 Bank Address */
|
||||
reg [7:0] Bank;
|
||||
|
||||
/* Async. DRAM Address Bus */
|
||||
input [1:0] CROW;
|
||||
input [9:0] MAin;
|
||||
input nFWE;
|
||||
reg n8MEGEN = 0;
|
||||
reg XOR8MEG = 0;
|
||||
|
||||
/* SDRAM Clock */
|
||||
input RCLK;
|
||||
|
||||
/* SDRAM */
|
||||
reg RCKEEN;
|
||||
output reg RCKE = 0;
|
||||
output reg nRCS = 1, nRRAS = 1, nRCAS = 1, nRWE = 1;
|
||||
output reg [1:0] RBA;
|
||||
reg nRowColSel;
|
||||
reg RA11;
|
||||
reg RA10;
|
||||
reg [9:0] RowA;
|
||||
output [11:0] RA;
|
||||
assign RA[11] = RA11;
|
||||
assign RA[10] = RA10;
|
||||
assign RA[9:0] = ~nRowColSel ? RowA[9:0] : MAin[9:0];
|
||||
output RDQML = ~nRowColSel ? 1'b1 : ~MAin[9];
|
||||
output RDQMH = ~nRowColSel ? 1'b1 : MAin[9];
|
||||
reg [7:0] WRD;
|
||||
inout [7:0] RD = (~nCCAS & ~nFWE) ? WRD[7:0] : 8'bZ;
|
||||
|
||||
/* UFM Interface */
|
||||
reg nUFMCS = 1;
|
||||
reg UFMCLK = 0;
|
||||
reg UFMSDI = 0;
|
||||
wire UFMSDO;
|
||||
wire UFMOsc;
|
||||
alta_ufms u_alta_ufms (
|
||||
.i_ufm_set (1'b1),
|
||||
.i_osc_ena (1'b1),
|
||||
.i_ufm_flash_csn (nUFMCS),
|
||||
.i_ufm_flash_sclk (UFMCLK),
|
||||
.i_ufm_flash_sdi (UFMSDI),
|
||||
.o_ufm_flash_sdo (UFMSDO),
|
||||
.o_osc (UFMOsc)
|
||||
);
|
||||
|
||||
/* UFM Command Interface */
|
||||
reg C1Submitted = 0;
|
||||
reg ADSubmitted = 0;
|
||||
reg CmdEnable = 0;
|
||||
reg CmdSubmitted = 0;
|
||||
reg Cmdn8MEGEN = 0;
|
||||
reg CmdUFMCLK = 0;
|
||||
reg CmdUFMSDI = 0;
|
||||
reg CmdUFMCS = 0;
|
||||
wire ADWR = Bank[7:0]==8'hFB & MAin[7:0]==8'hFF & ~nFWE;
|
||||
wire C1WR = Bank[7:0]==8'hFB & MAin[7:0]==8'hFE & ~nFWE;
|
||||
wire CMDWR = Bank[7:0]==8'hFB & MAin[7:0]==8'hFD & ~nFWE;
|
||||
|
||||
/* State Counters */
|
||||
reg InitReady = 0; // 1 if ready for init sequence
|
||||
reg Ready = 0; // 1 if done with init sequence
|
||||
reg [1:0] S = 0; // post-RAS State counter
|
||||
reg [17:0] FS = 0; // Fast init state counter
|
||||
reg [3:0] IS = 0; // Init state counter
|
||||
reg WriteDone;
|
||||
|
||||
/* Synchronize PHI2, RAS, CAS */
|
||||
always @(posedge RCLK) begin
|
||||
PHI2r <= PHI2; PHI2r2 <= PHI2r; PHI2r3 <= PHI2r2;
|
||||
RASr <= ~nCRAS; RASr2 <= RASr; RASr3 <= RASr2;
|
||||
CASr <= ~nCCAS; CASr2 <= CASr; CASr3 <= CASr2;
|
||||
end
|
||||
|
||||
/* Latch 65816 bank when PHI2 rises */
|
||||
always @(posedge PHI2) begin
|
||||
if (Ready) RA11 <= (Din[6] & ~n8MEGEN) ^ XOR8MEG; // Set RA11
|
||||
else RA11 <= 1'b0; // Reserved in mode register
|
||||
Bank[7:0] <= Din[7:0]; // Latch bank
|
||||
end
|
||||
|
||||
/* Latch bank address, row address, WE, and CAS when RAS falls */
|
||||
always @(negedge nCRAS) begin
|
||||
if (Ready) begin
|
||||
RBA[1:0] <= CROW[1:0];
|
||||
RowA[9:0] <= MAin[9:0];
|
||||
end else begin
|
||||
RBA[1:0] <= 2'b00; // Reserved in mode register
|
||||
RowA[9] <= 1'b1; // "1" for single write mode
|
||||
RowA[8] <= 1'b0; // Reserved
|
||||
RowA[7] <= 1'b0; // "0" for not test mode
|
||||
RowA[6:4] <= 3'b010; // "2" for CAS latency 2
|
||||
RowA[3] <= 1'b0; // "0" for sequential burst (not used)
|
||||
RowA[2:0] <= 3'b000; // "0" for burst length 1 (no burst)
|
||||
end
|
||||
FWEr <= ~nFWE;
|
||||
CBR <= ~nCCAS;
|
||||
end
|
||||
|
||||
/* Latch write data when CAS falls */
|
||||
always @(negedge nCCAS) begin
|
||||
WRD[7:0] <= Din[7:0];
|
||||
end
|
||||
|
||||
/* State counter from RAS */
|
||||
always @(posedge RCLK) begin
|
||||
if (~RASr2) S <= 0;
|
||||
else if (S==2'h3) S <= 2'h3;
|
||||
else S <= S+1;
|
||||
end
|
||||
/* Init state counter */
|
||||
always @(posedge RCLK) begin
|
||||
// Wait ~4.178ms (at 62.5 MHz) before starting init sequence
|
||||
FS <= FS+1;
|
||||
if (FS[17:10] == 8'hFF) InitReady <= 1'b1;
|
||||
end
|
||||
|
||||
/* SDRAM CKE */
|
||||
always @(posedge RCLK) begin
|
||||
// Only 1 LUT4 allowed for this function!
|
||||
RCKE <= ((RASr | RASr2) & RCKEEN) | (~RASr2 & RASr3);
|
||||
end
|
||||
|
||||
/* SDRAM command */
|
||||
always @(posedge RCLK) begin
|
||||
if (Ready) begin
|
||||
if (S==0) begin
|
||||
if (RASr2) begin
|
||||
if (CBR) begin
|
||||
// AREF
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end else begin
|
||||
// ACT
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // Bank RA10 consistently "1"
|
||||
end
|
||||
// Enable clock only for reads
|
||||
RCKEEN <= ~CBR & ~FWEr;
|
||||
end else if (RCKE) begin
|
||||
// PCall
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b0;
|
||||
RA10 <= 1'b1; // "all"
|
||||
RCKEEN <= 1'b1;
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
RCKEEN <= 1'b1;
|
||||
end
|
||||
nRowColSel <= 1'b0; // Select registered row addres
|
||||
end else if (S==1) begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
nRowColSel <= 1'b1; // Select asynchronous column address
|
||||
RCKEEN <= ~CBR; // Disable clock if refresh cycle
|
||||
end else if (S==2) begin
|
||||
if (~FWEr & ~CBR) begin
|
||||
// RD
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // Auto-precharge
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end
|
||||
nRowColSel <= 1'b1; // Select asynchronous column address
|
||||
RCKEEN <= ~CBR & FWEr; // Enable clock only for writes
|
||||
end else if (S==3) begin
|
||||
if (CASr2 & ~CASr3 & ~CBR & FWEr) begin
|
||||
// WR
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b0;
|
||||
RA10 <= 1'b1; // Auto-precharge
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end
|
||||
nRowColSel <= ~(~FWEr | CASr3 | CBR);
|
||||
RCKEEN <= ~(~FWEr | CASr2 | CBR);
|
||||
end
|
||||
end else if (InitReady) begin
|
||||
if (S==0 & RASr2) begin
|
||||
if (IS==0) begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end else if (IS==1) begin
|
||||
// PC all
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b0;
|
||||
RA10 <= 1'b1; // "all"
|
||||
end else if (IS==9) begin
|
||||
// Load mode register
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b0;
|
||||
RA10 <= 1'b0; // Reserved in mode register
|
||||
end else begin
|
||||
// AREF
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end
|
||||
IS <= IS+1;
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end
|
||||
if (S==3 & ~RASr2 & IS==15) Ready <= 1'b1;
|
||||
nRowColSel <= 1'b0; // Select registered row address
|
||||
RCKEEN <= 1'b1;
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
nRowColSel <= 1'b0; // Select registered row address
|
||||
RCKEEN <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
/* Submit command when PHI2 falls */
|
||||
always @(negedge PHI2) begin
|
||||
// Magic number check
|
||||
if (C1WR & Din[7:0]==8'hC1) begin // "C1" magic number
|
||||
if (ADSubmitted) begin
|
||||
CmdEnable <= 1'b1;
|
||||
end
|
||||
C1Submitted <= 1'b1;
|
||||
ADSubmitted <= 1'b0;
|
||||
end else if (ADWR & Din[7:0]==8'hAD) begin // "AD" magic number
|
||||
if (C1Submitted) begin
|
||||
CmdEnable <= 1'b1;
|
||||
end
|
||||
ADSubmitted <= 1'b1;
|
||||
C1Submitted <= 1'b0;
|
||||
end else if (C1WR | ADWR) begin // wrong magic number submitted
|
||||
CmdEnable <= 1'b0;
|
||||
C1Submitted <= 1'b0;
|
||||
ADSubmitted <= 1'b0;
|
||||
end else if (CMDWR) CmdEnable <= 1'b0;
|
||||
|
||||
// Submit command
|
||||
if (CMDWR & CmdEnable) begin
|
||||
if (Din[7:4]==4'h0) begin
|
||||
XOR8MEG <= Din[0];
|
||||
end else if (Din[7:4]==4'h1) begin
|
||||
Cmdn8MEGEN <= ~Din[0];
|
||||
CmdSubmitted <= 1'b1;
|
||||
end else if (Din[7:4]==4'h3) begin
|
||||
Cmdn8MEGEN <= n8MEGEN;
|
||||
CmdUFMCS <= Din[2];
|
||||
CmdUFMCLK <= Din[1];
|
||||
CmdUFMSDI <= Din[0];
|
||||
CmdSubmitted <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
/* UFM Control */
|
||||
output nUFMCSout = nUFMCS;
|
||||
output UFMCLKout = UFMCLK;
|
||||
output UFMSDIout = UFMSDI;
|
||||
output UFMSDOout = UFMSDO;
|
||||
input nUFMCSin;
|
||||
input UFMCLKin;
|
||||
input UFMSDIin;
|
||||
input UFMSDOin;
|
||||
always @(posedge RCLK) begin
|
||||
if (~InitReady && FS[17:10]==8'h00) begin
|
||||
nUFMCS <= 1'b1;
|
||||
UFMCLK <= 1'b0;
|
||||
UFMSDI <= 1'b0;
|
||||
end else if (~InitReady && FS[17:10]==8'h01) begin
|
||||
nUFMCS <= 1'b0;
|
||||
UFMCLK <= 1'b0;
|
||||
UFMSDI <= 1'b0;
|
||||
end else if (~InitReady && FS[17:10]==8'h02) begin
|
||||
nUFMCS <= 1'b0;
|
||||
UFMCLK <= FS[4];
|
||||
case (FS[9:5]) // Shift out read data command (0x03)
|
||||
5'h00: UFMSDI <= 1'b0; // command bit 7 (0)
|
||||
5'h01: UFMSDI <= 1'b0; // command bit 6 (0)
|
||||
5'h02: UFMSDI <= 1'b0; // command bit 5 (0)
|
||||
5'h03: UFMSDI <= 1'b0; // command bit 4 (0)
|
||||
5'h04: UFMSDI <= 1'b0; // command bit 3 (0)
|
||||
5'h05: UFMSDI <= 1'b0; // command bit 2 (0)
|
||||
5'h06: UFMSDI <= 1'b1; // command bit 1 (1)
|
||||
5'h07: UFMSDI <= 1'b1; // command bit 0 (1)
|
||||
5'h08: UFMSDI <= 1'b0; // address bit 23 (0)
|
||||
5'h09: UFMSDI <= 1'b0; // address bit 22 (0)
|
||||
5'h0A: UFMSDI <= 1'b0; // address bit 21 (0)
|
||||
5'h0B: UFMSDI <= 1'b0; // address bit 20 (0)
|
||||
5'h0C: UFMSDI <= 1'b0; // address bit 19 (0)
|
||||
5'h0D: UFMSDI <= 1'b0; // address bit 18 (0)
|
||||
5'h0E: UFMSDI <= 1'b0; // address bit 17 (0)
|
||||
5'h0F: UFMSDI <= 1'b0; // address bit 16 (0)
|
||||
5'h10: UFMSDI <= 1'b0; // address bit 15 (0)
|
||||
5'h11: UFMSDI <= 1'b0; // address bit 14 (0)
|
||||
5'h12: UFMSDI <= 1'b0; // address bit 13 (0)
|
||||
5'h13: UFMSDI <= 1'b1; // address bit 12 (0)
|
||||
5'h14: UFMSDI <= 1'b0; // address bit 11 (0)
|
||||
5'h15: UFMSDI <= 1'b0; // address bit 10 (0)
|
||||
5'h16: UFMSDI <= 1'b0; // address bit 09 (0)
|
||||
5'h17: UFMSDI <= 1'b0; // address bit 08 (0)
|
||||
5'h18: UFMSDI <= 1'b0; // address bit 07 (0)
|
||||
5'h19: UFMSDI <= 1'b0; // address bit 06 (0)
|
||||
5'h1A: UFMSDI <= 1'b0; // address bit 05 (0)
|
||||
5'h1B: UFMSDI <= 1'b0; // address bit 04 (0)
|
||||
5'h1C: UFMSDI <= 1'b0; // address bit 03 (0)
|
||||
5'h1D: UFMSDI <= 1'b0; // address bit 02 (0)
|
||||
5'h1E: UFMSDI <= 1'b0; // address bit 01 (0)
|
||||
5'h1F: UFMSDI <= 1'b0; // address bit 00 (0)
|
||||
endcase
|
||||
end else if (~InitReady && FS[17:10]==8'h03) begin
|
||||
nUFMCS <= 1'b0;
|
||||
UFMCLK <= 1'b0;
|
||||
UFMSDI <= 1'b0;
|
||||
// Latch n8MEGEN
|
||||
if (FS[9:4]==6'h00 && FS[3:0]==4'hF) n8MEGEN <= ~UFMSDO;
|
||||
end else if (~InitReady && FS[17:10]!=8'hFE && FS[17:10]!=8'hFF) begin
|
||||
nUFMCS <= 1'b0;
|
||||
UFMCLK <= FS[1];
|
||||
UFMSDI <= 1'b0;
|
||||
end else if (~InitReady) begin
|
||||
nUFMCS <= 1'b1;
|
||||
UFMCLK <= 1'b0;
|
||||
UFMSDI <= 1'b0;
|
||||
end else if (~PHI2r2 & PHI2r3 & CmdSubmitted) begin
|
||||
// Set user command signals after PHI2 falls
|
||||
// Cmdn8MEGEN, CmdUFMCS, CmdUFMCLK, CmdUFMSDI
|
||||
n8MEGEN <= Cmdn8MEGEN;
|
||||
nUFMCS <= ~CmdUFMCS;
|
||||
UFMCLK <= CmdUFMCLK;
|
||||
UFMSDI <= CmdUFMSDI;
|
||||
end
|
||||
end
|
||||
endmodule
|
436
Hardware/src/RAM4GS-MAX.v
Executable file
436
Hardware/src/RAM4GS-MAX.v
Executable file
@ -0,0 +1,436 @@
|
||||
module RAM4GS(PHI2, MAin, CROW, Din, Dout,
|
||||
nCCAS, nCRAS, nFWE,
|
||||
RBA, RA, RD, nRCS, RCLK, RCKE,
|
||||
nRWE, nRRAS, nRCAS, RDQMH, RDQML);
|
||||
|
||||
/* 65816 Phase 2 Clock */
|
||||
input PHI2;
|
||||
|
||||
/* Async. DRAM Control Inputs */
|
||||
input nCCAS, nCRAS;
|
||||
|
||||
/* Synchronized PHI2 and DRAM signals */
|
||||
reg PHI2r, PHI2r2, PHI2r3;
|
||||
reg RASr, RASr2, RASr3;
|
||||
reg CASr, CASr2, CASr3;
|
||||
reg FWEr;
|
||||
reg CBR;
|
||||
|
||||
/* 65816 Data */
|
||||
input [7:0] Din;
|
||||
output [7:0] Dout = RD[7:0];
|
||||
|
||||
/* Latched 65816 Bank Address */
|
||||
reg [7:0] Bank;
|
||||
|
||||
/* Async. DRAM Address Bus */
|
||||
input [1:0] CROW;
|
||||
input [9:0] MAin;
|
||||
input nFWE;
|
||||
reg n8MEGEN = 0;
|
||||
reg XOR8MEG = 0;
|
||||
|
||||
/* SDRAM Clock */
|
||||
input RCLK;
|
||||
|
||||
/* SDRAM */
|
||||
reg RCKEEN;
|
||||
output reg RCKE = 0;
|
||||
output reg nRCS = 1, nRRAS = 1, nRCAS = 1, nRWE = 1;
|
||||
output reg [1:0] RBA;
|
||||
reg nRowColSel;
|
||||
reg RA11;
|
||||
reg RA10;
|
||||
reg [9:0] RowA;
|
||||
output [11:0] RA;
|
||||
assign RA[11] = RA11;
|
||||
assign RA[10] = RA10;
|
||||
assign RA[9:0] = ~nRowColSel ? RowA[9:0] : MAin[9:0];
|
||||
output RDQML = ~nRowColSel ? 1'b1 : ~MAin[9];
|
||||
output RDQMH = ~nRowColSel ? 1'b1 : MAin[9];
|
||||
reg [7:0] WRD;
|
||||
inout [7:0] RD = (~nCCAS & ~nFWE) ? WRD[7:0] : 8'bZ;
|
||||
|
||||
/* UFM Interface */
|
||||
reg UFMD = 0; // UFM data register bit 15
|
||||
reg ARCLK = 0; // UFM address register clock
|
||||
// UFM address register data input tied to 0
|
||||
reg ARShift = 0; // 1 to Shift UFM address in, 0 to increment
|
||||
reg DRCLK = 0; // UFM data register clock
|
||||
reg DRDIn = 0; // UFM data register input
|
||||
reg DRShift = 0; // 1 to shift UFM out, 0 to load from current address
|
||||
reg UFMErase = 0; // Rising edge starts erase. UFM+RTP must not be busy
|
||||
reg UFMProgram = 0; // Rising edge starts program. UFM+RTP must not be busy
|
||||
reg UFMOscEN = 0; // UFM oscillator enable
|
||||
wire UFMBusy; // 1 if UFM is doing user operation. Asynchronous
|
||||
wire RTPBusy; // 1 if real-time programming in progress. Asynchronous
|
||||
wire DRDOut; // UFM data output
|
||||
// UFM oscillator always enabled
|
||||
wire UFMOsc; // UFM oscillator output (3.3-5.5 MHz)
|
||||
UFM UFM_inst ( // UFM IP block (for Altera MAX II and MAX V)
|
||||
.arclk (ARCLK),
|
||||
.ardin (1'b0),
|
||||
.arshft (ARShift),
|
||||
.drclk (DRCLK),
|
||||
.drdin (DRDIn),
|
||||
.drshft (DRShift),
|
||||
.erase (UFMErase),
|
||||
.oscena (UFMOscEN),
|
||||
.program (UFMProgram),
|
||||
.busy (UFMBusy),
|
||||
.drdout (DRDOut),
|
||||
.osc (UFMOsc),
|
||||
.rtpbusy (RTPBusy));
|
||||
reg UFMBusyReg = 0; // UFMBusy registered to sync with RCLK
|
||||
reg RTPBusyReg = 0; // RTPBusy registered to sync with RCLK
|
||||
|
||||
/* UFM State */
|
||||
reg UFMInitDone = 0; // 1 if UFM initialization finished
|
||||
reg UFMReqErase = 0; // 1 if UFM requires erase
|
||||
|
||||
/* UFM Command Interface */
|
||||
reg C1Submitted = 0;
|
||||
reg ADSubmitted = 0;
|
||||
reg CmdEnable = 0;
|
||||
reg CmdSubmitted = 0;
|
||||
reg Cmdn8MEGEN = 0;
|
||||
reg CmdDRCLK = 0;
|
||||
reg CmdDRDIn = 0;
|
||||
reg CmdUFMErase = 0; // Set by user command. Programs UFM
|
||||
reg CmdUFMPrgm = 0; // Set by user command. Erases UFM
|
||||
wire ADWR = Bank[7:0]==8'hFB & MAin[7:0]==8'hFF & ~nFWE;
|
||||
wire C1WR = Bank[7:0]==8'hFB & MAin[7:0]==8'hFE & ~nFWE;
|
||||
wire CMDWR = Bank[7:0]==8'hFB & MAin[7:0]==8'hFD & ~nFWE;
|
||||
|
||||
/* State Counters */
|
||||
reg InitReady = 0; // 1 if ready for init sequence
|
||||
reg Ready = 0; // 1 if done with init sequence
|
||||
reg [1:0] S = 0; // post-RAS State counter
|
||||
reg [17:0] FS = 0; // Fast init state counter
|
||||
reg [3:0] IS = 0; // Init state counter
|
||||
reg WriteDone;
|
||||
|
||||
/* Synchronize PHI2, RAS, CAS */
|
||||
always @(posedge RCLK) begin
|
||||
PHI2r <= PHI2; PHI2r2 <= PHI2r; PHI2r3 <= PHI2r2;
|
||||
RASr <= ~nCRAS; RASr2 <= RASr; RASr3 <= RASr2;
|
||||
CASr <= ~nCCAS; CASr2 <= CASr; CASr3 <= CASr2;
|
||||
end
|
||||
|
||||
/* Latch 65816 bank when PHI2 rises */
|
||||
always @(posedge PHI2) begin
|
||||
if (Ready) RA11 <= (Din[6] & ~n8MEGEN) ^ XOR8MEG; // Set RA11
|
||||
else RA11 <= 1'b0; // Reserved in mode register
|
||||
Bank[7:0] <= Din[7:0]; // Latch bank
|
||||
end
|
||||
|
||||
/* Latch bank address, row address, WE, and CAS when RAS falls */
|
||||
always @(negedge nCRAS) begin
|
||||
if (Ready) begin
|
||||
RBA[1:0] <= CROW[1:0];
|
||||
RowA[9:0] <= MAin[9:0];
|
||||
end else begin
|
||||
RBA[1:0] <= 2'b00; // Reserved in mode register
|
||||
RowA[9] <= 1'b1; // "1" for single write mode
|
||||
RowA[8] <= 1'b0; // Reserved
|
||||
RowA[7] <= 1'b0; // "0" for not test mode
|
||||
RowA[6:4] <= 3'b010; // "2" for CAS latency 2
|
||||
RowA[3] <= 1'b0; // "0" for sequential burst (not used)
|
||||
RowA[2:0] <= 3'b000; // "0" for burst length 1 (no burst)
|
||||
end
|
||||
FWEr <= ~nFWE;
|
||||
CBR <= ~nCCAS;
|
||||
end
|
||||
|
||||
/* Latch write data when CAS falls */
|
||||
always @(negedge nCCAS) begin
|
||||
WRD[7:0] <= Din[7:0];
|
||||
end
|
||||
|
||||
/* State counter from RAS */
|
||||
always @(posedge RCLK) begin
|
||||
if (~RASr2) S <= 0;
|
||||
else if (S==2'h3) S <= 2'h3;
|
||||
else S <= S+1;
|
||||
end
|
||||
/* Init state counter */
|
||||
always @(posedge RCLK) begin
|
||||
// Wait ~4.178ms (at 62.5 MHz) before starting init sequence
|
||||
FS <= FS+1;
|
||||
if (FS[17:10] == 8'hFF) InitReady <= 1'b1;
|
||||
end
|
||||
|
||||
/* SDRAM CKE */
|
||||
always @(posedge RCLK) begin
|
||||
// Only 1 LUT4 allowed for this function!
|
||||
RCKE <= ((RASr | RASr2) & RCKEEN) | (~RASr2 & RASr3);
|
||||
end
|
||||
|
||||
/* SDRAM command */
|
||||
always @(posedge RCLK) begin
|
||||
if (Ready) begin
|
||||
if (S==0) begin
|
||||
if (RASr2) begin
|
||||
if (CBR) begin
|
||||
// AREF
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end else begin
|
||||
// ACT
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // Bank RA10 consistently "1"
|
||||
end
|
||||
// Enable clock only for reads
|
||||
RCKEEN <= ~CBR & ~FWEr;
|
||||
end else if (RCKE) begin
|
||||
// PCall
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b0;
|
||||
RA10 <= 1'b1; // "all"
|
||||
RCKEEN <= 1'b1;
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
RCKEEN <= 1'b1;
|
||||
end
|
||||
nRowColSel <= 1'b0; // Select registered row addres
|
||||
end else if (S==1) begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
nRowColSel <= 1'b1; // Select asynchronous column address
|
||||
RCKEEN <= ~CBR; // Disable clock if refresh cycle
|
||||
end else if (S==2) begin
|
||||
if (~FWEr & ~CBR) begin
|
||||
// RD
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // Auto-precharge
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end
|
||||
nRowColSel <= 1'b1; // Select asynchronous column address
|
||||
RCKEEN <= ~CBR & FWEr; // Enable clock only for writes
|
||||
end else if (S==3) begin
|
||||
if (CASr2 & ~CASr3 & ~CBR & FWEr) begin
|
||||
// WR
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b0;
|
||||
RA10 <= 1'b1; // Auto-precharge
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end
|
||||
nRowColSel <= ~(~FWEr | CASr3 | CBR);
|
||||
RCKEEN <= ~(~FWEr | CASr2 | CBR);
|
||||
end
|
||||
end else if (InitReady) begin
|
||||
if (S==0 & RASr2) begin
|
||||
if (IS==0) begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end else if (IS==1) begin
|
||||
// PC all
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b0;
|
||||
RA10 <= 1'b1; // "all"
|
||||
end else if (IS==9) begin
|
||||
// Load mode register
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b0;
|
||||
RA10 <= 1'b0; // Reserved in mode register
|
||||
end else begin
|
||||
// AREF
|
||||
nRCS <= 1'b0;
|
||||
nRRAS <= 1'b0;
|
||||
nRCAS <= 1'b0;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end
|
||||
IS <= IS+1;
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
end
|
||||
if (S==3 & ~RASr2 & IS==15) Ready <= 1'b1;
|
||||
nRowColSel <= 1'b0; // Select registered row address
|
||||
RCKEEN <= 1'b1;
|
||||
end else begin
|
||||
// NOP
|
||||
nRCS <= 1'b1;
|
||||
nRRAS <= 1'b1;
|
||||
nRCAS <= 1'b1;
|
||||
nRWE <= 1'b1;
|
||||
RA10 <= 1'b1; // RA10 is don't care
|
||||
nRowColSel <= 1'b0; // Select registered row address
|
||||
RCKEEN <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
/* Submit command when PHI2 falls */
|
||||
always @(negedge PHI2) begin
|
||||
// Magic number check
|
||||
if (C1WR & Din[7:0]==8'hC1) begin // "C1" magic number
|
||||
if (ADSubmitted) begin
|
||||
CmdEnable <= 1'b1;
|
||||
UFMOscEN <= 1'b1;
|
||||
end
|
||||
C1Submitted <= 1'b1;
|
||||
ADSubmitted <= 1'b0;
|
||||
end else if (ADWR & Din[7:0]==8'hAD) begin // "AD" magic number
|
||||
if (C1Submitted) begin
|
||||
CmdEnable <= 1'b1;
|
||||
UFMOscEN <= 1'b1;
|
||||
end
|
||||
ADSubmitted <= 1'b1;
|
||||
C1Submitted <= 1'b0;
|
||||
end else if (C1WR | ADWR) begin // wrong magic number submitted
|
||||
CmdEnable <= 1'b0;
|
||||
C1Submitted <= 1'b0;
|
||||
ADSubmitted <= 1'b0;
|
||||
end else if (CMDWR) CmdEnable <= 1'b0;
|
||||
|
||||
// Submit command
|
||||
if (CMDWR & CmdEnable) begin
|
||||
if (Din[7:4]==4'h0) begin
|
||||
XOR8MEG <= Din[0];
|
||||
end else if (Din[7:4]==4'h1) begin
|
||||
Cmdn8MEGEN <= ~Din[0];
|
||||
CmdSubmitted <= 1'b1;
|
||||
end else if (Din[7:4]==4'h2) begin
|
||||
Cmdn8MEGEN <= n8MEGEN;
|
||||
CmdUFMErase <= Din[3];
|
||||
CmdUFMPrgm <= Din[2];
|
||||
CmdDRCLK <= Din[1];
|
||||
CmdDRDIn <= Din[0];
|
||||
CmdSubmitted <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
/* UFM Control */
|
||||
always @(posedge RCLK) begin
|
||||
if (~Ready) begin
|
||||
if (~UFMInitDone & FS[17:16]==2'b00) begin
|
||||
// Shift 0 into address register
|
||||
ARCLK <= FS[3]; // Clock address register
|
||||
ARShift <= 1'b1; // Shift 0 into address register
|
||||
DRCLK <= 1'b0; // Don't clock data register
|
||||
DRDIn <= 1'b0; // DRDIn is don't care
|
||||
DRShift <= 1'b0; // DRShift is don't care
|
||||
end else if (~UFMInitDone & FS[17:16]==2'b01 & FS[7:4]==4'h0) begin
|
||||
// Parallel transfer UFM data to shift register
|
||||
ARCLK <= 1'b0; // Don't clock address register
|
||||
ARShift <= 1'b0; // ARShift is don't care
|
||||
DRCLK <= FS[3]; // Clock data register
|
||||
DRDIn <= 1'b0; // DRDIn is don't care
|
||||
DRShift <= 1'b0; // Parallel transfer to data register
|
||||
end else if (~UFMInitDone & FS[17:16]==2'b01 & FS[7:4]==4'h4) begin
|
||||
// Shift UFM
|
||||
ARCLK <= 1'b0; // Don't clock address register
|
||||
ARShift <= 1'b0; // ARShift is don't care
|
||||
DRCLK <= FS[3]; // Clock data register
|
||||
DRDIn <= 1'b0; // DRDIn is don't care
|
||||
DRShift <= 1'b1; // Shift data register
|
||||
// Capture bit 15 of this UFM word in UFMD register
|
||||
if (FS[3:0]==4'h7) UFMD <= DRDOut;
|
||||
end else if (~UFMInitDone & FS[17:16]==2'b01 & FS[7:4]==4'h5) begin
|
||||
// Check saved capacity entry
|
||||
if (UFMD) UFMInitDone <= 1'b1; // If erased, quit iterating
|
||||
else begin // If valid setting here
|
||||
n8MEGEN <= ~DRDOut; // Set capacity setting
|
||||
// If last byte in sector, mark need to erase
|
||||
if (FS[15:8]==8'hFF) begin
|
||||
UFMReqErase <= 1'b1; // Mark need to wrap around
|
||||
UFMInitDone <= 1'b1; // Quit iterating
|
||||
end
|
||||
end
|
||||
end else if (~UFMInitDone & FS[17:16]==2'b01 & FS[7:4]==4'h6) begin
|
||||
// Increment UFM address
|
||||
ARCLK <= FS[3]; // Clock address register
|
||||
ARShift <= 1'b0; // Increment UFM address
|
||||
DRCLK <= 1'b0; // Don't clock data register
|
||||
DRDIn <= 1'b0; // DRDIn is don't care
|
||||
DRShift <= 1'b0; // DRShift is don't care
|
||||
end else if (FS[17:16]==2'b10 & UFMReqErase) begin
|
||||
// Shift 0 into address register
|
||||
ARCLK <= FS[3]; // Clock address register
|
||||
ARShift <= 1'b1; // Shift 0 into address register
|
||||
DRCLK <= 1'b0; // Don't clock data register
|
||||
DRDIn <= 1'b0; // DRDIn is don't care
|
||||
DRShift <= 1'b0; // DRShift is don't care
|
||||
end else begin
|
||||
// Don't do anything with UFM
|
||||
ARCLK <= 1'b0; // Don't clock address register
|
||||
ARShift <= 1'b0; // ARShift is don't care
|
||||
DRCLK <= 1'b0; // Don't clock data register
|
||||
DRDIn <= 1'b0; // DRDIn is don't care
|
||||
DRShift <= 1'b0; // DRShift is don't care
|
||||
end
|
||||
|
||||
// Don't erase or program UFM during initialization
|
||||
UFMErase <= 1'b0;
|
||||
UFMProgram <= 1'b0;
|
||||
end else begin
|
||||
// Can only shift UFM data register now
|
||||
ARCLK <= 1'b0;
|
||||
ARShift <= 1'b0;
|
||||
DRShift <= 1'b1;
|
||||
|
||||
// Set user command signals after PHI2 falls
|
||||
if (~PHI2r2 & PHI2r3 & CmdSubmitted) begin
|
||||
n8MEGEN <= Cmdn8MEGEN;
|
||||
DRCLK <= CmdDRCLK;
|
||||
DRDIn <= CmdDRDIn;
|
||||
end
|
||||
|
||||
// UFM programming sequence
|
||||
if (CmdUFMPrgm | CmdUFMErase) begin
|
||||
if (~UFMBusyReg & ~RTPBusyReg) begin
|
||||
if (UFMReqErase | CmdUFMErase) UFMErase <= 1'b1;
|
||||
else if (CmdUFMPrgm) UFMProgram <= 1'b1;
|
||||
end else if (UFMBusyReg) UFMReqErase <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user