Refactor to separate core and chip-specific stuff

This commit is contained in:
Zane Kaminski 2023-12-27 01:09:54 -05:00
parent 1de3608efa
commit 04eb798443
5 changed files with 550 additions and 1626 deletions

View File

@ -1,785 +0,0 @@
module RAM2E(C14M, PHI1, LED,
nWE, nWE80, nEN80, nC07X,
Ain, Din, Dout, nDOE, Vout, nVOE,
CKEout, nCSout, nRASout, nCASout, nRWEout,
BA, RAout, DQML, DQMH, RD);
/* Clocks */
input C14M, PHI1;
/* Control inputs */
input nWE, nWE80, nEN80, nC07X;
/* Activity LED */
reg LEDEN = 0;
output LED; assign LED = !(!nEN80 && LEDEN && Ready);
/* Address Bus */
input [7:0] Ain; // Multiplexed DRAM address input
/* 6502 Data Bus */
input [7:0] Din; // 6502 data bus inputs
reg DOEEN;
always @(posedge C14M) begin
DOEEN <= /*(S==4'h8) || (S==4'h9) || (S==4'hA) ||*/ (S==4'hB) ||
(S==4'hC) || (S==4'hD) || (S==4'hE) || (S==4'hF);
end
output nDOE; assign nDOE = !(!nEN80 && nWE && DOEEN);
output [7:0] Dout; assign Dout[7:0] = RD[7:0];
/* Video Data Bus */
reg VOEEN;
always @(posedge C14M) begin
VOEEN <= (S==4'h7) ||
(S==4'h8) || (S==4'h9) || (S==4'hA) || (S==4'hB) ||
(S==4'hC) || (S==4'hD) || (S==4'hE) || (S==4'hF);
end
output nVOE; assign nVOE = !(!PHI1 && VOEEN);
output reg [7:0] Vout; // Video data bus
always @(posedge C14M) if (S==4'h6) Vout[7:0] <= RD[7:0];
/* SDRAM */
reg CKE = 1;
//reg nCS = 1;
reg nRAS = 1, nCAS = 1, nRWE = 1;
output reg [1:0] BA;
reg [11:0] RA;
output reg DQML = 1, DQMH = 1;
inout [7:0] RD;
assign RD[7:0] = Ready ? (!nWE80 ? Din[7:0] : 8'bZ) : 8'h00;
/* SDRAM falling edge outputs */
output reg CKEout;
output nCSout; assign nCSout = 0;
output reg nRASout = 1, nCASout = 1, nRWEout = 1;
output reg [11:0] RAout;
always @(negedge C14M) begin
CKEout <= CKE;
nRASout <= nRAS;
nCASout <= nCAS;
nRWEout <= nRWE;
RAout <= RA;
end
/* RAMWorks Bank Register and Capacity Mask */
reg [7:0] RWBank = 0; // RAMWorks bank register
reg [7:0] RWMask = 0; // RAMWorks bank reg. capacity mask
reg RWSel = 0; // RAMWorks bank register select
always @(posedge C14M) begin
if (S==4'h9) RWSel <= RA[0] && !RA[3] && !nWE && !nC07X;
end
reg CmdRWMaskSet = 0; // RAMWorks Mask register set flag
// Causes RWBank to be zeroed next RWSel access
reg CmdSetRWBankFFChip = 0;
reg CmdSetRWBankFFLED = 0;
reg CmdLEDSet = 0;
reg CmdLEDGet = 0;
/* Command Sequence Detector */
reg [2:0] CS = 0; // Command sequence state
reg [2:0] CmdTout = 0; // Command sequence timeout
/* UFM Interface */
reg wb_rst;
reg wb_cyc_stb;
reg wb_req;
reg wb_we;
reg [7:0] wb_adr;
reg [7:0] wb_dati;
wire wb_ack;
wire [7:0] wb_dato;
wire ufm_irq;
REFB ufmefb(
.wb_clk_i(C14M),
.wb_rst_i(wb_rst),
.wb_cyc_i(wb_cyc_stb),
.wb_stb_i(wb_cyc_stb),
.wb_we_i(wb_we),
.wb_adr_i(wb_adr),
.wb_dat_i(wb_dati),
.wb_dat_o(wb_dato),
.wb_ack_o(wb_ack),
.wbc_ufm_irq(ufm_irq));
/* User Command Triggers */
//reg CmdBitbangMAX = 0; // Set by user command. Loads UFM outputs next RWSel
//reg CmdBitbangSPI = 0;
reg CmdBitbangMXO2 = 0;
reg CmdExecMXO2 = 0;
//reg CmdPrgmMAX = 0; // Set by user command. Programs UFM
//reg CmdEraseMAX = 0; // Set by user command. Erases UFM
/* State Counters */
reg PHI1reg = 0; // Saved PHI1 at last rising clock edge
reg Ready = 0; // 1 if done with init sequence (S0) and enter S1-S15
reg [15:0] FS = 0; // Fast state counter
wire RefReq = FS[5:4]==0; // Refresh request based on fast state counter
reg [3:0] S = 0; // IIe State counter
/* State Counters */
always @(posedge C14M) begin
// Increment fast state counter
FS <= FS+16'h0001;
// Synchronize Apple state counter to S1 when just entering PHI1
PHI1reg <= PHI1; // Save old PHI1
S <= (PHI1 && !PHI1reg && Ready) ? 4'h1 :
(S==4'h0) ? 4'h0 :
(S==4'hF) ? 4'hF : S+4'h1;
// Begin normal operation after 64k init cycles (~4.59ms)
if (FS[15:0]==16'hFFFF) Ready <= 1'b1;
end
/* Command sequence control */
always @(posedge C14M) begin
if (S==4'hC) begin
if (RWSel) begin
CmdTout <= 0; // Reset command timeout if RWSel accessed
// Recognize command sequence and advance CS state
if ((CS==3'h0 && Din[7:0]==8'hFF) ||
(CS==3'h1 && Din[7:0]==8'h00) ||
(CS==3'h2 && Din[7:0]==8'h55) ||
(CS==3'h3 && Din[7:0]==8'hAA) ||
(CS==3'h4 && Din[7:0]==8'hC1) ||
(CS==3'h5 && Din[7:0]==8'hAD) ||
CS==3'h6 || CS==3'h7) CS <= CS+3'h1;
else CS <= 0; // Back to beginning if it's not right
end else begin
CmdTout <= CmdTout+3'h1; // Increment command timeout
// If command sequence times out, reset sequence state
if (CmdTout==3'h7) CS <= 0;
end
end
end
/* UFM Control */
always @(posedge C14M) begin
if (S==4'h0) begin
if (FS[15:14]==2'b00) wb_rst <= 1'b1;
else if (FS[15:14]==2'b01) wb_rst <= 1'b0;
else if (FS[15:14]==2'b10) begin
wb_rst <= 1'b0;
if (wb_ack || (FS[7:0]==0)) wb_cyc_stb <= 0;
else if ((FS[7:0]==1) && wb_req) wb_cyc_stb <= 1;
case (FS[13:8])
0: begin // Open frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h80;
wb_req <= 1;
end 1: begin // Enable configuration interface - command
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h74;
wb_req <= 1;
end 2: begin // Enable configuration interface - operand 1/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h08;
wb_req <= 1;
end 3: begin // Enable configuration interface - operand 2/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 4: begin // Enable configuration interface - operand 3/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 5: begin // Close frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 6: begin // Open frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h80;
wb_req <= 1;
end 7: begin // Poll status register - command
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h3C;
wb_req <= 1;
end 8: begin // Poll status register - operand 1/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 9: begin // Poll status register - operand 2/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 10: begin // Poll status register - operand 3/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 11, 12, 13, 14: begin // Read status register 1-4
wb_we <= 1'b0;
wb_adr[7:0] <= 8'h73;
wb_dati[7:0] <= 8'h3C;
wb_req <= 1;
end 15: begin // Close frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 16: begin // Open frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h80;
wb_req <= 1;
end 17: begin // Set UFM address - command
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'hB4;
wb_req <= 1;
end 18: begin // Set UFM address - operand 1/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 19: begin // Set UFM address - operand 2/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 20: begin // Set UFM address - operand 3/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 21: begin // Set UFM address - data 1/4
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h40;
wb_req <= 1;
end 22: begin // Set UFM address - data 2/4
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 23: begin // Set UFM address - data 3/4
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 24: begin // Set UFM address - data 4/4
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 190;
wb_req <= 1;
end 25: begin // Close frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 26: begin // Open frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h80;
wb_req <= 1;
end 27: begin // Read UFM page - command
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'hCA;
wb_req <= 1;
end 28: begin // Read UFM page - operand 1/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h10;
wb_req <= 1;
end 29: begin // Read UFM page - operand 2/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 30: begin // Read UFM page - operand 3/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h01;
wb_req <= 1;
end 31: begin // Read UFM page - data 0
wb_we <= 1'b0;
wb_adr[7:0] <= 8'h73;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
if (wb_ack) RWMask[7:0] <= wb_dato[7:0];
end 32: begin // Read UFM page - data 1
wb_we <= 1'b0;
wb_adr[7:0] <= 8'h73;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
if (wb_ack) LEDEN <= wb_dato[0];
end 33, 34,
35, 36, 37, 38,
39, 40, 41, 42,
43, 44, 45, 46: begin // Read UFM page - data 2-15
wb_we <= 1'b0;
wb_adr[7:0] <= 8'h73;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 47: begin // Close frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 48: begin // Open frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h80;
wb_req <= 1;
end 49: begin // Disable configuration interface - command
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h26;
wb_req <= 1;
end 50: begin // Disable configuration interface - operand 1/2
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 51: begin // Disable configuration interface - operand 2/2
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 52: begin // Close frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 53: begin // Open frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h80;
wb_req <= 1;
end 54: begin // Bypass - command
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'hFF;
wb_req <= 1;
end 55: begin // Close frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end default: begin
wb_we <= 1'b0;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 0;
end
endcase
end else begin
wb_rst <= 1'b0;
wb_cyc_stb <= 1'b0;
wb_req <= 1'b0;
wb_we <= 1'b0;
wb_adr[7:0] <= 8'h00;
wb_dati[7:0] <= 8'h00;
end
end else begin
// UFM bitbang control
wb_rst <= 1'b0;
wb_req <= 1'b0;
if (RWSel && S==4'hC) begin
// LED control
if (CmdLEDSet) LEDEN <= Din[0];
// Set capacity mask
if (CmdRWMaskSet) RWMask[7:0] <= {Din[7], ~Din[6:0]};
// Set EFB address
if (CmdBitbangMXO2) begin
wb_adr[7:0] <= Din[7:0];
wb_dati[7:0] <= wb_adr[7:0];
end
// Excecute EFB R/W cycle
if (CmdExecMXO2) begin
wb_we <= Din[0];
wb_cyc_stb <= 1;
end else if (wb_ack) wb_cyc_stb <= 0;
end
end
end
/* RAMWorks register control - bank, LED, etc. */
always @(posedge C14M) begin
if (S==4'hC && RWSel) begin
// Latch RAMWorks bank if accessed
if ((CmdSetRWBankFFLED) ||
(CmdSetRWBankFFChip) ||
(CmdLEDGet && LEDEN)) RWBank <= 8'hFF;
else RWBank <= Din[7:0] & {RWMask[7], ~RWMask[6:0]};
if (CS==3'h6) begin // Recognize and submit command in CS6
// Board has LED detect command
CmdSetRWBankFFLED <= Din[7:0]==8'hF0;
// Volatile commands
CmdRWMaskSet <= Din[7:0]==8'hE0;
CmdLEDSet <= Din[7:0]==8'hE2;
CmdLEDGet <= Din[7:0]==8'hE3;
end else begin // Reset command triggers
CmdSetRWBankFFLED <= 0;
CmdRWMaskSet <= 0;
CmdLEDSet <= 0;
CmdLEDGet <= 0;
end
end
end
/* RAMWorks register control - Lattice MachXO2 */
always @(posedge C14M) begin
if (S==4'hC && RWSel) begin
if (CS==3'h6) begin // Recognize and submit command in CS6
// Chip detection commands
//CmdSetRWBankFFChip <= Din[7:0]==8'hFF; // MAX
//CmdSetRWBankFFChip <= Din[7:0]==8'hFE; // SPI
CmdSetRWBankFFChip <= Din[7:0]==8'hFD; // MachXO2
// Altera MAX II/V commands
//CmdBitbangMAX <= Din[7:0]==8'hEA;
//if (!CmdEraseMAX && !CmdPrgmMAX) begin
// if (Din[7:0]==8'hEE) CmdEraseMAX <= 1;
// if (Din[7:0]==8'hEF) CmdPrgmMAX <= 1;
//end
// SPI commands
//CmdBitbangSPI <= Din[7:0]==8'hEB;
// MachXO2 commands
CmdBitbangMXO2 <= Din[7:0]==8'hEC;
CmdExecMXO2 <= Din[7:0]==8'hED;
end else begin // Reset command triggers
CmdSetRWBankFFChip <= 0;
//CmdBitbangMAX <= 0;
//CmdBitbangSPI <= 0;
CmdBitbangMXO2 <= 0;
CmdExecMXO2 <= 0;
end
end
end
/* SDRAM Control */
always @(posedge C14M) case (S)
4'h0: begin
CKE <= 1'b1;
if (!FS[15] || FS[0]) begin
// NOP
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end else case (FS[4:1])
4'h0: begin
// PC all
nRAS <= 1'b0;
nCAS <= 1'b1;
nRWE <= 1'b0;
end 4'h1: begin
// LDM
nRAS <= 1'b0;
nCAS <= 1'b0;
nRWE <= 1'b0;
end 4'h2: begin
// NOP
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end 4'h3, 4'h4, 4'h5, 4'h6,
4'h7, 4'h8, 4'h9, 4'hA: begin
// AREF
nRAS <= 1'b0;
nCAS <= 1'b0;
nRWE <= 1'b1;
end 4'hB: begin
// ACT
nRAS <= 1'b0;
nCAS <= 1'b1;
nRWE <= 1'b1;
end 4'hC, 4'hD: begin
// WR
nRAS <= 1'b1;
nCAS <= 1'b0;
nRWE <= 1'b0;
end 4'hE: begin
// NOP
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end 4'hF: begin
// PC all
nRAS <= 1'b0;
nCAS <= 1'b1;
nRWE <= 1'b0;
end
endcase
case (FS[4:3])
2'b00, 2'b01: begin
// Mode register contents
BA[1:0] <= 2'b00; // Reserved
RA[11] <= 1'b0; // Reserved
RA[10] <= !FS[1]; // reserved / "all"
RA[9] <= 1'b1; // "1" for single write mode
RA[8] <= 1'b0; // Reserved
RA[7] <= 1'b0; // "0" for not test mode
RA[6:4] <= 3'b010; // "2" for CAS latency 2
RA[3] <= 1'b0; // "0" for sequential burst (not used)
RA[2:0] <= 3'b000; // "0" for burst length 1 (no burst)
end 2'b10: begin
BA[1:0] <= 2'b00;
RA[11:8] <= 4'h0;
RA[7:0] <= FS[14:7];
end 2'b11: begin
BA[1:0] <= 2'b00;
RA[11:3] <= 9'h000;
RA[2:1] <= FS[6:5];
RA[0] <= FS[1];
end
endcase
DQML <= !FS[15];
DQMH <= !FS[15];
end 4'h1: begin
// NOP CKE
CKE <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
BA[1:0] <= 2'b00;
RA[11:8] <= 4'b0000;
// Hold RA[7:0]
DQML <= 1'b0;
DQMH <= 1'b1;
end 4'h2: begin
// ACT CKE
CKE <= 1'b1;
nRAS <= 1'b0;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Hold BA
// Hold RA
// Hold DQMs
end 4'h3: begin
// RD CKE
CKE <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b0;
nRWE <= 1'b1;
// Hold BA
// Hold RA[11:8]
RA[7:0] <= Ain[7:0];
// Hold DQMs
end 4'h4: begin
// PC all CKE
CKE <= 1'b1;
nRAS <= 1'b0;
nCAS <= 1'b1;
nRWE <= 1'b0;
// Hold BA
// Hold RA[11]
RA[10] <= 1'b1; // "all"
// Hold RA[9:0]
// Hold DQMs
end 4'h5: begin
if (RefReq) begin
// AREF CKE
CKE <= 1'b1;
nRAS <= 1'b0;
nCAS <= 1'b0;
nRWE <= 1'b1;
end else begin
// NOP CKD
CKE <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end
// Hold BA
// Hold RA
// Hold DQMs
end 4'h6: begin
// NOP CKD
CKE <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Hold BA
// Hold RA
// Hold DQMs
end 4'h7: begin
// Can't check EN80 at this time
if (nWE) begin // Read / idle
// NOP CKE
CKE <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end else begin // Write / idle
// NOP CKD
CKE <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end
BA[1:0] <= RWBank[6:5];
RA[11:8] <= RWBank[4:1];
RA[7:0] <= Ain[7:0];
// Hold DQMs
end 4'h8: begin
if (nEN80) begin // Idle
// NOP CKD
CKE <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end else if (nWE) begin // Read
// ACT CKE
CKE <= 1'b1;
nRAS <= 1'b0;
nCAS <= 1'b1;
nRWE <= 1'b1;
end else begin // Write
// NOP CKE
CKE <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end
// Hold BA
// Hold RA
// Hold DQMs
end 4'h9: begin
if (nEN80) begin // Idle
// NOP CKD
CKE <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end else if (nWE) begin // Read
// RD CKE
CKE <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b0;
nRWE <= 1'b1;
end else begin // Write
// ACT CKE
CKE <= 1'b1;
nRAS <= 1'b0;
nCAS <= 1'b1;
nRWE <= 1'b1;
end
// Hold BA
RA[11:9] <= 3'b000; // no auto-precharge
RA[8] <= RWBank[7];
RA[7:0] <= Ain[7:0];
DQMH <= !RWBank[0];
DQMH <= RWBank[0];
end 4'hA: begin
if (nEN80) begin // Idle
// NOP CKD
CKE <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Hold RA[10]
end else if (nWE) begin // Read
// PC all CKD
CKE <= 1'b0;
nRAS <= 1'b0;
nCAS <= 1'b1;
nRWE <= 1'b0;
RA[10] <= 1'b1;
end else begin // Write
// WR CKE
CKE <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b0;
nRWE <= 1'b0;
RA[10] <= 1'b0;
end
// Hold BA
// Hold RA[11,9:0]
// Hold DQMs
end 4'hB: begin
if (nEN80) begin // Idle
// NOP CKD
CKE <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end else if (nWE) begin // Read
// NOP CKD
CKE <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end else begin // Write
// NOP CKE
CKE <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end
// Hold BA
// Hold RA[11:0]
// Hold DQMs
end 4'hC: begin
if (nEN80) begin // Idle
// NOP CKD
CKE <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Hold RA[10]
end else if (nWE) begin // Read
// NOP CKD
CKE <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Hold RA[10]
end else begin // Write
// PC all CKD
CKE <= 1'b0;
nRAS <= 1'b0;
nCAS <= 1'b1;
nRWE <= 1'b0;
RA[10] <= 1'b1; // "all"
end
// Hold BA
// Hold RA[11,9:0]
// Hold RA[7:0]
// Hold DQMs
end 4'hD: begin
// NOP CKD
CKE <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Hold BA
// Hold RA[11:0]
// Hold DQMs
end 4'hE, 4'hF: begin
// NOP CKD
CKE <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Hold BA
// Hold RA[11:8]
RA[7:0] <= Ain[7:0]; // Latch row address for next video read
// Hold DQMs
end
endcase
endmodule

View File

@ -1,636 +0,0 @@
module RAM2E(C14M, PHI1,
nWE, nWE80, nEN80, nC07X,
Ain, Din, Dout, nDOE, Vout, nVOE,
CKE, nCS, nRAS, nCAS, nRWE,
BA, RA, RD, DQML, DQMH);
/* Clocks */
input C14M, PHI1;
/* Control inputs */
input nWE, nWE80, nEN80, nC07X;
/* Delay for EN80 signal */
//output DelayOut = 1'b0;
//input DelayIn;
wire EN80 = ~nEN80;
/* Address Bus */
input [7:0] Ain; // Multiplexed DRAM address input
/* 6502 Data Bus */
input [7:0] Din; // 6502 data bus inputs
reg DOEEN = 0; // 6502 data bus output enable from state machine
output nDOE = ~(EN80 & nWE & DOEEN); // 6502 data bus output enable
output reg [7:0] Dout; // 6502 data Bus output
/* Video Data Bus */
output nVOE = ~(~PHI1); /// Video data bus output enable
output reg [7:0] Vout; // Video data bus
/* SDRAM */
output reg CKE = 0;
output reg nCS = 1, nRAS = 1, nCAS = 1, nRWE = 1;
output reg [1:0] BA;
output reg [11:0] RA;
output reg DQML = 1, DQMH = 1;
wire RDOE = EN80 & ~nWE80;
inout [7:0] RD = RDOE ? Din[7:0] : 8'bZ;
/* RAMWorks Bank Register and Capacity Mask */
reg [7:0] RWBank = 0; // RAMWorks bank register
reg [7:0] RWMask = 0; // RAMWorks bank reg. capacity mask
reg RWSel = 0; // RAMWorks bank register select
reg RWMaskSet = 0; // RAMWorks Mask register set flag
reg SetRWBankFF = 0; // Causes RWBank to be zeroed next RWSel access
/* Command Sequence Detector */
reg [2:0] CS = 0; // Command sequence state
reg [2:0] CmdTout = 0; // Command sequence timeout
/* UFM Interface */
reg [15:8] UFMD = 0; // *Parallel* UFM data register
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 UFMBusyReg = 0; // UFMBusy registered to sync with C14M
reg RTPBusyReg = 0; // RTPBusy registered to sync with C14M
/* UFM State & User Command Triggers */
reg UFMInitDone = 0; // 1 if UFM initialization finished
reg UFMReqErase = 0; // 1 if UFM requires erase
reg UFMBitbang = 0; // Set by user command. Loads UFM outputs next RWSel
reg UFMPrgmEN = 0; // Set by user command. Programs UFM
reg UFMEraseEN = 0; // Set by user command. Erases UFM
reg DRCLKPulse = 0; // Set by user command. Causes DRCLK pulse next C14M
/* State Counters */
reg PHI1reg = 0; // Saved PHI1 at last rising clock edge
reg Ready = 0; // 1 if done with init sequence (S0) and enter S1-S15
reg [15:0] FS = 0; // Fast state counter
reg [3:0] S = 0; // IIe State counter
/* State Counters */
always @(posedge C14M) begin
// Increment fast state counter
FS <= FS+1;
// Synchronize Apple state counter to S1 when just entering PHI1
PHI1reg <= PHI1; // Save old PHI1
S <= (PHI1 & ~PHI1reg & Ready) ? 4'h1 :
S==4'h0 ? 4'h0 :
S==4'hF ? 4'hF : S+1;
end
/* UFM Control */
always @(posedge C14M) begin
// Synchronize asynchronous UFM signals
UFMBusyReg <= UFMBusy;
RTPBusyReg <= RTPBusy;
if (S==4'h0) begin
if ((FS[15:13]==3'b101) | (FS[15:13]==3'b111 & UFMReqErase)) begin
// In states AXXX-BXXX and also EXXX-FXXX if erase/wrap req'd
// shift in 0's to address register
ARCLK <= FS[0]; // Clock address register
DRCLK <= 1'b0; // Don't clock data register
ARShift <= 1'b1; // Shift address registers
DRDIn <= 1'b0; // Don't care DRDIn
DRShift <= 1'b0; // Don't care DRDShift
end else if (~UFMInitDone & FS[15:13]==3'b110 & FS[4:1]==4'h4) begin
// In states CXXX-DXXX (substep 4)
// Xfer to data reg (repeat 256x 1x)
ARCLK <= 1'b0; // Don't clock address register
DRCLK <= FS[0]; // Clock data register
ARShift <= 1'b0; // Don't care ARShift
DRDIn <= 1'b0; // Don't care DRDIn
DRShift <= 1'b0; // Don't care DRShift
end else if (~UFMInitDone & FS[15:13]==3'b110 & FS[4]==1'b1) begin
// In states CXXX-DXXX (substeps 8-F)
// Save UFM D15-8, shift out D14-7 (repeat 256x 8x)
DRCLK <= FS[0]; // Clock data register
ARShift <= 1'b0; // ARShift is 0 because we want to increment
DRDIn <= 1'b0; // Don't care what to shift into data register
DRShift <= 1'b1; // Shift data register
// Shift into UFMD
if (FS[0]) UFMD[15:8] <= {UFMD[14:8], DRDOut};
// Compare and store mask
if (FS[4:1]==4'hF) begin
ARCLK <= FS[0]; // Clock address register to increment
// If byte is erased (0xFF, i.e. all 1's, is erased)...
if (UFMD[14:8]==7'b1111111 & DRDOut==1'b1) begin
// Current UFM address is where we want to store
UFMInitDone <= 1'b1; // Quit iterating
// Otherwise byte is valid setting (i.e. some bit is 0)...
end else begin
// Set RWMask, but if saved mask is 0x80, store ~0xFF
if (UFMD[14:8]==7'b1000000 & DRDOut==1'b0) begin
RWMask[7:0] <= {1'b1, ~7'h7F};
end else RWMask[7:0] <= {UFMD[14], ~UFMD[13:8], ~DRDOut};
// If last byte in sector...
if (FS[12:5]==8'hFF) begin
UFMReqErase <= 1'b1; // Mark need to erase
end
end
end else ARCLK <= 1'b0; // Don't clock address register
end else begin
ARCLK <= 1'b0;
DRCLK <= 1'b0;
ARShift <= 1'b0;
DRDIn <= 1'b0;
DRShift <= 1'b0;
end
// Don't erase or program UFM during initialization
UFMErase <= 1'b0;
UFMProgram <= 1'b0;
// Keep DRCLK pulse control disabled during init
DRCLKPulse <= 1'b0;
end else begin
// Can only shift UFM data register now
ARCLK <= 1'b0;
ARShift <= 1'b0;
DRShift <= 1'b1;
// UFM bitbang control
if (UFMBitbang & CS==3'h7 & RWSel & S==4'hC) begin
DRDIn <= Din[6];
DRCLKPulse <= Din[7];
DRCLK <= 1'b0;
end else begin
DRCLKPulse <= 1'b0;
DRCLK <= DRCLKPulse;
end
// Set capacity mask
if (RWMaskSet & RWSel & S==4'hC) RWMask[7:0] <= {Din[7], ~Din[6:0]};
// UFM programming sequence
if (UFMPrgmEN | UFMEraseEN) begin
if (~UFMBusyReg & ~RTPBusyReg) begin
if (UFMReqErase | UFMEraseEN) UFMErase <= 1'b1;
else if (UFMPrgmEN) UFMProgram <= 1'b1;
end else if (UFMBusyReg) UFMReqErase <= 1'b0;
end
end
end
/* SDRAM Control */
always @(posedge C14M) begin
if (S==4'h0) begin
// SDRAM initialization
if (FS[15:0]==16'hFFC0) begin
// Precharge All
nCS <= 1'b0;
nRAS <= 1'b0;
nCAS <= 1'b1;
nRWE <= 1'b0;
RA[10] <= 1'b1; // "all"
end else if (FS[15:4]==16'hFFD & FS[0]==1'b0) begin // Repeat 8x
// Auto-refresh
nCS <= 1'b0;
nRAS <= 1'b0;
nCAS <= 1'b0;
nRWE <= 1'b1;
RA[10] <= 1'b0;
end else if (FS[15:0]==16'hFFE8) begin
// Set Mode Register
nCS <= 1'b0;
nRAS <= 1'b0;
nCAS <= 1'b0;
nRWE <= 1'b0;
RA[10] <= 1'b0; // Reserved in mode register
end else if (FS[15:4]==12'hFFF & FS[0]==1'b0) begin // Repeat 8x
// Auto-refresh
nCS <= 1'b0;
nRAS <= 1'b0;
nCAS <= 1'b0;
nRWE <= 1'b1;
RA[10] <= 1'b0;
end else begin // Otherwise send no-op
// NOP
nCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
RA[10] <= 1'b0;
end
// Enable SDRAM clock after 65,280 cycles (~4.56ms)
CKE <= FS[15:8] == 8'hFF;
// Mode register contents
BA[1:0] <= 2'b00; // Reserved
RA[11] <= 1'b0; // Reserved
// RA[10] set above ^
RA[9] <= 1'b1; // "1" for single write mode
RA[8] <= 1'b0; // Reserved
RA[7] <= 1'b0; // "0" for not test mode
RA[6:4] <= 3'b010; // "2" for CAS latency 2
RA[3] <= 1'b0; // "0" for sequential burst (not used)
RA[2:0] <= 3'b000; // "0" for burst length 1 (no burst)
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Inhibit data bus output
DOEEN <= 1'b0;
// Begin normal operation after 128k init cycles (~9.15ms)
if (FS == 16'hFFFF) Ready <= 1'b1;
end else if (S==4'h1) begin
// Enable clock
CKE <= 1'b1;
// NOP
nCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Don't care bank, RA[11:8]
BA <= 2'b00;
RA[11:8] <= 4'b0000;
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Inhibit data bus output
DOEEN <= 1'b0;
end else if (S==4'h2) begin
// Enable clock
CKE <= 1'b1;
// Activate
nCS <= 1'b0;
nRAS <= 1'b0;
nCAS <= 1'b1;
nRWE <= 1'b1;
// SDRAM bank 0, high-order row address is 0
BA <= 2'b00;
RA[11:8] <= 4'b0000;
// Row address is as previously latched
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Inhibit data bus output
DOEEN <= 1'b0;
end else if (S==4'h3) begin
// Enable clock
CKE <= 1'b1;
// Read
nCS <= 1'b0;
nRAS <= 1'b1;
nCAS <= 1'b0;
nRWE <= 1'b1;
// SDRAM bank 0, RA[11,9:8] don't care
BA <= 2'b00;
RA[11] <= 1'b0;
RA[10] <= 1'b1; // (A10 set to auto-precharge)
RA[9] <= 1'b0;
RA[8] <= 1'b0;
// Latch column address for read command
RA[7:0] <= Ain[7:0];
// Read low byte (high byte is +4MB in ramworks)
DQML <= 1'b0;
DQMH <= 1'b1;
// Inhibit data bus output
DOEEN <= 1'b0;
end else if (S==4'h4) begin
// Enable clock
CKE <= 1'b1;
// NOP
nCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Don't care bank, RA[11:8]
BA <= 2'b00;
RA[11:8] <= 4'b0000;
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Inhibit data bus output
DOEEN <= 1'b0;
end else if (S==4'h5) begin
// Enable clock
CKE <= 1'b1;
// NOP
nCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Don't care bank, RA[11:8]
BA <= 2'b00;
RA[11:8] <= 4'b0000;
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Inhibit data bus output
DOEEN <= 1'b0;
end else if (S==4'h6) begin
// Enable clock
CKE <= 1'b1;
if (FS[5:4]==0) begin
// Auto-refresh
nCS <= 1'b0;
nRAS <= 1'b0;
nCAS <= 1'b0;
nRWE <= 1'b1;
end else begin
// NOP
nCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
end
// Don't care bank, RA[11:8]
BA <= 2'b00;
RA[11:8] <= 4'b0000;
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Inhibit data bus output
DOEEN <= 1'b0;
end else if (S==4'h7) begin
// Enable clock
CKE <= 1'b1;
// NOP
nCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Don't care bank, RA[11:8]
BA <= 2'b00;
RA[11:8] <= 4'b0000;
// Latch row address for activate command
RA[7:0] <= Ain[7:0];
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Inhibit data bus output
DOEEN <= 1'b0;
end else if (S==4'h8) begin
// Enable clock if '245 output enabled
CKE <= EN80;
// Activate if '245 output enabled
nCS <= nEN80;
nRAS <= 1'b0;
nCAS <= 1'b1;
nRWE <= 1'b1;
// SDRAM bank, RA[11:8] determine by RamWorks bank
BA <= RWBank[5:4];
RA[11:8] <= RWBank[3:0];
// Row address is as previously latched
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Inhibit data bus output
DOEEN <= 1'b0;
end else if (S==4'h9) begin
// Enable clock if '245 output enabled
CKE <= EN80;
// Read/Write if '245 output enabled
nCS <= nEN80;
nRAS <= 1'b1;
nCAS <= 1'b0;
nRWE <= nWE80;
// SDRAM bank still determined by RamWorks, RA[11,9:8] don't care
BA <= RWBank[5:4];
RA[11] <= 1'b0;
RA[10] <= 1'b1; // (A10 set to auto-precharge)
RA[9] <= 1'b0;
RA[8] <= RWBank[7];
// Latch column address for R/W command
RA[7:0] <= Ain[7:0];
// Latch RAMWorks low nybble write select using old row address
RWSel <= RA[0] & ~RA[3] & ~nWE & ~nC07X;
// Mask according to RAMWorks bank (high byte is +4MB)
DQML <= RWBank[6];
DQMH <= ~RWBank[6];
// Inhibit data bus output
DOEEN <= 1'b0;
end else if (S==4'hA) begin
// Enable clock if '245 output enabled
CKE <= EN80;
// NOP
nCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Don't care bank, RA[11:8]
BA <= 2'b00;
RA[11:8] <= 4'b0000;
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Inhibit data bus output
DOEEN <= 1'b0;
end else if (S==4'hB) begin
// Disable clock
CKE <= 1'b0;
// NOP
nCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Don't care bank, RA[11:8]
BA <= 2'b00;
RA[11:8] <= 4'b0000;
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Enable data bus output
DOEEN <= 1'b1;
end else if (S==4'hC) begin
// Disable clock
CKE <= 1'b0;
// NOP
nCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Don't care bank, RA[11:8]
BA <= 2'b00;
RA[11:8] <= 4'b0000;
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Enable data bus output
DOEEN <= 1'b1;
// RAMWorks Bank Register Select
if (RWSel) begin
// Latch RAMWorks bank if accessed
if (SetRWBankFF) RWBank <= 8'hFF;
else RWBank <= Din[7:0] & {RWMask[7], ~RWMask[6:0]};
// Recognize command sequence and advance CS state
if ((CS==3'h0 & Din[7:0]==8'hFF) |
(CS==3'h1 & Din[7:0]==8'h00) |
(CS==3'h2 & Din[7:0]==8'h55) |
(CS==3'h3 & Din[7:0]==8'hAA) |
(CS==3'h4 & Din[7:0]==8'hC1) |
(CS==3'h5 & Din[7:0]==8'hAD) |
CS==3'h6 | CS==3'h7) CS <= CS+1;
else CS <= 0; // Back to beginning if it's not right
if (CS==3'h6) begin // Recognize and submit command in CS6
SetRWBankFF <= Din[7:0]==8'hFF;
if (Din[7:0]==8'hEF) UFMPrgmEN <= 1'b1;
if (Din[7:0]==8'hEE) UFMEraseEN <= 1'b1;
UFMBitbang <= Din[7:0]==8'hEA;
RWMaskSet <= Din[7:0]==8'hE0;
end else begin // Reset command triggers
SetRWBankFF <= 1'b0;
UFMBitbang <= 1'b0;
RWMaskSet <= 1'b0;
end
CmdTout <= 0; // Reset command timeout if RWSel accessed
end else begin
CmdTout <= CmdTout+1; // Increment command timeout
// If command sequence times out, reset sequence state
if (CmdTout==3'h7) CS <= 0;
end
end else if (S==4'hD) begin
// Disable clock
CKE <= 1'b0;
// NOP
nCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Don't care bank, RA[11:8]
BA <= 2'b00;
RA[11:8] <= 4'b0000;
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Enable data bus output
DOEEN <= 1'b1;
end else if (S==4'hE) begin
// Disable clock
CKE <= 1'b0;
// NOP
nCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Don't care bank, RA[11:8]
BA <= 2'b00;
RA[11:8] <= 4'b0000;
// Latch row address for next video read
RA[7:0] <= Ain[7:0];
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Enable data bus output
DOEEN <= 1'b1;
end else if (S==4'hF) begin
// Disable clock
CKE <= 1'b0;
// NOP
nCS <= 1'b1;
nRAS <= 1'b1;
nCAS <= 1'b1;
nRWE <= 1'b1;
// Don't care bank, RA[11:8]
BA <= 2'b00;
RA[11:8] <= 4'b0000;
// Latch row address for next video read
RA[7:0] <= Ain[7:0];
// Mask everything
DQML <= 1'b1;
DQMH <= 1'b1;
// Enable data bus output
DOEEN <= 1'b1;
end
end
always @(negedge C14M) begin
// Latch video and read data outputs
if (S==4'h6) Vout[7:0] <= RD[7:0];
if (S==4'hC) Dout[7:0] <= RD[7:0];
end
endmodule

View File

@ -10,8 +10,23 @@ module RAM2E(C14M, PHI1, LED,
/* Control inputs */
input nWE, nWE80, nEN80, nC07X;
/* "Fast" (init) state counter */
reg [15:0] FS = 0; always @(posedge C14M) FS <= FS+16'h0001;
reg Ready = 0;
always @(posedge C14M) if (FS[15:0]==16'hFFFF) Ready <= 1'b1;
wire RefReq = FS[5:4]==0; // Refresh request based on fast state counter
/* IIe state counter */
reg [3:0] S = 0;
reg PHI1r = 0; always @(posedge C14M) PHI1r <= PHI1;
always @(posedge C14M) begin
S <= (PHI1 && !PHI1r && Ready) ? 4'h1 :
(S==4'h0) ? 4'h0 :
(S==4'hF) ? 4'hF : S+4'h1;
end
/* Activity LED */
reg LEDEN = 0;
wire LEDEN;
output LED; assign LED = !(!nEN80 && LEDEN && Ready);
/* Address Bus */
@ -63,14 +78,14 @@ module RAM2E(C14M, PHI1, LED,
/* RAMWorks Bank Register and Capacity Mask */
reg [7:0] RWBank = 0; // RAMWorks bank register
reg [7:0] RWMask = 0; // RAMWorks bank reg. capacity mask
wire [7:0] RWMask;
reg RWSel = 0; // RAMWorks bank register select
always @(posedge C14M) begin
if (S==4'h9) RWSel <= RA[0] && !RA[3] && !nWE && !nC07X;
end
reg CmdRWMaskSet = 0; // RAMWorks Mask register set flag
// Causes RWBank to be zeroed next RWSel access
reg CmdSetRWBankFFChip = 0;
wire CmdSetRWBankFFChip;
reg CmdSetRWBankFFLED = 0;
reg CmdLEDSet = 0;
reg CmdLEDGet = 0;
@ -79,68 +94,13 @@ module RAM2E(C14M, PHI1, LED,
reg [2:0] CS = 0; // Command sequence state
reg [2:0] CmdTout = 0; // Command sequence timeout
/* UFM Interface */
reg [15:8] UFMD = 0; // *Parallel* UFM data register
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 UFMRTPBusy = 0;
always @(posedge C14M) UFMRTPBusy <= UFMBusy || RTPBusy;
reg UFMInitDone = 0; // 1 if UFM initialization finished
reg UFMReqErase = 0; // 1 if UFM requires erase
reg DRCLKPulse = 0; // Set by user command. Causes DRCLK pulse next C14M
/* User Command Triggers */
reg CmdBitbangMAX = 0; // Set by user command. Loads UFM outputs next RWSel
//reg CmdBitbangSPI = 0;
//reg CmdBitbangMXO2 = 0;
//reg CmdExecMXO2 = 0;
reg CmdPrgmMAX = 0; // Set by user command. Programs UFM
reg CmdEraseMAX = 0; // Set by user command. Erases UFM
/* State Counters */
reg PHI1reg = 0; // Saved PHI1 at last rising clock edge
reg Ready = 0; // 1 if done with init sequence (S0) and enter S1-S15
reg [15:0] FS = 0; // Fast state counter
wire RefReq = FS[5:4]==0; // Refresh request based on fast state counter
reg [3:0] S = 0; // IIe State counter
/* State Counters */
always @(posedge C14M) begin
// Increment fast state counter
FS <= FS+16'h0001;
// Synchronize Apple state counter to S1 when just entering PHI1
PHI1reg <= PHI1; // Save old PHI1
S <= (PHI1 && !PHI1reg && Ready) ? 4'h1 :
(S==4'h0) ? 4'h0 :
(S==4'hF) ? 4'hF : S+4'h1;
// Begin normal operation after 64k init cycles (~4.59ms)
if (FS[15:0]==16'hFFFF) Ready <= 1'b1;
end
/* Chip-specific UFM interface */
RAM2E_UFM ram2e_ufm (
.C14M(C14M), .S(S), .FS(FS), .CS(CS),
.RWSel(RWSel), .D(Din),
.RWMask(RWMask), .LEDEN(LEDEN),
.CmdRWMaskSet(CmdRWMaskSet), .CmdLEDSet(CmdLEDSet),
.CmdSetRWBankFFChip(CmdSetRWBankFFChip));
/* Command sequence control */
always @(posedge C14M) begin
@ -164,125 +124,20 @@ module RAM2E(C14M, PHI1, LED,
end
end
/* UFM Control */
reg UFMProgStart;
always @(posedge C14M) begin
if (S==4'h0) begin
if ((FS[15:13]==3'b101) || (FS[15:13]==3'b111 && UFMReqErase)) begin
// In states AXXX-BXXX and also EXXX-FXXX if erase/wrap req'd
// shift in 0's to address register
ARCLK <= FS[0]; // Clock address register
DRCLK <= 1'b0; // Don't clock data register
ARShift <= 1'b1; // Shift address registers
DRDIn <= 1'b0; // Don't care DRDIn
DRShift <= 1'b0; // Don't care DRDShift
end else if (!UFMInitDone && FS[15:13]==3'b110 && FS[4:1]==4'h4) begin
// In states CXXX-DXXX (substep 4)
// Xfer to data reg (repeat 256x 1x)
ARCLK <= 1'b0; // Don't clock address register
DRCLK <= FS[0]; // Clock data register
ARShift <= 1'b0; // Don't care ARShift
DRDIn <= 1'b0; // Don't care DRDIn
DRShift <= 1'b0; // Don't care DRShift
end else if (!UFMInitDone && FS[15:13]==3'b110 && (FS[4:1]==4'h7 || FS[4]==1'b1)) begin
// In states CXXX-DXXX (substeps 8-F)
// Save UFM D15-8, shift out D14-7 (repeat 256x 8x)
DRCLK <= FS[0]; // Clock data register
ARShift <= 1'b0; // ARShift is 0 because we want to increment
DRDIn <= 1'b0; // Don't care what to shift into data register
DRShift <= 1'b1; // Shift data register
// Shift into UFMD
if (FS[0]) UFMD[15:8] <= {UFMD[14:8], DRDOut};
// Compare and store mask
if (FS[4:1]==4'hF) begin
ARCLK <= FS[0]; // Clock address register to increment
// If byte is erased (0xFF, i.e. all 1's, is erased)...
if (UFMD[15:8]==8'hFF && DRDOut==1'b1) begin
// Current UFM address is where we want to store
UFMInitDone <= 1'b1; // Quit iterating
// Otherwise byte is valid setting (i.e. some bit is 0)...
end else begin
// Set RWMask, but if saved mask is 0x80, store ~0xFF
if (UFMD[15:8]==8'b10000000) begin
RWMask[7:0] <= {1'b1, ~7'h7F};
end else RWMask[7:0] <= {UFMD[15], ~UFMD[14:8]};
// Set LED setting
LEDEN <= DRDOut ^ UFMD[15];
// If last byte in sector...
if (FS[12:5]==8'hFF) begin
UFMReqErase <= 1'b1; // Mark need to erase
end
end
end else ARCLK <= 1'b0; // Don't clock address register
end else begin
ARCLK <= 1'b0;
DRCLK <= 1'b0;
ARShift <= 1'b0;
DRDIn <= 1'b0;
DRShift <= 1'b0;
end
// Don't erase or program UFM during initialization
UFMErase <= 1'b0;
UFMProgram <= 1'b0;
// Keep DRCLK pulse control disabled during init
DRCLKPulse <= 1'b0;
// Reset UFMProgStart
UFMProgStart <= 1'b0;
end else begin
// Can only shift UFM data register now
ARCLK <= 1'b0;
ARShift <= 1'b0;
DRShift <= 1'b1;
// UFM bitbang control
if (CmdBitbangMAX && RWSel && S==4'hC) begin
DRDIn <= Din[6];
DRCLKPulse <= Din[7];
DRCLK <= 1'b0;
end else begin
DRCLKPulse <= 1'b0;
DRCLK <= DRCLKPulse;
end
// Volatile settings command execution
if (RWSel && S==4'hC) begin
// LED control
if (CmdLEDSet) LEDEN <= Din[0];
// Set capacity mask
if (CmdRWMaskSet) RWMask[7:0] <= {Din[7], ~Din[6:0]};
end
// UFM programming sequence
if (S==4'h1) begin
if (!UFMProgStart && !UFMRTPBusy) begin
if (CmdPrgmMAX) begin
UFMErase <= UFMReqErase;
UFMProgStart <= 1;
end else if (CmdEraseMAX) UFMErase <= 1;
end else if (UFMProgStart && !UFMRTPBusy) begin
UFMErase <= 0;
if (!UFMErase) UFMProgram <= 1;
end
end
end
end
/* RAMWorks register control - bank, LED, etc. */
always @(posedge C14M) begin
if (S==4'hC && RWSel) begin
// Latch RAMWorks bank if accessed
if ((CmdSetRWBankFFLED) ||
(CmdSetRWBankFFChip) ||
if ((CmdSetRWBankFFLED) || (CmdSetRWBankFFChip) ||
(CmdLEDGet && LEDEN)) RWBank <= 8'hFF;
else RWBank <= Din[7:0] & {RWMask[7], ~RWMask[6:0]};
if (CS==3'h6) begin // Recognize and submit command in CS6
// Board has LED detect command
// LED detect command
CmdSetRWBankFFLED <= Din[7:0]==8'hF0;
// Volatile commands
CmdSetRWBankFFLED <= Din[7:0]==8'hF0;
CmdRWMaskSet <= Din[7:0]==8'hE0;
CmdLEDSet <= Din[7:0]==8'hE2;
CmdLEDGet <= Din[7:0]==8'hE3;
@ -295,38 +150,6 @@ module RAM2E(C14M, PHI1, LED,
end
end
/* RAMWorks register control - Altera MAX */
always @(posedge C14M) begin
if (S==4'hC && RWSel) begin
if (CS==3'h6) begin // Recognize and submit command in CS6
// Chip detection commands
CmdSetRWBankFFChip <= Din[7:0]==8'hFF; // MAX
//CmdSetRWBankFFChip <= Din[7:0]==8'hFE; // SPI
//CmdSetRWBankFFChip <= Din[7:0]==8'hFD; // MachXO2
// Altera MAX II/V commands
CmdBitbangMAX <= Din[7:0]==8'hEA;
if (!CmdEraseMAX && !CmdPrgmMAX) begin
if (Din[7:0]==8'hEE) CmdEraseMAX <= 1;
if (Din[7:0]==8'hEF) CmdPrgmMAX <= 1;
end
// SPI commands
//CmdBitbangSPI <= Din[7:0]==8'hEB;
// MachXO2 commands
//CmdBitbangMXO2 <= Din[7:0]==8'hEC;
//CmdExecMXO2 <= Din[7:0]==8'hED;
end else begin // Reset command triggers
CmdSetRWBankFFChip <= 0;
CmdBitbangMAX <= 0;
//CmdBitbangSPI <= 0;
//CmdBitbangMXO2 <= 0;
//CmdExecMXO2 <= 0;
end
end
end
/* SDRAM Control */
always @(posedge C14M) case (S)
4'h0: begin

333
CPLD/UFM-LCMXO2.v Normal file
View File

@ -0,0 +1,333 @@
module RAM2E_UFM(C14M, S, FS, CS,
RWSel, D,
RWMask, LEDEN,
CmdRWMaskSet, CmdLEDSet,
CmdSetRWBankFFChip);
input C14M;
input [3:0] S;
input [15:0] FS;
input [2:0] CS;
input RWSel;
input [7:0] D;
output reg [7:0] RWMask;
output reg LEDEN;
input CmdRWMaskSet;
input CmdLEDSet;
output reg CmdSetRWBankFFChip;
/* RAMWorks register control - Lattice MachXO2 */
reg CmdBitbangMXO2 = 0;
reg CmdExecMXO2 = 0;
always @(posedge C14M) begin
if (S==4'hC && RWSel) begin
if (CS==3'h6) begin // Recognize and submit command in CS6
// Chip detection commands
//CmdSetRWBankFFChip <= D[7:0]==8'hFF; // MAX
//CmdSetRWBankFFChip <= D[7:0]==8'hFE; // SPI
CmdSetRWBankFFChip <= D[7:0]==8'hFD; // MachXO2
// Altera MAX II/V commands
//CmdBitbangMAX <= D[7:0]==8'hEA;
//if (!CmdEraseMAX && !CmdPrgmMAX) begin
// if (D[7:0]==8'hEE) CmdEraseMAX <= 1;
// if (D[7:0]==8'hEF) CmdPrgmMAX <= 1;
//end
// SPI commands
//CmdBitbangSPI <= D[7:0]==8'hEB;
// MachXO2 commands
CmdBitbangMXO2 <= D[7:0]==8'hEC;
CmdExecMXO2 <= D[7:0]==8'hED;
end else begin // Reset command triggers
CmdSetRWBankFFChip <= 0;
CmdBitbangMXO2 <= 0;
CmdExecMXO2 <= 0;
end
end
end
/* UFM Interface */
reg wb_rst;
reg wb_cyc_stb;
reg wb_req;
reg wb_we;
reg [7:0] wb_adr;
reg [7:0] wb_dati;
wire wb_ack;
wire [7:0] wb_dato;
wire ufm_irq;
REFB ufmefb(
.wb_clk_i(C14M),
.wb_rst_i(wb_rst),
.wb_cyc_i(wb_cyc_stb),
.wb_stb_i(wb_cyc_stb),
.wb_we_i(wb_we),
.wb_adr_i(wb_adr),
.wb_dat_i(wb_dati),
.wb_dat_o(wb_dato),
.wb_ack_o(wb_ack),
.wbc_ufm_irq(ufm_irq));
/* UFM Control */
always @(posedge C14M) begin
if (S==4'h0) begin
if (FS[15:14]==2'b00) wb_rst <= 1'b1;
else if (FS[15:14]==2'b01) wb_rst <= 1'b0;
else if (FS[15:14]==2'b10) begin
wb_rst <= 1'b0;
if (wb_ack || (FS[7:0]==0)) wb_cyc_stb <= 0;
else if ((FS[7:0]==1) && wb_req) wb_cyc_stb <= 1;
case (FS[13:8])
0: begin // Open frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h80;
wb_req <= 1;
end 1: begin // Enable configuration interface - command
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h74;
wb_req <= 1;
end 2: begin // Enable configuration interface - operand 1/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h08;
wb_req <= 1;
end 3: begin // Enable configuration interface - operand 2/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 4: begin // Enable configuration interface - operand 3/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 5: begin // Close frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 6: begin // Open frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h80;
wb_req <= 1;
end 7: begin // Poll status register - command
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h3C;
wb_req <= 1;
end 8: begin // Poll status register - operand 1/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 9: begin // Poll status register - operand 2/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 10: begin // Poll status register - operand 3/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 11, 12, 13, 14: begin // Read status register 1-4
wb_we <= 1'b0;
wb_adr[7:0] <= 8'h73;
wb_dati[7:0] <= 8'h3C;
wb_req <= 1;
end 15: begin // Close frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 16: begin // Open frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h80;
wb_req <= 1;
end 17: begin // Set UFM address - command
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'hB4;
wb_req <= 1;
end 18: begin // Set UFM address - operand 1/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 19: begin // Set UFM address - operand 2/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 20: begin // Set UFM address - operand 3/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 21: begin // Set UFM address - data 1/4
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h40;
wb_req <= 1;
end 22: begin // Set UFM address - data 2/4
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 23: begin // Set UFM address - data 3/4
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 24: begin // Set UFM address - data 4/4
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 190;
wb_req <= 1;
end 25: begin // Close frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 26: begin // Open frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h80;
wb_req <= 1;
end 27: begin // Read UFM page - command
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'hCA;
wb_req <= 1;
end 28: begin // Read UFM page - operand 1/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h10;
wb_req <= 1;
end 29: begin // Read UFM page - operand 2/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 30: begin // Read UFM page - operand 3/3
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h01;
wb_req <= 1;
end 31: begin // Read UFM page - data 0
wb_we <= 1'b0;
wb_adr[7:0] <= 8'h73;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
if (wb_ack) RWMask[7:0] <= wb_dato[7:0];
end 32: begin // Read UFM page - data 1
wb_we <= 1'b0;
wb_adr[7:0] <= 8'h73;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
if (wb_ack) LEDEN <= wb_dato[0];
end 33, 34,
35, 36, 37, 38,
39, 40, 41, 42,
43, 44, 45, 46: begin // Read UFM page - data 2-15
wb_we <= 1'b0;
wb_adr[7:0] <= 8'h73;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 47: begin // Close frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 48: begin // Open frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h80;
wb_req <= 1;
end 49: begin // Disable configuration interface - command
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h26;
wb_req <= 1;
end 50: begin // Disable configuration interface - operand 1/2
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 51: begin // Disable configuration interface - operand 2/2
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 52: begin // Close frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end 53: begin // Open frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h80;
wb_req <= 1;
end 54: begin // Bypass - command
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h71;
wb_dati[7:0] <= 8'hFF;
wb_req <= 1;
end 55: begin // Close frame
wb_we <= 1'b1;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 1;
end default: begin
wb_we <= 1'b0;
wb_adr[7:0] <= 8'h70;
wb_dati[7:0] <= 8'h00;
wb_req <= 0;
end
endcase
end else begin
wb_rst <= 1'b0;
wb_cyc_stb <= 1'b0;
wb_req <= 1'b0;
wb_we <= 1'b0;
wb_adr[7:0] <= 8'h00;
wb_dati[7:0] <= 8'h00;
end
end else begin
// UFM bitbang control
wb_rst <= 1'b0;
wb_req <= 1'b0;
if (RWSel && S==4'hC) begin
// LED control
if (CmdLEDSet) LEDEN <= D[0];
// Set capacity mask
if (CmdRWMaskSet) RWMask[7:0] <= {D[7], ~D[6:0]};
// Set EFB address
if (CmdBitbangMXO2) begin
wb_adr[7:0] <= D[7:0];
wb_dati[7:0] <= wb_adr[7:0];
end
// Excecute EFB R/W cycle
if (CmdExecMXO2) begin
wb_we <= D[0];
wb_cyc_stb <= 1;
end else if (wb_ack) wb_cyc_stb <= 0;
end
end
end
endmodule

189
CPLD/UFM-MAX.v Normal file
View File

@ -0,0 +1,189 @@
module RAM2E_UFM(C14M, S, FS, CS,
RWSel, D,
RWMask, LEDEN,
CmdRWMaskSet, CmdLEDSet,
CmdSetRWBankFFChip);
input C14M;
input [3:0] S;
input [15:0] FS;
input [2:0] CS;
input RWSel;
input [7:0] D;
output reg [7:0] RWMask;
output reg LEDEN;
input CmdRWMaskSet;
input CmdLEDSet;
output reg CmdSetRWBankFFChip;
/* RAMWorks register control - Altera MAX */
reg CmdBitbangMAX = 0; // Set by user command. Loads UFM outputs next RWSel
reg CmdPrgmMAX = 0; // Set by user command. Programs UFM
reg CmdEraseMAX = 0; // Set by user command. Erases UFM
always @(posedge C14M) begin
if (S==4'hC && RWSel) begin
if (CS==3'h6) begin // Recognize and submit command in CS6
// Chip detection commands
CmdSetRWBankFFChip <= D[7:0]==8'hFF; // MAX
//CmdSetRWBankFFChip <= D[7:0]==8'hFE; // SPI
//CmdSetRWBankFFChip <= D[7:0]==8'hFD; // MachXO2
// Altera MAX II/V commands
CmdBitbangMAX <= D[7:0]==8'hEA;
if (!CmdEraseMAX && !CmdPrgmMAX) begin
if (D[7:0]==8'hEE) CmdEraseMAX <= 1;
if (D[7:0]==8'hEF) CmdPrgmMAX <= 1;
end
// SPI commands
//CmdBitbangSPI <= D[7:0]==8'hEB;
// MachXO2 commands
//CmdBitbangMXO2 <= D[7:0]==8'hEC;
//CmdExecMXO2 <= D[7:0]==8'hED;
end else begin // Reset command triggers
CmdSetRWBankFFChip <= 0;
CmdBitbangMAX <= 0;
end
end
end
/* UFM Interface */
reg [15:8] UFMD = 0; // *Parallel* UFM data register
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 UFMRTPBusy = 0;
always @(posedge C14M) UFMRTPBusy <= UFMBusy || RTPBusy;
reg UFMInitDone = 0; // 1 if UFM initialization finished
reg UFMReqErase = 0; // 1 if UFM requires erase
reg DRCLKPulse = 0; // Set by user command. Causes DRCLK pulse next C14M
/* UFM control */
reg UFMProgStart;
always @(posedge C14M) begin
if (S==4'h0) begin
if ((FS[15:13]==3'b101) || (FS[15:13]==3'b111 && UFMReqErase)) begin
// In states AXXX-BXXX and also EXXX-FXXX if erase/wrap req'd
// shift in 0's to address register
ARCLK <= FS[0]; // Clock address register
DRCLK <= 1'b0; // Don't clock data register
ARShift <= 1'b1; // Shift address registers
DRDIn <= 1'b0; // Don't care DRDIn
DRShift <= 1'b0; // Don't care DRDShift
end else if (!UFMInitDone && FS[15:13]==3'b110 && FS[4:1]==4'h4) begin
// In states CXXX-DXXX (substep 4)
// Xfer to data reg (repeat 256x 1x)
ARCLK <= 1'b0; // Don't clock address register
DRCLK <= FS[0]; // Clock data register
ARShift <= 1'b0; // Don't care ARShift
DRDIn <= 1'b0; // Don't care DRDIn
DRShift <= 1'b0; // Don't care DRShift
end else if (!UFMInitDone && FS[15:13]==3'b110 && (FS[4:1]==4'h7 || FS[4]==1'b1)) begin
// In states CXXX-DXXX (substeps 8-F)
// Save UFM D15-8, shift out D14-7 (repeat 256x 8x)
DRCLK <= FS[0]; // Clock data register
ARShift <= 1'b0; // ARShift is 0 because we want to increment
DRDIn <= 1'b0; // Don't care what to shift into data register
DRShift <= 1'b1; // Shift data register
// Shift into UFMD
if (FS[0]) UFMD[15:8] <= {UFMD[14:8], DRDOut};
// Compare and store mask
if (FS[4:1]==4'hF) begin
ARCLK <= FS[0]; // Clock address register to increment
// If byte is erased (0xFF, i.e. all 1's, is erased)...
if (UFMD[15:8]==8'hFF && DRDOut==1'b1) begin
// Current UFM address is where we want to store
UFMInitDone <= 1'b1; // Quit iterating
// Otherwise byte is valid setting (i.e. some bit is 0)...
end else begin
// Set RWMask, but if saved mask is 0x80, store ~0xFF
if (UFMD[15:8]==8'b10000000) begin
RWMask[7:0] <= {1'b1, ~7'h7F};
end else RWMask[7:0] <= {UFMD[15], ~UFMD[14:8]};
// Set LED setting
LEDEN <= DRDOut ^ UFMD[15];
// If last byte in sector...
if (FS[12:5]==8'hFF) begin
UFMReqErase <= 1'b1; // Mark need to erase
end
end
end else ARCLK <= 1'b0; // Don't clock address register
end else begin
ARCLK <= 1'b0;
DRCLK <= 1'b0;
ARShift <= 1'b0;
DRDIn <= 1'b0;
DRShift <= 1'b0;
end
// Don't erase or program UFM during initialization
UFMErase <= 1'b0;
UFMProgram <= 1'b0;
// Keep DRCLK pulse control disabled during init
DRCLKPulse <= 1'b0;
// Reset UFMProgStart
UFMProgStart <= 1'b0;
end else begin
// Can only shift UFM data register now
ARCLK <= 1'b0;
ARShift <= 1'b0;
DRShift <= 1'b1;
// UFM bitbang control
if (CmdBitbangMAX && RWSel && S==4'hC) begin
DRDIn <= D[6];
DRCLKPulse <= D[7];
DRCLK <= 1'b0;
end else begin
DRCLKPulse <= 1'b0;
DRCLK <= DRCLKPulse;
end
// Volatile settings command execution
if (RWSel && S==4'hC) begin
// LED control
if (CmdLEDSet) LEDEN <= D[0];
// Set capacity mask
if (CmdRWMaskSet) RWMask[7:0] <= {D[7], ~D[6:0]};
end
// UFM programming sequence
if (S==4'h1) begin
if (!UFMProgStart && !UFMRTPBusy) begin
if (CmdPrgmMAX) begin
UFMErase <= UFMReqErase;
UFMProgStart <= 1;
end else if (CmdEraseMAX) UFMErase <= 1;
end else if (UFMProgStart && !UFMRTPBusy) begin
UFMErase <= 0;
if (!UFMErase) UFMProgram <= 1;
end
end
end
end
endmodule