SE-Exp30/paste.sv

274 lines
9.4 KiB
Systemverilog

/******************************************************************************
* SE-Exp30 MacSE Accelerator
* techav
* 2021-09-26
* Processor Accelerator System Translation Engine
******************************************************************************
* Handles all logic to translate the Mac SE 68000 PDS bus to the 68030 bus as
* well as additional logic for interfacing with the 68882 FPU.
*****************************************************************************/
module paste (
inout wire cpuRESETnz, // 68030 reset signal (tristate)
inout wire cpuHALTnz, // 68030 halt signal (tristate)
input wire cpuDSn, // 68030 data strobe signal
input wire cpuASn, // 68030 address strobe signal
inout wire cpuDSACK0nz, // 68030 DS Ack 0 signal
inout wire cpuDSACK1nz, // 68030 DS Ack 1 signal
input wire cpuSIZE0, // 68030 Size 0 signal
input wire cpuSIZE1, // 68030 Size 1 signal
input wire cpuA0, // 68030 Address 0 signal
input logic [3:0] cpuAHI, // 68030 Address Hi (16MB) signals A[23:20]
input logic [6:0] cpuAMID, // 68030 Address Mid (FPU decode) signals A[19:13]
output wire cpuAVECn, // 68030 Autovector request signal
input logic [2:0] cpuFC, // 68030 Function Code signals
input wire cpuClock, // 68030 Primary CPU Clock signal
input wire cpuRnW, // 68030 Read/Write signal
input wire cpuBGn, // 68030 Bus Grant signal
output wire cpuBERRn, // 68030 Bus Error signal
output wire cpuCIINn, // 68030 Cache Inhibit signal
input wire pdsRESETn, // PDS Reset signal
inout wire pdsLDSnz, // PDS Lower Data Strobe signal
inout wire pdsUDSnz, // PDS Upper Data Strobe signal
inout wire pdsASnz, // PDS Address Strobe signal
input wire pdsDTACKn, // PDS Data Xfer Ack signal
input wire pdsBGn, // PDS Bus Grant signal
output wire pdsBGACKn, // PDS Bus Grant Ack signal
output wire pdsBRn, // PDS Bus Request signal
inout wire pdsVMAnz, // PDS Valid Memory Addr signal
input wire pdsVPAn, // PDS Valid Peripheral Addr signal
input wire pdsBERRn, // PDS Bus Error signal
input wire pdsPMCYCn, // PDS Memory Cycle signal
input wire pdsC8M, // PDS 8MHz System Clock signal
output wire pdsClockE, // PDS 800kHz 6800 bus E clock
output wire bufDHICEn, // Data buffer CPU[31:24] <=> PDS[15:8]
output wire bufDLO1CEn, // Data buffer CPU[23:16] <=> PDS[7:0]
output wire bufDLO2CEn, // Data buffer CPU[31:24] <=> PDS[7:0]
output wire bufDDIR, // Data buffer direction
output wire bufCCEn, // Control signal buffer enable
output wire bufACEn, // Address buffer enable
input wire fpuSENSEn, // FPU Presence Detect signal
output wire fpuCEn // FPU Chip Select signal
);
// SE memory cycle syncronization
// the SE bus is fully synchronous and uses the PMCYCn singal to indicate when
// it is loading video data from memory and to indicate the beginning of a
// 68000 cpu cycle. Asserting PDS ASn during the S3-S4 transition will cause
// the memory RAS/CAS generator to glitch, and so should be avoided.
logic [1:0] cycCount;
always @(posedge pdsC8M or posedge pdsPMCYCn) begin
if(pdsPMCYCn) cycCount <= 0;
else if(pdsC8M) begin
cycCount <= cycCount + 2'h1;
end
end
// pds address strobe
// For ROM & peripheral accesses, PDS ASn can fall at any time, but for memory
// accesses, PDS ASn must be synchronized with the SE state machine
// For memory accesses, we need to check both the current address and the state
// of cycCount to meet timing requirements
logic pdsASnINNER;
always @(posedge pdsC8M or posedge cpuASn) begin
if(cpuASn) pdsASnINNER <= 1;
else if(cpuAHI < 4'h4) begin
// this is a memory access cycle, we need to pay special attention to
// synchronization with the SE state machine
if(!pdsPMCYCn && cycCount != 1) pdsASnINNER <= 0;
else if(!pdsASnINNER && !cpuASn) pdsASnINNER <= 0; // keep low if already low as long as CPU holds low
else pdsASnINNER <= 1;
// I'm not entirely sure this is going to work, given internal timing
// of the CPLD, signal propagation times, etc.
end else if(pdsC8M && !cpuASn) pdsASnINNER <= 0;
else pdsASnINNER <= 1;
end
always_comb begin
if(pdsBGn) pdsASnz <= 1'bZ;
else if(!pdsASnINNER) pdsASnz <= 0;
else pdsASnz <= 1'bZ;
end
// cpu bus termination (normal, 6800, & autovector)
logic cpuDTACKnINNER;
always @(posedge pdsC8M or posedge cpuASn) begin
if(cpuASn) cpuDTACKnINNER <= 1;
else if(pdsC8M && !pdsASnINNER && !pdsDTACKn) cpuDTACKnINNER <= 0;
else cpuDTACKnINNER <= 1;
end
// since the 68000 had a 16-bit bus and did not support
// dynamic bus sizing the way the 68030 did, all our
// normal bus cycles will be terminated as 16-bit.
// The exception is interrupts, where we'll terminate
// with AVEC instead of DSACKx
always_comb begin
cpuDSACK0nz <= 1'bZ;
if(cpuFC == 3'h7) begin
// interrupt autovector
if(!cpuDTACK68nINNER) begin
cpuDSACK1nz <= 1'bZ;
cpuAVECn <= 0;
end else begin
cpuDSACK1nz <= 1'bZ;
cpuAVECn <= 1;
end
end else begin
if(!cpuDTACKnINNER || !cpuDTACK68nINNER) begin
cpuDSACK1nz <= 0;
cpuAVECn <= 1;
end else begin
cpuDSACK1nz <= 1'bZ;
cpuAVECn <= 1;
end
end
end
// pds E clock & 6800 bus
reg [3:0] pdsEcount;
reg pdsVMAnINNER, cpuDTACK68nINNER;
always @(posedge pdsC8M) begin
if(pdsEcount == 9) pdsEcount <= 0;
else pdsEcount <= pdsEcount + 4'h1;
end
always @(posedge cpuClock or posedge pdsVPAn) begin
if(pdsVPAn) pdsVMAnINNER <= 1;
else if(!pdsVPAn && pdsEcount == 2) pdsVMAnINNER <= 0;
end
always @(posedge pdsC8M or posedge cpuASn) begin
if(cpuASn) cpuDTACK68nINNER <= 1;
else if(!pdsVMAnINNER && pdsEcount > 8) cpuDTACK68nINNER <= 0;
end
always_comb begin
if(pdsEcount < 6) pdsClockE <= 0;
else pdsClockE <= 1;
if(pdsVMAnINNER) pdsVMAnz <= 1'bZ;
else pdsVMAnz <= 0;
end
// pds data strobes
reg pdsDSnINNER;
wire pdsDSn2INNER;
wire pdsLDSnINNER;
wire pdsUDSnINNER;
wire pdsUPPERn, pdsLOWERn;
always @(posedge pdsC8M or posedge cpuASn) begin
if(cpuASn) pdsDSnINNER <= 1;
else if (pdsC8M && !pdsASnINNER) pdsDSnINNER <= 0;
else pdsDSnINNER <= 1;
end
always_comb begin
// upper strobe
if(cpuRnW) pdsUPPERn <= 0;
else begin
if(cpuA0) pdsUPPERn <= 1;
else pdsUPPERn <= 0;
end
// lower strobe
if(cpuRnW) pdsLOWERn <= 0;
else begin
if(cpuSIZE0 == 1 && cpuSIZE1 == 0 && cpuA0 == 0) pdsLOWERn <= 1;
else pdsLOWERn <= 0;
end
if(cpuRnW) pdsDSn2INNER <= pdsASnINNER;
else pdsDSn2INNER <= pdsDSnINNER;
// Upper Data Strobe
if(pdsDSn2INNER) begin
pdsUDSnINNER <= 1;
end else begin
pdsUDSnINNER <= pdsUPPERn;
end
// Lower Data Strobe
if(pdsDSn2INNER) begin
pdsLDSnINNER <= 1;
end else begin
pdsLDSnINNER <= pdsLOWERn;
end
// Data Strobe outputs
if(pdsBGn) begin
pdsLDSnz <= 1'bZ;
pdsUDSnz <= 1'bZ;
end else begin
if(pdsLDSnINNER) pdsLDSnz <= 1'bZ;
else pdsLDSnz <= 0;
if(pdsUDSnINNER) pdsUDSnz <= 1'bZ;
else pdsUDSnz <= 0;
end
end
// fpu addressing
wire fpuCEnINNER;
always_comb begin
if(cpuAHI == 0 && cpuAMID == 7'h11 && cpuFC == 3'h7) fpuCEnINNER <= 0;
else fpuCEnINNER <= 1;
fpuCEn <= fpuCEnINNER;
end
// bus error
always_comb begin
if(!fpuCEnINNER && !cpuASn && fpuSENSEn) cpuBERRn <= 0;
else if(!pdsBERRn) cpuBERRn <= 0;
else cpuBERRn <= 1;
end
// cache inhibit
always_comb begin
if(cpuAHI >= 4'h4) cpuCIINn <= 0;
else cpuCIINn <= 1;
end
// cpu reset
reg [1:0] resetState;
always @(posedge cpuClock or negedge pdsRESETn) begin
if(!pdsRESETn) resetState <= 0;
else if(cpuClock) begin
case(resetState)
0: begin
if(pdsRESETn) resetState <= 1;
else resetState <= 0;
end
1: begin
if(!pdsBGn) resetState <= 2;
else resetState <= 1;
end
2: begin
resetState <= 2;
end
default: begin
resetState <= 2;
end
endcase
end
end
always_comb begin
if(resetState == 2) begin
cpuHALTnz <= 1'bZ;
cpuRESETnz <= 1'bZ;
pdsBGACKn <= 0;
end else begin
cpuHALTnz <= 0;
cpuRESETnz <= 0;
pdsBGACKn <= 1;
end
pdsBRn <= 0;
end
// bus buffer controls
assign bufDDIR = cpuRnW;
wire bufCEn;
assign bufCEn = ~(cpuBGn & ~pdsBGn);
assign bufACEn = bufCEn;
assign bufCCEn = bufCEn;
assign bufDHICEn = bufCEn;
assign bufDLO1CEn = bufCEn;
// it turns out we don't actually need the Lo2 buffer
assign bufDLO2CEn = 1;
endmodule