GR8RAM/cpld/GR8RAM.v
Zane Kaminski 0c8bf7ebe5 SPI?
2023-06-07 18:52:44 -04:00

541 lines
14 KiB
Verilog

module GR8RAM(C25M, PHI0, nRES, nRESout, SetFW,
INTin, INTout, DMAin, DMAout,
GNDout1, GNDout2, nIRQout, RWout, nDMAout,
RA, PU, nWE, RD, RAdir, RDdir, nIOSEL, nDEVSEL, nIOSTRB,
SBA, SA, nRCS, nRAS, nCAS, nSWE, DQML, DQMH, RCKE, SD,
nFCS, FCK, MISO, MOSI);
/* Clock signals */
input C25M, PHI0;
/* PHI0 synchronization to 25 MHz clock */
reg [2:0] PHI0r;
always @(posedge C25M) PHI0r <= { PHI0r[1:0], PHI0 };
/* Reset synchronization */
input nRES; reg nRESr = 0;
always @(posedge C25M) begin
if (PS==15) nRESr <= nRES;
end
/* Firmware select */
input [1:0] SetFW;
wire [1:0] SetROM = ~SetFW[1:0];
wire SetENRestore = SetROM[1:0]==2'b11;
wire SetEN24bit = SetROM[1];
/* State counter from PHI0 rising edge */
reg [3:0] PS = 0;
wire PSStart = PS==0 && PHI0r[0] && !PHI0r[1];
always @(posedge C25M) begin
if (PSStart) PS <= 1;
else if (PS==0) PS <= 0;
else PS <= PS+1;
end
/* Long state counter: counts from 0 to $3FFF */
reg [13:0] LS = 0;
always @(posedge C25M) begin if (PS==15) LS <= LS+1; end
/* Init state */
output reg nRESout = 0;
reg [2:0] IS = 0;
always @(posedge C25M) begin
if (IS==7) nRESout <= 1;
else if (PS==15) begin
if (LS==14'h1FCE) IS <= 1; // PC all + load mode
else if (LS==14'h1FCF) IS <= 4; // AREF pause, SPI select
else if (LS==14'h1FFA) IS <= 5; // SPI flash command
else if (LS==14'h1FFF) IS <= 6; // Flash load driver
else if (LS==14'h3FFF) IS <= 7; // Operating mode
end
end
/* Apple IO area select signals */
input nIOSEL, nDEVSEL, nIOSTRB;
/* Apple address bus */
input [15:0] RA;
input nWE;
input PU;
wire RA4 = RA[4] && PU;
/* Apple select signals */
wire RAMExists = !SetEN24bit || !Addr[23] ;
wire BankSEL = REGEN && !nDEVSEL && RA[3:0]==4'hF;
wire SPITXSEL = REGEN && !nDEVSEL && (RA[3:0]==4'hC || RA[3:0]==4'hD) &&
!RestoreDone && SetENRestore;
wire RAMSEL = REGEN && !nDEVSEL && RA[3:0]==4'h3;
wire AddrHSEL = REGEN && !nDEVSEL && RA[3:0]==4'h2;
wire AddrMSEL = REGEN && !nDEVSEL && RA[3:0]==4'h1;
wire AddrLSEL = REGEN && !nDEVSEL && RA[3:0]==4'h0;
/* Slot number detect */
reg SlotKnown = 0;
reg [2:0] Slot;
always @(negedge PHI0) begin
if (!nIOSEL) begin
SlotKnown <= 1;
Slot <= RA[10:8];
end
end
/* RAM/ROM speculative select */
wire RAMSpecSEL = RA[15:8]==8'hC0 && RA[7] && RA[3:0]==4'h3 && REGEN;
wire IOSELSpecSEL = RA[15:12]==4'hC && !RA[11] && (RA[10:8]==Slot[2:0] || !SlotKnown);
wire IOSTRBSpecSEL = RA[15:12]==4'hC && RA[11] && IOROMEN;
wire RAMROMSpecSEL = RAMSpecSEL || IOSELSpecSEL || IOSTRBSpecSEL;
reg RAMROMSpecSELr; always @(posedge PHI0) RAMROMSpecSELr <= RAMROMSpecSEL;
/* IOROMEN control */
reg IOROMEN = 0;
wire IOROMRES = !nIOSTRB && RA[10:0]==11'h7FF;
always @(posedge C25M, posedge IOROMRES) begin
if (IOROMRES) IOROMEN <= 0;
else if (!nRESr) IOROMEN <= 0;
else if (!nIOSEL) IOROMEN <= 1;
end
/* REGEN control */
reg REGEN = 0;
always @(posedge C25M, negedge nRESr) begin
if (!nRESr) REGEN <= 0;
else if (PS==8 && !nIOSEL) REGEN <= 1;
end
/* Apple data bus */
wire RDOEbase = PHI0 && nWE &&
((!nDEVSEL && RAMExists) || !nIOSEL || (!nIOSTRB && IOROMEN));
reg [7:0] RDD;
inout [7:0] RD = (RDOEbase && PHI0r[2]) ? RDD[7:0] : 8'bZ;
output RDdir = !(RDOEbase && PHI0r[1]);
/* Slinky address registers */
reg [23:0] Addr = 0;
reg AddrIncL = 0;
reg AddrIncM = 0;
reg AddrIncH = 0;
always @(posedge C25M, negedge nRESr) begin
if (!nRESr) begin
Addr[23:0] <= 24'h000000;
end else begin
if (PS==8 && RAMSEL) AddrIncL <= 1;
else AddrIncL <= 0;
if (PS==8 && AddrLSEL && !nWE) begin
Addr[7:0] <= RD[7:0];
AddrIncM <= Addr[7] && !RD[7];
end else if (AddrIncL) begin
Addr[7:0] <= Addr[7:0]+1;
AddrIncM <= Addr[7:0]==8'hFF;
end else AddrIncM <= 0;
if (PS==8 && AddrMSEL && !nWE) begin
Addr[15:8] <= RD[7:0];
AddrIncH <= Addr[15] && !RD[7];
end else if (AddrIncM) begin
Addr[15:8] <= Addr[15:8]+1;
AddrIncH <= Addr[15:8]==8'hFF;
end else AddrIncH <= 0;
if (PS==8 && AddrHSEL && !nWE) begin
Addr[23:16] <= RD[7:0];
end else if (AddrIncH) begin
Addr[23:16] <= Addr[23:16]+1;
end
end
end
/* ROM bank register */
reg Bank;
always @(negedge PHI0, negedge nRESr) begin
if (!nRESr) Bank <= 0;
else if (BankSEL && !nWE) Bank <= RD[0];
end
/* Restore state */
reg RestoreDone = 0;
always @(negedge PHI0, negedge SetENRestore) begin
if (!SetENRestore) RestoreDone <= 1;
else if (BankSEL && !nWE && RD[1]) RestoreDone <= 1;
end
/* Flash chip select register */
reg FCS = 0;
always @(negedge PHI0, posedge RestoreDone) begin
if (RestoreDone) FCS <= 0;
else if (BankSEL && !nWE) FCS <= RD[0];
end
/* SPI flash control signals */
output reg nFCS = 1;
reg FCKout; output FCK = FCKout;
inout MOSI = MOSIOE ? MOSIout : 1'bZ;
reg MOSIOE;
input MISO;
always @(posedge C25M) begin
case (PS[3:0])
0: FCKout <= 1'b1; // NOP CKE
1: FCKout <= !(IS==5 || IS==6); // ACT
2: FCKout <= 1'b1; // RD
3: FCKout <= !(IS==5 || IS==6); // NOP CKE
4: FCKout <= 1'b1; // NOP CKE
5: FCKout <= !(IS==5 || IS==6); // NOP CKE
6: FCKout <= 1'b1; // NOP CKE
7: FCKout <= !(IS==5 || IS==6 || SPITXSEL); // NOP CKE
8: FCKout <= 1'b1; // WR AP
9: FCKout <= !(IS==5); // NOP CKE
10: FCKout <= 1'b1; // PC all
11: FCKout <= !(IS==5); // AREF
12: FCKout <= 1'b1; // NOP CKE
13: FCKout <= !(IS==5); // NOP CKE
14: FCKout <= 1'b1; // NOP CKE
15: FCKout <= !(IS==5); // NOP CKE
endcase
nFCS <= !(IS==4 || IS==5 || IS==6 || FCS);
MOSIOE <= IS==5 || (IS==7 && SetENRestore && !RestoreDone);
end
/* SPI flash MOSI control */
reg MOSIout = 0;
always @(posedge C25M) begin
case (PS[3:0])
1: case (LS[1:0])
2'h3: MOSIout <= 1'b0; // Command bit 7
2'h0: MOSIout <= 1'b0; // Address bit 23
2'h1: MOSIout <= 1'b0; // Address bit 15
2'h2: MOSIout <= 1'b0; // Address bit 7
endcase 3: case (LS[1:0])
2'h3: MOSIout <= 1'b0; // Command bit 6
2'h0: MOSIout <= 1'b0; // Address bit 22
2'h1: MOSIout <= SetROM[1]; // Address bit 14
2'h2: MOSIout <= 1'b0; // Address bit 6
endcase 5: case (LS[1:0])
2'h3: MOSIout <= 1'b1; // Command bit 5
2'h0: MOSIout <= 1'b0; // Address bit 21
2'h1: MOSIout <= SetROM[0]; // Address bit 13
2'h2: MOSIout <= 1'b0; // Address bit 5
endcase 7: begin
if (!nRESout) case (LS[1:0])
2'h3: MOSIout <= 1'b1; // Command bit 4
2'h0: MOSIout <= 1'b0; // Address bit 20
2'h1: MOSIout <= 1'b0; // Address bit 12
2'h2: MOSIout <= 1'b0; // Address bit 4
endcase else MOSIout <= RA[0];
end 9: case (LS[1:0])
2'h3: MOSIout <= 1'b1; // Command bit 3
2'h0: MOSIout <= 1'b0; // Address bit 19
2'h1: MOSIout <= 1'b0; // Address bit 11
2'h2: MOSIout <= 1'b0; // Address bit 3
endcase 11: case (LS[1:0])
2'h3: MOSIout <= 1'b0; // Command bit 2
2'h0: MOSIout <= 1'b0; // Address bit 18
2'h1: MOSIout <= 1'b0; // Address bit 10
2'h2: MOSIout <= 1'b0; // Address bit 2
endcase 13: case (LS[1:0])
2'h3: MOSIout <= 1'b1; // Command bit 1
2'h0: MOSIout <= 1'b0; // Address bit 16
2'h1: MOSIout <= 1'b0; // Address bit 9
2'h2: MOSIout <= 1'b0; // Address bit 1
endcase 15: case (LS[1:0])
2'h3: MOSIout <= 1'b1; // Command bit 0
2'h0: MOSIout <= 1'b0; // Address bit 15
2'h1: MOSIout <= 1'b0; // Address bit 7
2'h2: MOSIout <= 1'b0; // Address bit 0
endcase
endcase
end
/* SDRAM data bus */
inout [7:0] SD = SDOE ? WRD[7:0] : 8'bZ;
reg [7:0] WRD;
reg SDOE = 0;
always @(posedge C25M) begin
case (PS[3:0])
0: begin // NOP CKE
if (IS==6) WRD[7:0] <= { WRD[5:0], MISO, MOSI };
else WRD[7:0] <= RD[7:0];
end 1: begin // ACT
end 2: begin // RD
if (IS==6) WRD[7:0] <= { WRD[5:0], MISO, MOSI };
else WRD[7:0] <= RD[7:0];
end 3: begin // NOP CKE
end 4: begin // NOP CKE
if (IS==6) WRD[7:0] <= { WRD[5:0], MISO, MOSI };
else WRD[7:0] <= RD[7:0];
end 5: begin // NOP CKE
end 6: begin // NOP CKE
if (IS==6) WRD[7:0] <= { WRD[5:0], MISO, MOSI };
else WRD[7:0] <= RD[7:0];
end 7: begin // NOP CKE
end 8: begin // WR AP
if (IS==6) WRD[7:0] <= { WRD[5:0], MISO, MOSI };
else WRD[7:0] <= RD[7:0];
end 9: begin // NOP CKE
end 10: begin // PC all
if (IS==6) WRD[7:0] <= { WRD[5:0], MISO, MOSI };
else WRD[7:0] <= RD[7:0];
end 11: begin // AREF
end 12: begin // NOP CKE
if (IS==6) WRD[7:0] <= { WRD[5:0], MISO, MOSI };
else WRD[7:0] <= RD[7:0];
end 13: begin // NOP CKE
end 14: begin // NOP CKE
if (IS==6) WRD[7:0] <= { WRD[5:0], MISO, MOSI };
else WRD[7:0] <= RD[7:0];
end 15: begin // NOP CKE
end
endcase
end
/* Apple data bus from SDRAM */
always @(negedge C25M) begin
if (PS==5) begin
if (!nDEVSEL) case (RA[3:0])
4'h0: RDD[7:0] <= Addr[7:0];
4'h1: RDD[7:0] <= Addr[15:8];
4'h2: RDD[7:0] <= { SetEN24bit ? Addr[23:20] : 4'hF, Addr[19:16] };
4'h3: RDD[7:0] <= SD[7:0];
4'hF: RDD[7:0] <= { MISO, SD[6:0] };
default: RDD[7:0] <= SD[7:0];
endcase else RDD[7:0] <= SD[7:0];
end
end
/* SDRAM command */
output reg RCKE = 1;
output reg nRCS = 1;
output reg nRAS = 1;
output reg nCAS = 1;
output reg nSWE = 1;
wire RefReqd = LS[1:0] == 2'b11;
always @(posedge C25M) begin
case (PS[3:0])
0: begin // NOP CKE / NOP CKD
RCKE <= PSStart && (IS==6 || (IS==7 && RAMROMSpecSELr));
nRCS <= 1;
nRAS <= 1;
nCAS <= 1;
nSWE <= 1;
SDOE <= 0;
end 1: begin // ACT CKE / NOP CKD (ACT)
RCKE <= RCKE;
nRCS <= !RCKE;
nRAS <= 0;
nCAS <= 1;
nSWE <= 1;
SDOE <= 0;
end 2: begin // RD CKE / NOP CKD (RD)
RCKE <= RCKE;
nRCS <= !RCKE;
nRAS <= 1;
nCAS <= 0;
nSWE <= 1;
SDOE <= 0;
end 3: begin // NOP CKE / CKD
RCKE <= RCKE;
nRCS <= 1;
nRAS <= 1;
nCAS <= 1;
nSWE <= 1;
SDOE <= 0;
end 4: begin // NOP CKD
RCKE <= 0;
nRCS <= 1;
nRAS <= 1;
nCAS <= 1;
nSWE <= 1;
SDOE <= 0;
end 5: begin // NOP CKD
RCKE <= 0;
nRCS <= 1;
nRAS <= 1;
nCAS <= 1;
nSWE <= 1;
SDOE <= 0;
end 6: begin // NOP CKD
RCKE <= 0;
nRCS <= 1;
nRAS <= 1;
nCAS <= 1;
nSWE <= 1;
SDOE <= 0;
end 7: begin // NOP CKE / CKD
RCKE <= IS==6 || (RAMSEL && !nWE && IS==7);
nRCS <= 1;
nRAS <= 1;
nCAS <= 1;
nSWE <= 1;
SDOE <= 0;
end 8: begin // WR AP CKE / NOP CKD (WR AP)
RCKE <= RCKE;
nRCS <= !RCKE;
nRAS <= 1;
nCAS <= 0;
nSWE <= 0;
SDOE <= RCKE;
end 9: begin // NOP CKE / NOP CKD
RCKE <= 1;
nRCS <= 1;
nRAS <= 1;
nCAS <= 1;
nSWE <= 1;
SDOE <= 0;
end 10: begin // PC all CKE / PC all CKD
RCKE <= IS==1 || IS==4 || IS==5 || IS==6 || (IS==7 && RefReqd);
nRCS <= 0;
nRAS <= 0;
nCAS <= 1;
nSWE <= 0;
SDOE <= 0;
end 11: begin // LDM CKE / AREF CKE / NOP CKD
RCKE <= RCKE;
nRCS <= !RCKE;
nRAS <= 0;
nCAS <= 0;
nSWE <= !(IS==1);
SDOE <= 0;
end default: begin // NOP CKD
RCKE <= 0;
nRCS <= 1;
nRAS <= 1;
nCAS <= 1;
nSWE <= 1;
SDOE <= 0;
end
endcase
end
/* SDRAM address */
output reg DQML = 1;
output reg DQMH = 1;
output reg [1:0] SBA;
output reg [12:0] SA;
always @(posedge C25M) begin
case (PS[3:0])
0: begin // NOP CKE
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0011000100000;
end 1: begin // ACT
DQML <= 1'b1;
DQMH <= 1'b1;
if (IS==6) begin
SBA[1:0] <= 2'b10;
SA[12:0] <= { 10'b0011000100, LS[12:10] };
end else if (nIOSEL && nIOSTRB) begin
SBA[1:0] <= { 1'b0, SetEN24bit ? Addr[22] : 1'b0 };
SA[12:10] <= SetEN24bit ? { 1'b0, Addr[21:20] } : 3'b000;
SA[9:0] <= Addr[19:10];
end else if (!nIOSTRB) begin
SBA[1:0] <= 2'b10;
SA[12:0] <= { 10'b0011000100, Bank, 1'b1, RA[10] };
end else begin // IOSEL
SBA[1:0] <= 2'b10;
SA[12:0] <= { 10'b0011000100, !RestoreDone, 1'b0, RA[10] };
end
end 2: begin // RD
if (nIOSEL && nIOSTRB) begin
SBA[1:0] <= { 1'b0, SetEN24bit ? Addr[22] : 1'b0 };
SA[12:0] <= { 4'b0011, Addr[9:1] };
DQML <= Addr[0];
DQMH <= !Addr[0];
end else begin
SBA[1:0] <= 2'b10;
SA[12:0] <= { 4'b0011, RA[9:5], RA4, RA[3:1]};
DQML <= RA[0];
DQMH <= !RA[0];
end
end 3: begin // NOP CKE
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0011000100000;
end 4: begin // NOP CKE
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0011000100000;
end 5: begin // NOP CKE
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0011000100000;
end 6: begin // NOP CKE
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0011000100000;
end 7: begin // NOP CKE
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0011000100000;
end 8: begin // WR AP
if (IS==6) begin
SBA[1:0] <= 2'b10;
SA[12:0] <= { 4'b0011, LS[9:1] };
DQML <= LS[0];
DQMH <= !LS[0];
end else begin
SBA[1:0] <= { 1'b0, SetEN24bit ? Addr[22] : 1'b0 };
SA[12:0] <= { 4'b0011, Addr[9:1] };
DQML <= Addr[0];
DQMH <= !Addr[0];
end
end 9: begin // NOP CKE
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0011000100000;
end 10: begin // PC all
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0011000100000;
end 11: begin // AREF / load mode
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0001000100000;
end 12: begin // NOP CKE
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0011000100000;
end 13: begin // NOP CKE
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0011000100000;
end 14: begin // NOP CKE
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0011000100000;
end 15: begin // NOP CKE
DQML <= 1'b1;
DQMH <= 1'b1;
SBA[1:0] <= 2'b00;
SA[12:0] <= 13'b0011000100000;
end
endcase
end
/* DMA/INT in/out */
input INTin, DMAin;
output INTout = INTin;
output DMAout = DMAin;
/* Unused Pins */
output RAdir = 1;
output nDMAout = 1;
output nIRQout = 1;
output RWout = 1;
/* Grounds next to PU */
output GNDout1 = 0;
output GNDout2 = 0;
endmodule