Sketch of verilog

This commit is contained in:
Zane Kaminski 2020-10-07 23:32:29 -04:00
parent 089fee98b8
commit 13c6a59278
1 changed files with 577 additions and 253 deletions

View File

@ -1,275 +1,599 @@
module GR8RAM(C7M, C7M_2, Q3, PHI0in, PHI1in, nRES, nMode,
A, RA, nWE, D, RD,
nDEVSEL, nIOSEL, nIOSTRB,
nRAS, nCAS0, nCAS1, nRCS, nROE, nRWE);
module GR8RAM(C25M, PHI1, nIOSEL, nDEVSEL, nIOSTRB,
RA, RB6, nRWE, nROE, nAOE, Adir, nRCS,
RD, nDOE, Ddir,
SBA, SA, nSCS, nRAS, nCAS, nSWE, DQML, DQMH, SCKE, SD,
nRST, nPreBOD,
DMAin, DMAout, INTin, INTout,
nIRQout, nINHout, nDMAout, nNMIout);
/* Clock, Reset, Mode */
input C7M, C7M_2, Q3, PHI0in, PHI1in; // Clock inputs
input nRES;
/* Clock inputs */
input C25M, PHI1;
wire PHI0 = ~PHI1;
/* PHI1 Delay */
wire [8:0] PHI1b;
wire PHI1;
LCELL PHI1b0_MC (.in(PHI1in), .out(PHI1b[0]));
LCELL PHI1b1_MC (.in(PHI1b[0]), .out(PHI1b[1]));
LCELL PHI1b2_MC (.in(PHI1b[1]), .out(PHI1b[2]));
LCELL PHI1b3_MC (.in(PHI1b[2]), .out(PHI1b[3]));
LCELL PHI1b4_MC (.in(PHI1b[3]), .out(PHI1b[4]));
LCELL PHI1b5_MC (.in(PHI1b[4]), .out(PHI1b[5]));
LCELL PHI1b6_MC (.in(PHI1b[5]), .out(PHI1b[6]));
LCELL PHI1b7_MC (.in(PHI1b[6]), .out(PHI1b[7]));
LCELL PHI1b8_MC (.in(PHI1b[7]), .out(PHI1b[8]));
LCELL PHI1b9_MC (.in(PHI1b[8] & PHI1in), .out(PHI1));
/* Address Bus, etc. */
input nDEVSEL, nIOSEL, nIOSTRB; // Card select signals
input [15:0] A; // 6502 address bus
input nWE; // 6502 R/W
output [10:0] RA; // DRAM/ROM address
assign RA[10:8] = CASel ? Addr[21:19] : Addr[10:8];
assign RA[7:0] =
(~nIOSTRB & ~FullIOEN) ? {7'b0000001, Bank[0]} :
(~nIOSTRB & FullIOEN) ? Bank+1 :
( nIOSTRB & ~CASel & nIOSEL) ? Addr[18:11] :
( nIOSTRB & CASel & nIOSEL) ? Addr[7:0] : 8'h00;
/* Select Signals */
wire BankSELA = A[3:0]==4'hF;
wire MagicSELA = A[3:0]==4'hE;
wire TCntHSELA = A[3:0]==4'hB;
wire TCntLSELA = A[3:0]==4'hA;
wire DestHSELA = A[3:0]==4'h9;
wire DestLSELA = A[3:0]==4'h8;
wire RAMSELA = A[3:0]==4'h3;
wire AddrHSELA = A[3:0]==4'h2;
wire AddrMSELA = A[3:0]==4'h1;
wire AddrLSELA = A[3:0]==4'h0;
LCELL BankWR_MC (.in(BankSELA & ~nWE & ~nDEVSEL & REGEN), .out(BankWR)); wire BankWR;
LCELL MagicWR_MC (.in(MagicSELA & ~nWE & ~nDEVSEL & REGEN), .out(MagicWR)); wire MagicWR;
LCELL TCntHWR_MC (.in(TCntHSELA & ~nWE & ~nDEVSEL & REGEN), .out(TCntHWR)); wire TCntHWR;
LCELL TCntLWR_MC (.in(TCntLSELA & ~nWE & ~nDEVSEL & REGEN), .out(TCntLWR)); wire TCntLWR;
LCELL DestHWR_MC (.in(DestHSELA & ~nWE & ~nDEVSEL & REGEN), .out(DestHWR)); wire DestHWR;
LCELL DestLWR_MC (.in(DestLSELA & ~nWE & ~nDEVSEL & REGEN), .out(DestLWR)); wire DestLWR;
LCELL RAMSEL_MC (.in(RAMSELA & ~nDEVSEL & REGEN), .out(RAMSEL)); wire RAMSEL;
LCELL AddrHWR_MC (.in(AddrHSELA & ~nWE & ~nDEVSEL & REGEN), .out(AddrHWR)); wire AddrHWR;
LCELL AddrMWR_MC (.in(AddrMSELA & ~nWE & ~nDEVSEL & REGEN), .out(AddrMWR)); wire AddrMWR;
LCELL AddrLWR_MC (.in(AddrLSELA & ~nWE & ~nDEVSEL & REGEN), .out(AddrLWR)); wire AddrLWR;
/* Data Bus Routing */
// DRAM/ROM data bus
wire RDOE = DBEN & ~nWE;
inout [7:0] RD = RDOE ? D[7:0] : 8'bZ;
// Apple II data bus
wire DOE = DBEN & nWE &
((~nDEVSEL & REGEN) | ~nIOSEL | (~nIOSTRB & IOROMEN));
wire [7:0] Dout = (nDEVSEL | RAMSELA) ? RD[7:0] :
AddrHSELA ? Addr[23:16] :
AddrMSELA ? Addr[15:8] :
AddrLSELA ? Addr[7:0] : 8'h00;
inout [7:0] D = DOE ? Dout : 8'bZ;
/* DRAM and ROM Control Signals */
output nRCS = ~((~nIOSEL | (~nIOSTRB & IOROMEN)) & CSEN); // ROM chip select
output nROE = ~nWE; // need this for flash ROM
output nRWE = CASel ? nWE : 1'b1; // for ROM & DRAM
output nRAS = ~(RASr | RASf);
output nCAS0 = ~(CAS0f | (CASr & RAMSEL & ~Addr[22])); // DRAM CAS bank 0
output nCAS1 = ~(CAS1f | (CASr & RAMSEL & Addr[22])); // DRAM CAS bank 1
/* 6502-accessible Registers */
reg REGEN = 0; // Register enable
reg IOROMEN = 0; // IOSTRB ROM enable
reg FullIOEN = 0; // Set to enable full I/O ROM space
reg PDMARDEN = 0;
reg PDMAWREN = 0;
reg [7:0] Bank = 0; // Bank register for ROM access
reg [23:0] Addr = 0; // RAM address register
/* RAM Address Register Increment Control */
reg IncAddrL = 0, IncAddrM = 0, IncAddrH = 0;
/* Pseudo-DMA Transfer Counters */
reg [9:0] TCnt = 0;
reg [15:0] Dest = 0;
/* Transfer Counter Increment Control */
reg PDMANext = 0, IncDestH = 0;
/* CAS rising/falling edge components */
// These are combined to create the CAS outputs.
reg CASr = 0, CAS0f = 0, CAS1f = 0;
reg RASr = 0, RASf = 0;
reg CASel = 0; // DRAM address multiplexer select
/* State Counters */
reg PHI1reg = 0; // Saved PHI1 at last rising clock edge
reg PHI0seen = 0; // Have we seen PHI0 since reset?
reg [2:0] S = 0; // State counter
reg [3:0] Ref = 0; // Refresh skip counter
reg DBEN = 0; // Data bus driver gating
reg CSEN = 0; // ROM CS enable gating
/* Configuration */
input Mode;
// Apple II Bus Compatibiltiy Rules:
// Synchronize to PHI0 or PHI1. (PHI1 here)
// PHI1's edge may be -20ns,+10ns relative to C7M.
// Delay the rising edge of PHI1 to get enough hold time:
// PHI1modified = PHI1 & PHI1delayed;
// Only sample /DEVSEL, /IOSEL at these times:
// 2nd and 3rd rising edge of C7M in PHI0 (S4, S5)
// all 3 falling edges of C7M in PHI0 (S4, S5, S6)
// Can sample /IOSTRB at same times as /IOSEL, plus:
// 1st rising edge of C7M in PHI0 (S3)
/* State counters */
always @(posedge C7M) begin
// Synchronize state counter to S1 when just entering PHI1
PHI1reg <= PHI1; // Save old PHI1
if (~PHI1) PHI0seen <= 1; // PHI0seen set in PHI0
S <= (PHI1 & ~PHI1reg & PHI0seen) ? 4'h1 :
S==0 ? 3'h0 :
S==7 ? 3'h7 : S+1;
// Refresh counter allows DRAM refresh once every 13 cycles
if (S==3) Ref <= (Ref[3:2]==2'b11) ? 4'h0 : Ref+1;
/* Reset inputs */
input nRST, nPreBOD;
reg nRSTr0;
always @(posedge C25M) begin
nRSTr0 <= nRST;
end
/* State-based data bus and ROM CS gating */
always @(posedge C7M, negedge nRES) begin
if (~nRES) begin
DBEN <= 0;
CSEN <= 0;
end else begin
// Only drive Apple II data bus after S4 to avoid bus fight.
// Thus we wait 1.5 7M cycles (210 ns) into PHI0 before driving.
// Same for driving the ROM/SRAM data bus (RD).
DBEN <= S==4 | S==5 | S==6 | S==7;
// Similarly, only select the ROM chip starting at
// the end of S4 for reads and the end of S5 for writes.
// This ensures that write data is valid for
// the entire time that the ROM is selected,
// and minimizes power consumption.
CSEN <= (S==4 & nWE) | S==5 | S==6 | S==7;
end
/* Select inputs */
input nIOSEL, nDEVSEL, nIOSTRB;
/* Synchronized select inputs */
reg nDEVSELr0, nDEVSELr1;
reg nIOSELr0;
reg nIOSTRBr0;
always @(posedge C25M) begin
nDEVSELr0 <= nDEVSEL;
nDEVSELr1 <= nDEVSELr0;
nIOSELr0 <= nIOSEL;
nIOSTRBr0 <= nIOSTRB;
end
/* DEVSEL-based state counter */
wire [9:0] DEVSELe = {DEVSELer[9:1], nDEVSELr1 && ~nDEVSELr0 && nRSTr0}
reg [9:1] DEVSELer;
always @(posedge C25M) begin
DEVSELer[9:1] <= DEVSELe[8:0];
end
/* DEVSEL register and IOSTRB ROM enable */
always @(posedge C7M, negedge nRES) begin
if (~nRES) begin
REGEN <= 0;
IOROMEN <= 0;
end else begin
// Enable registers at end of S4 when IOSEL accessed (Cn00-CnFF).
if (S==4 & ~nIOSEL) REGEN <= 1'b1;
/* Flash Control */
output nRCS = ~((~nIOSEL || (~nIOSTRB && IOROMEN)) && CSDBEN && nRST);
output nROE = ~nRWE;
// Enable IOSTRB ROM when accessing CnXX in IOSEL ROM.
if (S==4 & ~nIOSEL) IOROMEN <= 1'b1;
// Disable IOSTRB ROM when accessing 0xCFFF.
if (S==4 & ~nIOSTRB & A[10:0]==11'h7FF) IOROMEN <= 1'b0;
end
/* 6502/Flash Data Bus */
inout RD = RDOE ? Rdout : 8'bZ;
wire RDOE = ~nDEVSEL && nRST;
wire RDout =
AddrLSelA ? Addr[7:0] :
AddrMSelA ? Addr[15:8] :
AddrHSelA ? Addr[23:16] :
DataSelA ? Addr==0 ? Data0[7:0] : Data[7:0] :
8'h57;
output nDOE = ~((~nDEVSEL || ~nIOSEL || (~nIOSTRB && IOROMEN)) && CSDBEN && nRST);
output Ddir = ~nRWE;
/* Data bus / ROM chip select delay */
reg CSDBEN = 0;
always @(posedge C25M, negedge nRST) begin
if (~nRST) CSDBEN <= 1'b0;
else CSDBEN <= ~nDEVSELr0 || ~nIOSELr0 || ~nIOSTRBr0;
end
/* Set registers */
always @(negedge C7M, negedge nRES) begin
if (~nRES) begin
/* IOROMEN control */
wire IOROMEN = IOROMEN0 ^ IOROMEN1;
reg IOROMEN0 = 0;
reg IOROMEN1 = 0;
always @(negedge nIOSEL, negedge nRST) begin
if (~nRST) IOROMEN0 <= 1'b0; // On reset, set both to 0; 0 ^ 0 == 0
else IOROMEN0 <= ~IOROMEN1; // Enable; X ^ ~X == 1
end
always @(negedge nIOSTRB, negedge nRST) begin
if (~nRST) IOROMEN1 <= 1'b0; // On reset, set both to 0; 0 ^ 0 == 0
else if (RA[10:0] == 11'h7FF) IOROMEN1 <= IOROMEN0; // Disable; X^X==0
end
/* 6502/Flash Address Bus */
input [15:0] RA;
input nRWE;
output nAOE = 0;
output Adir = 1;
reg [3:0] RAr;
reg nRWEr;
always @(posedge nDEVSEL) begin
// Latch RA and nRWE at end of DEVSEL access
RAr[3:0] <= RA[3:0];
nRWEr <= nRWE;
end
/* Register Select Signals */
wire AddrLSelA = RA[3:0] == 4'h0;
wire AddrMSelA = RA[3:0] == 4'h1;
wire AddrHSelA = RA[3:0] == 4'h2;
wire DataSelA = RA[3:0] == 4'h3;
wire DMAAddrLSelA = RA[3:0] == 4'h4;
wire DMAAddrHSelA = RA[3:0] == 4'h5;
wire DMALenLSelA = RA[3:0] == 4'h6;
wire DMALenHSelA = RA[3:0] == 4'h7;
wire MagicSelA = RA[3:0] == 4'h8;
wire CfgSelA = RA[3:0] == 4'h9;
wire RAMMaskSelA = RA[3:0] == 4'hB;
wire BankHSelA = RA[3:0] == 4'hE;
wire BankLSelA = RA[3:0] == 4'hF;
/* SDRAM Address / Flash Bank Bus */
output [1:0] SBA = SAmux ? SBAreg[1:0] :
~nIOSTRB ? {
BankC8[4], // SBA0, Bank4
BankC8[2] // SBA1, Bank2
} : { // IOSEL
1'b1, // SBA0, Bank4
1'b1 // SBA1, Bank2
};
output [12:0] SA = SAmux ? SAreg[12:0] :
~nIOSTRB ? {
SAreg[0], // SA0
BankC8[11], // SA1, Bank11
BankC8[8] ^ BankCX[8], // SA2, Bank8
SAreg[3], // SA3
SAreg[4], // SA4
ExtBankEN ? BankC8[7] : 1'b0, // SA5, Bank7
SAreg[6], // SA6
BankC8[10], // SA7, Bank10
BankC8[9] ^ BankCX[9], // SA8, Bank9
BankC8[1], // SA9, Bank1
BankC8[0], // SA10, Bank0
BankC8[3], // SA11, Bank3
BankC8[5] // SA12, Bank5
} : { // IOSEL
SAreg[0], // SA0
1'b0, // SA1, Bank11
BankCX[8], // SA2, Bank8
SAreg[3], // SA3
SAreg[4], // SA4
1'b1, // SA5, Bank7
SAreg[6], // SA6
1'b0, // SA7, Bank10
BankCX[9], // SA8, Bank9
1'b1, // SA9, Bank1
1'b1, // SA10, Bank0
1'b1, // SA11, Bank3
1'b1 // SA12, Bank5
};
output RB6 = ~nIOSEL ? 1'b1 : BankC8[6];
reg SAmux = 1'b0;
reg [1:0] SBAreg;
reg [12:0] SAreg;
/* SDRAM Data Bus */
inout [7:0] SD = SDOE ? WRD : 8'bZ;
reg SDOE = 0;
reg [7:0] WRD = 0;
always @(posedge nDEVSEL) begin
WRD[7:0] <= RD[7:0];
if (nRSTr0 && DataSelA && ~nRWE && Addr==0) Data0[7:0] <= RD[7:0];
end
/* SDRAM Control Bus */
output reg nSCS = 1;
output reg nRAS = 1;
output reg nCAS = 1;
output reg nSWE = 1;
output reg DQML = 1;
output reg DQMH = 1;
output reg SCKE = 1;
/* INT/DMA in/out */
input DMAin;
input INTin;
output DMAout = DMAin;
output INTout = INTin;
/* IRQ, NMI, DMA, INH outputs (open-drain is external) */
output nIRQ = 1;
output nNMI = 1;
output nDMA = 1;
output nINH = 1;
/* Refresh/Init Counter */
reg [19:0] Tick;
always @(posedge C25M) begin
Tick <= Tick+1;
end
reg InitDone = 0;
always @(posedge C25M) begin
if (Tick[19:0]==20'hFFFFF) InitDone <= 1'b1;
end
reg RefWake = 0;
reg RefDone = 0;
/* User-Accessible Registers */
reg [23:0] Addr = 0;
reg [7:0] Data = 0;
reg [7:0] Data0 = 0;
reg [11:0] BankC8 = 0; // Bits 9:8 are XORed with BankCX
reg [9:8] BankCX = 0; // Bank CX is init value
reg ExtBankEN = 0;
/* Set/Increment Address Register */
always @(posedge C25M, negedge nRST) begin
if (~nRST) begin
Addr <= 0;
Bank <= 0;
FullIOEN <= 0;
PDMARDEN <= 0;
PDMAWREN <= 0;
IncAddrL <= 0;
IncAddrM <= 0;
IncAddrH <= 0;
end else begin
// Increment address register
if (S==1 & IncAddrL) begin
IncAddrL <= 0;
Addr[7:0] <= Addr[7:0]+1;
IncAddrM <= Addr[7:0] == 8'hFF;
end
if (S==2 & IncAddrM) begin
IncAddrM <= 0;
Addr[15:8] <= Addr[15:8]+1;
IncAddrH <= Addr[15:8] == 8'hFF;
end
if (S==3 & IncAddrH) begin
IncAddrH <= 0;
Addr[23:16] <= Addr[23:16]+1;
end
// Set register in middle of S6 if accessed.
if (S==6) begin
if (BankWR) begin
Bank[7:0] <= D[7:0];
PDMARDEN <= D[7:0]==8'h10 & FullIOEN;
PDMAWREN <= D[7:0]==8'h10 & FullIOEN;
if (DEVSELe[0] && ~nRWEr) begin // Write address register
if (RAr[3:0]==4'h0) begin // AddrL
Addr[7:0] <= WRD[7:0];
if (Addr[7] & ~WRD[7]) Addr[23:8] <= Addr[23:8]+1;
end else if (RAr[3:0]==4'h1) begin // AddrM
Addr[15:8] <= WRD[7:0];
if (Addr[15] & ~WRD[7]) Addr[23:16] <= Addr[23:16]+1;
end else if (RAr[3:0]==4'h2) begin // AddrH
Addr[23:16] <= WRD[7:0];
end
if (MagicWR) FullIOEN <= D[7:0] == 8'hE5;
IncAddrL <= RAMSEL;
IncAddrM <= AddrLWR & Addr[7] & ~D[7];
IncAddrH <= AddrMWR & Addr[15] & ~D[7];
if (AddrHWR) Addr[23:16] <= D[7:0]; // Addr hi
if (AddrMWR) Addr[15:8] <= D[7:0]; // Addr mid
if (AddrLWR) Addr[7:0] <= D[7:0]; // Addr lo
end else if (DEVSELe[2] && RAr[3:0]==4'h3) begin // R/W data
Addr[23:0] <= Addr[23:0]+1;
end
end
end
/* Pseudo-DMA transfer counters */
always @(negedge C7M, negedge nRES) begin
if (~nRES) begin
TCnt <= 0;
Dest <= 0;
PDMANext <= 0;
IncDestH <= 0;
/* Set bank */
always @(posedge nDEVSEL, negedge nRST) begin
if (~nRST) begin
BankC8 <= 0;
end else begin
// Increment destination pointer and decrement transfer counter
if (S==1 & PDMANext) begin
PDMANext <= 0;
Dest[7:0] <= Dest[7:0]+1;
IncDestH <= Dest[7:0] == 8'hFF;
TCnt <= TCnt-1;
end
if (S==2 & IncDestH) begin
IncDestH <= 0;
Dest[15:8] <= Dest[15:8]+1;
end
// Set register in middle of S6 if accessed.
if (S==6) begin
PDMANext <= RAMSEL;
if (TCntHWR) TCnt[15:8] <= D[7:0]; // TCnt hi
if (TCntLWR) TCnt[7:0] <= D[7:0]; // TCnt lo
if (DestHWR) Dest[15:8] <= D[7:0]; // Dest hi
if (DestLWR) Dest[7:0] <= D[7:0]; // Dest lo
if (~nRWE) begin
if (RAr[3:0]==4'hE && ExtBankEN) begin
BankC8[11:10] <= WRD[3:2];
BankC8[9:8] <= WRD[1:0] ^ BankCX[9:8];
end else if (RAr[3:0]==4'hF) begin
BankC8[7] <= WRD[7] & ExtBankEN;
BankC8[6:0] <= WRD[6:0];
end
end
end
end
/* DRAM RAS/CAS */
always @(posedge C7M) begin
RASr <= (S==1 & Ref==0) | // Refresh
(S==4 & RAMSEL & nWE) | // Read: Early RAS
(S==5 & RAMSEL & ~nWE); // Write: Late RAS
CASel = (RAMSEL & nWE & S==4) | // Read: mux address early
(RAMSEL & ~nWE & S==5); // Write: mux address late
// Read: long, early CAS, gated later by RAMSEL
CASr <= (nWE & (S==5 | S==6 | S==7));
/* Latch read data */
always @(posedge C25M) begin
if (DEVSELe[9]) Data[7:0] <= SDD[7:0];
end
always @(negedge C7M) begin
RASf <= (S==4 & RAMSEL & nWE) | // Read: Early RAS
(S==5 & RAMSEL & ~nWE); // Write: Late RAS
CAS0f <= (S==1 & Ref==0) | // Refresh
(S==5 & RAMSEL & ~Addr[22] & nWE) | // Read: Early CAS
(S==6 & RAMSEL & ~Addr[22] & ~nWE); // Write: Late CAS
CAS1f <= (S==1 & Ref==0) | // Refresh
(S==5 & RAMSEL & Addr[22] & nWE) | // Read: Early CAS
(S==6 & RAMSEL & Addr[22] & ~nWE); // Write: Late CAS
/* SDRAM Control */
always @(posedge C25M) begin
if (~InitDone) begin
if (Tick[19:8]==12'hFFF) begin
if (Tick[3:0]==4'h8) begin
if (Tick[7:4]==4'h0) begin
// PC all
SCKE <= 1'b1;
nSCS <= 1'b0;
nRAS <= 1'b0;
nCAS <= 1'b1;
nSWE <= 1'b0;
DQML <= 1'b1;
DQMH <= 1'b1;
SAreg[10] <= 1'b1; // "all"
end else if (Tick[7:4]==4'h7) begin
// Load mode register
SCKE <= 1'b1;
nSCS <= 1'b0;
nRAS <= 1'b0;
nCAS <= 1'b0;
nSWE <= 1'b0;
DQML <= 1'b1;
DQMH <= 1'b1;
SAreg[11] <= 1'b0; // Reserved in mode register
end else begin
// AREF
SCKE <= 1'b1;
nSCS <= 1'b0;
nRAS <= 1'b0;
nCAS <= 1'b0;
nSWE <= 1'b1;
DQML <= 1'b1;
DQMH <= 1'b1;
end
end else begin
// NOP
SCKE <= 1'b1;
nSCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nSWE <= 1'b1;
DQML <= 1'b1;
DQMH <= 1'b1;
end
end else begin
// NOP ckdis
SCKE <= 1'b0;
nSCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nSWE <= 1'b1;
DQML <= 1'b1;
DQMH <= 1'b1;
end
// Mode register contents
SBAreg[1:0] <= 2'b00; // Reserved
SAreg[11] <= 1'b0; // Reserved
SAreg[9] <= 1'b1; // "1" for single write mode
SAreg[8] <= 1'b0; // Reserved
SAreg[7] <= 1'b0; // "0" for not test mode
SAreg[6:4] <= 3'b010; // "2" for CAS latency 2
SAreg[3] <= 1'b0; // "0" for sequential burst (not used)
SAreg[2:0] <= 3'b000; // "0" for burst length 1 (no burst)
SAmux <= 1'b1;
RefDone <= 1'b0;
RefWake <= 1'b0;
end else if (DEVSELe[0] && RAr[3:0]==4'h3) begin
// NOP
SCKE <= ~nRWEr;
nSCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nSWE <= 1'b1;
DQML <= 1'b1;
DQMH <= 1'b1;
SAmux <= 1'b1;
RefWake <= 1'b0;
end else if (DEVSELe[1] && RAr[3:0]==4'h3) begin
// ACT
SCKE <= ~nRWEr;
nSCS <= nRWEr;
nRAS <= 1'b0;
nCAS <= 1'b1;
nSWE <= 1'b1;
DQML <= 1'b1;
DQMH <= 1'b1;
// Row address
SBAreg[1:0] <= Addr[23:22];
SAreg[12] <= 1'b0;
SAreg[11:0] <= Addr[21:10];
SAmux <= 1'b1;
RefWake <= 1'b0;
end else if (DEVSELe[2] && RAr[3:0]==4'h3) begin
// WR/NOP
SCKE <= ~nRWEr;
nSCS <= nRWEr;
nRAS <= 1'b1;
nCAS <= 1'b0;
nSWE <= 1'b0;
DQML <= Addr[0];
DQMH <= ~Addr[0];
// Column address
SBAreg[1:0] <= Addr[23:22];
SAreg[12:11] <= 2'b00;
SAreg[9] <= 1'b0;
SAreg[8:0] <= Addr[9:1];
// Auto-precharge only if row will increment
SAreg[10] <= Addr[9:0]==10'h3FF;
SAmux <= 1'b1;
RefWake <= 1'b0;
end else if (DEVSELe[3] && RAr[3:0]==4'h3) begin
// NOP
SCKE <= ~nRWEr;
nSCS <= nRWEr;
nRAS <= 1'b1;
nCAS <= 1'b1;
nSWE <= 1'b1;
DQML <= 1'b1;
DQMH <= 1'b1;
SAmux <= 1'b0;
RefWake <= 1'b0;
end else if (DEVSELe[4] && RAr[3:0]==4'h3) begin
// NOP (auto-precharge from previous write)
SCKE <= 1'b1;
nSCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nSWE <= 1'b1;
DQML <= 1'b1;
DQMH <= 1'b1;
SAmux <= 1'b0;
RefWake <= 1'b0;
end else if (DEVSELe[5] && RAr[3:0]==4'h3) begin
// ACT only if WR AP just occurred / NOP
SCKE <= 1'b1;
nSCS <= ~nRWEr && ~SAreg[10];
nRAS <= 1'b0;
nCAS <= 1'b1;
nSWE <= 1'b1;
DQML <= 1'b1;
DQMH <= 1'b1;
// Row address
SBAreg[1:0] <= Addr[23:22];
SAreg[12] <= 1'b0;
SAreg[11:0] <= Addr[21:10];
SAmux <= 1'b1;
RefWake <= 1'b0;
end else if (DEVSELe[6] && RAr[3:0]==4'h3) begin
// RD
SCKE <= 1'b1;
nSCS <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b0;
nSWE <= 1'b1;
DQML <= Addr[0];
DQMH <= ~Addr[0];
// Column address
SBAreg[1:0] <= Addr[23:22];
SAreg[12:11] <= 2'b00;
SAreg[10] <= 1'b1; // auto-precharge
SAreg[9] <= 1'b0;
SAreg[8:0] <= Addr[9:1];
SAmux <= 1'b1;
RefWake <= 1'b0;
end else if (DEVSELe[7] && RAr[3:0]==4'h3) begin
// NOP
SCKE <= 1'b1;
nSCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nSWE <= 1'b1;
DQML <= 1'b1;
DQMH <= 1'b1;
SAmux <= 1'b0;
RefWake <= 1'b0;
end else begin
if (Tick[5] && ~RefDone) begin
if (~RefWake) begin
// NOP
SCKE <= 1'b1;
nSCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nSWE <= 1'b1;
DQML <= 1'b1;
DQMH <= 1'b1;
RefWake <= 1'b1;
end else begin
// AREF
SCKE <= 1'b1;
nSCS <= 1'b0;
nRAS <= 1'b0;
nCAS <= 1'b0;
nSWE <= 1'b1;
DQML <= 1'b1;
DQMH <= 1'b1;
RefWake <= 1'b0;
RefDone <= 1'b1;
end
end else begin
// NOP ckdis
SCKE <= 1'b0;
nSCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nSWE <= 1'b1;
DQML <= 1'b1;
DQMH <= 1'b1;
RefWake <= 1'b0;
if (Tick[5]) RefDone <= 1'b0;
end
SAmux <= 1'b0;
end
end
endmodule
/* UFM Interface */
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
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 (1'b1),
.program (UFMProgram),
.busy (UFMBusy),
.drdout (DRDOut),
.osc (UFMOsc),
.rtpbusy (RTPBusy));
reg UFMBr = 0; // UFMBusy registered to sync with C14M
reg RTPBr = 0; // RTPBusy registered to sync with C14M
reg [15:0] Cfg;
reg CfgLoaded = 0;
// Do nothing when Tick15:14==2'h0
// Get ready when Tick15:14==2'h1
// Zero AR
// Load Cfg when Tick15:14==2'h2
// Tick13:6 (256) - first half of UFM looked at
// Tick5:2 (16) - 16 bits loaded from UFM
// 0: set CfgLoaded if DRDout==1, otherwise shift DRDout into Cfg
// 1-14: continue shifting DRDout into Cfg[15:0]
// 15: shift last DRDout bit into Cfg[15:0] and increment AR
// Tick1:0 (4) - 1 bit shifted
// Do nothing when Tick15:14==2'h3
// Set CfgLoaded too
always @(posedge C25M) begin
if (~CfgLoaded) begin
if (Tick[15:14]==2'h0) begin
// Do nothing
ARShift <= 1;
ARCLK <= 0;
DRCLK <= 0;
end else if (Tick[15:14]==2'h1) begin
// Shift zeros into AR during first half
if (~Tick[13]) begin
ARShift <= 1;
ARCLK <= Tick[1];
end else begin
ARShift <= 0;
ARCLK <= 0;
end
// Load default config
Cfg[15:0] <= 16'hFFFF;
// Load indirect into DR at end
if (Tick[13:0]==14'h3FFC ||
Tick[13:0]==14'h3FFD ||
Tick[13:0]==14'h3FFE ||
Tick[13:0]==14'h3FFF || ) begin
DRCLK <= 1;
end else DRCLK <= 0;
end else if (Tick[15:14]==2'h2) begin
// Load 16 bits into Cfg register
if (Tick[5:2]==4'h0 && Tick[1:0]==0 && DRDout) begin
CfgLoaded <= 1;
end else if (Tick[1:0]==0) begin
Cfg[15:0] <= {Cfg[14:1], DRDout};
end
// Increment AR
if (Tick[5:2]==4'hE) begin
ARCLK <= 1;
end else begin
ARCLK <= 0;
end
// Load indirect into DR
if (Tick[5:2]==4'hF) begin
DRCLK <= 1;
end else begin
DRCLK <= 0;
end
ARShift <= 1'b0; // Only incrementing AR now
end else if (Tick[15:14]==2'h3) begin
// Do nothing
ARShift <= 1;
ARCLK <= 0;
DRCLK <= 0;
CfgLoaded <= 1; // in case setting at address 0xFF
end
DRShift <= 0; // Only reading DR during init, not writing UFM
DRDIn <= 0;
end else if (DEVSELe[0] && RAr[3:0]==4'h8) begin
end else begin
// Do nothing
ARShift <= 1;
ARCLK <= 0;
DRCLK <= 0;
DRShift <= 0;
DRDIn <= 0;
end
end
always @(posedge nDEVSEL, negedge nRST) begin
if (~nRST)
end
endmodule