diff --git a/Hardware/src/RAM4GS-AGM.v b/Hardware/src/RAM4GS-AGM.v new file mode 100755 index 0000000..291a060 --- /dev/null +++ b/Hardware/src/RAM4GS-AGM.v @@ -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 diff --git a/Hardware/src/RAM4GS-ExtSPI.v b/Hardware/src/RAM4GS-ExtSPI.v new file mode 100755 index 0000000..291a060 --- /dev/null +++ b/Hardware/src/RAM4GS-ExtSPI.v @@ -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 diff --git a/Hardware/src/RAM4GS-MAX.v b/Hardware/src/RAM4GS-MAX.v new file mode 100755 index 0000000..ac5eb43 --- /dev/null +++ b/Hardware/src/RAM4GS-MAX.v @@ -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