Added source files

This commit is contained in:
Zane Kaminski 2021-04-29 18:53:26 -04:00
parent f7be442af2
commit 903413e89e
3 changed files with 1248 additions and 0 deletions

406
Hardware/src/RAM4GS-AGM.v Executable file
View 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
View 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
View 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