partial draft 1

This commit is contained in:
techav 2021-04-06 23:15:48 -05:00
parent eaf6747995
commit 77a0a23e1a
7 changed files with 401 additions and 1 deletions

View File

@ -1,2 +1,6 @@
# SE-VGA
Mirror the Mac SE video over VGA
Simple CPLD project to mirror the Mac SE video over VGA. No scaling is performed -- the Mac 512x342 video is displayed letterboxed (black borders) in a 640x480 frame.
Circuit uses a single AFT1508AS-100AU CPLD, 32kx8 15ns SRAM, and a 25.175MHz can oscillator, along with some passives.
Plugs into SE PDS slot and snoops writes to the frame buffer memory locations. Writes are cached and copied to VRAM.

108
cpusnoop.sv Normal file
View File

@ -0,0 +1,108 @@
/******************************************************************************
* SE-VGA
* CPU Bus Snoop
* techav
* 2021-04-06
******************************************************************************
* Watches for writes to frame buffer memory addresses and copies that data
* into VRAM
*****************************************************************************/
module cpusnoop (
input wire nReset, // System Reset signal
input wire pixClock, // 25.175MHz Pixel Clock
input logic [2:0] sequence, // Sequence count (low 3 bits of hCount)
input logic [23:1] cpuAddr, // CPU Address bus
input logic [15:0] cpuData, // CPU Data bus
input wire ncpuAS, // CPU Address Strobe signal
input wire ncpuUDS, // CPU Upper Data Strobe signal
input wire ncpuLDS, // CPU Lower Data Strobe signal
input wire cpuRnW, // CPU Read/Write select signal
input wire cpuClk, // CPU Clock
output logic [12:0] vramAddr, // VRAM Address Bus
inout logic [7:0] vramData, // VRAM Data Bus
output wire nvramWE, // VRAM Write strobe
);
// framebuffer address (with 4MB RAM installed): 0x3FA700 - 0x3FFFFF
wire pendWriteLo; // low byte write to VRAM pending
wire pendWriteHi; // high byte write to VRAM pending
logic [12:1] addrCache; // store address for cpu writes to framebuffer
logic [7:0] dataCacheLo; // store data for cpu writes to low byte
logic [7:0] dataCacheHi; // store data for cpu writes to high byte
// when cpu addresses the framebuffer, save the address
always @(negedge ncpuAS or negedge nReset) begin
if(nReset == 1'b0) begin
addrCache <= 16'h0;
end else begin
if(cpuAddr >= 24'h3FA700 && cpuAddr < 24'h400000) begin
addrCache[12:0] <= cpuAddr - 16'hA700;
end
end
end
// when cpu addresses the framebuffer, save high byte
always @(negedge ncpuUDS or negedge nReset) begin
if(nReset == 1'b0) begin
dataCacheHi <= 8'h0;
end else begin
if(cpuAddr >= 24'h3FA700 && cpuAddr < 24'h400000 && cpuRnW == 1'b0) begin
dataCacheHi <= cpuData[15:8];
end
end
end
// when cpu addresses the framebuffer, save low byte
always @(negedge ncpuUDS or negedge nReset) begin
if(nReset == 1'b0) begin
dataCacheLo <= 8'h0;
end else begin
if(cpuAddr >= 24'h3FA700 && cpuAddr < 24'h400000 && cpuRnW == 1'b0) begin
dataCacheLo <= cpuData[7:0];
end
end
end
// set pending flags for cpu accesses & clear when that cycle comes back around
always @(negedge pixClock or negedge nReset) begin
if(nReset == 1'b0) begin
pendWriteLo <= 1'b0;
pendWriteHi <= 1'b0;
end else begin
if(cpuAddr >= 24'h3FA700 && cpuAddr < 24'h400000 && cpuRnW == 1'b0) begin
if(ncpuUDS == 1'b0) begin
pendWriteHi <= 1'b1;
end
if(ncpuLDS == 1'b0) begin
pendWriteLo <= 1'b1;
end
end else begin
if(sequence == 3'h1) begin
pendWriteLo <= 1'b0;
end
if(sequence == 3'h2) begin
pendWriteHi <= 1'b0;
end
end
end
end
always_comb begin
vramAddr[12:1] <= addrCache[12:1];
if(pendWriteLo == 1'b1 && sequence == 3'h1) begin
vramAddr[0] <= 1'b0;
nvramWE <= 1'b0;
vramData <= dataCacheLo;
end else if(pendWriteHi == 1'b1 && sequence = 3'h2) begin
vramAddr[0] <= 1'b1;
nvramWE <= 1'b0;
vramData <= dataCacheHi;
end else begin
vramAddr[0] <= 1'b0;
nvramWE <= 1'b1;
vramData <= 8'bZ;
end
end
endmodule

76
primitives/primitives.sv Normal file
View File

@ -0,0 +1,76 @@
/******************************************************************************
* SE-VGA
* Primitives
* techav
* 2021-04-06
******************************************************************************
* Basic modules to be used elsewhere
*****************************************************************************/
// basic d-flipflop
module dff (
input wire nReset,
input wire clk,
input wire d,
output reg q
);
always @(posedge clock or negedge nReset) begin
if(nReset == 1'b0) begin
q <= 1'b0;
end else begin
q <= d;
end
end
endmodule
// basic 8-bit mux
module mux8 (
input logic [7:0] inA,
input logic [7:0] inB,
input wire select,
output logic [7:0] out
);
always_comb begin
if(select == 1'b0) begin
out <= inA;
end else begin
out <= inB;
end
end
endmodule
// basic 8-to-1 mux
module mux8x1 (
input logic[7:0] in,
input logic[2:0] select,
output wire out
);
always_comb begin
out <= in[select];
end
endmodule
// basic 8-bit PISO shift register
module piso8 (
input wire nReset,
input wire clk,
input wire load,
input logic [7:0] parIn,
output wire out
);
logic [7:0] muxIns;
logic [7:0] muxOuts;
mux8 loader(muxIns[7:0],parIn[7:0],load,muxOuts[7:0]);
dff u0(nReset,clk,muxOuts[0],muxIns[1]);
dff u1(nReset,clk,muxOuts[1],muxIns[2]);
dff u2(nReset,clk,muxOuts[2],muxIns[3]);
dff u3(nReset,clk,muxOuts[3],muxIns[4]);
dff u4(nReset,clk,muxOuts[4],muxIns[5]);
dff u5(nReset,clk,muxOuts[5],muxIns[6]);
dff u6(nReset,clk,muxOuts[6],muxIns[7]);
dff u7(nReset,clk,muxOuts[7],muxIns[0]);
out <= muxIns[0];
endmodule

47
se-vga.sv Normal file
View File

@ -0,0 +1,47 @@
/******************************************************************************
* SE-VGA
* Top-level module
* techav
* 2021-04-06
******************************************************************************
* Pulls together all the smaller modules to form the SE-VGA adapter
*****************************************************************************/
module design sevga (
input wire nReset, // System reset signal
input wire pixClk, // 25.175MHz pixel clock
output wire nhSync, // HSync signal
output wire nvSync, // VSync signal
output wire vidOut, // 1-bit Monochrome video signal
output logic [12:0] vramAddr, // VRAM Address bus
inout logic [7:0] vramData, // VRAM Data bus
output wire nvramOE, // VRAM Read strobe
output wire nvramWE, // VRAM Write strobe
input logic [23:1] cpuAddr, // CPU Address bus
input logic [15:0] cpuData, // CPU Data bus
input wire ncpuAS, // CPU Address Strobe signal
input wire ncpuUDS, // CPU Upper Data Strobe signal
input wire ncpuLDS, // CPU Lower Data Strobe signal
input wire cpuRnW, // CPU Read/Write select signal
input wire cpuClk // CPU Clock
);
logic [9:0] hCount;
logic [9:0] vCount;
wire hActive;
wire hSEActive;
logic [7:0] vidVramData;
logic [12:0] vidVramAddr;
// link module that generates all our timing signals
vgagen vgatiming(nReset,pixClk,hCount,hActive,hSEActive,nhSync,vCount,vActive,vSEActive,nvSync);
// link module that fetches & outputs video data
vgaout vidvram(pixClock,nReset,hCount,vCount,hSEActive,vSEActive,vidVramData,vidVramAddr,nvramOE,vidOut);
// link module that handles cpu writes
endmodule

67
vgacount.sv Normal file
View File

@ -0,0 +1,67 @@
/******************************************************************************
* SE-VGA
* VGA signal counter
* techav
* 2021-04-06
******************************************************************************
* Low-level VGA signal counter
*****************************************************************************/
module vgacount (
input wire nReset, // system reset signal
input wire clock, // counter increment clock
output logic [9:0] count, // count output
output wire nSync, // sync pulse
output wire activeVid, // active video signal
output wire activeSE // secondary active video signal (SE)
);
parameter COUNTMAX=800,
SYNCBEGIN=592,
SYNCEND=688,
ACTBEGIN=576,
ACTEND=736,
SEACTBEGIN=512;
logic [9:0] counter;
// primary counter
always @(negedge clock or negedge nReset) begin
if(nReset == 1'b0) begin
counter <= 10'h0;
end else begin
if (counter < COUNTMAX) begin
counter <= counter + 10'h1;
end else begin
counter <= 10'h0;
end
end
end
// combinatorial logic derived from the counters
always_comb begin
// output the count signals
count <= counter;
// Sync pulse
if(hCount >= SYNCBEGIN && hCount < SYNCEND) begin
nhSync <= 1'b0;
end else begin
nhSync <= 1'b1;
end
if(hCount >= ACTBEGIN && hCount < ACTEND) begin
hActive <= 1'b0;
end else begin
hActive <= 1'b1;
end
if(hCount >= SEACTBEGIN) begin
hSEActive <= 1'b0;
end else begin
hSEActive <= 1'b1;
end
end
endmodule

28
vgagen.sv Normal file
View File

@ -0,0 +1,28 @@
/******************************************************************************
* SE-VGA
* VGA timing generator
* techav
* 2021-04-06
******************************************************************************
* Generates VGA timing signals & counters
*****************************************************************************/
`include "vgacount.sv"
module vgagen (
input wire nReset, // master reset signal
input wire pixClk, // 25.175MHz pixel clock
output logic [9:0] hCount, // horizontal pixel count
output wire hActive, // horizontal VGA active video signal
output wire hSEActive, // horizontal SE active video signal
output wire nhSync, // horizontal sync pulse signal
output logic [9:0] vCount, // vertical line count
output wire vActive, // vertical VGA active video signal
output wire vSEActive, // vertical SE active video signal
output wire nvSync // vertical sync pulse signal
);
vgacount #(800,592,688,576,736,512) hoz(nReset,pixClk,hCount,nhSync,hActive,hSEActive);
vgacount #(525,421,423,411,456,342) ver(nReset,nhSync,vCount,nvSync,vActive,vSEActive);
endmodule

70
vgaout.sv Normal file
View File

@ -0,0 +1,70 @@
/******************************************************************************
* SE-VGA
* VGA video output
* techav
* 2021-04-06
******************************************************************************
* Fetches video data from VRAM and shifts out
*****************************************************************************/
`include "primitives.sv"
module vgaout (
input wire pixClock,
input wire nReset,
input logic [9:0] hCount,
input logic [9:0] vCount,
input wire hSEActive,
input wire vSEActive,
inout logic [7:0] vramData,
output logic [12:0] vramAddr,
output wire nvramOE,
output wire vidOut
);
reg [7:0] rVid;
wire vidMuxOut;
wire vidActive; // combined active video signal
mux8x1 vidOutMux(rVid[7:0],hCount[2:0],vidMuxOut);
// latch incoming vram data on rising clock and sequence 7
always @(posedge pixClock or negedge nReset) begin
if(nReset == 1'b0) begin
rVid <= 8'h0;
end else begin
if(hCount[2:0] == 3'b7) begin
rVid <= vramData;
end
end
end
always_comb begin
// combined video active signal
if(hSEActive == 1'b1 && vSEActive == 1'b1) begin
vidActive <= 1'b1;
end else begin
vidActive <= 1'b0;
end
// video data output
if(vidActive == 1'b1) begin
vidOut <= vidMuxOut;
end else begin
vidOut <= 1'b0;
end
// vram read signal
if(vidActive == 1'b1 && hCount[2:0] == 3'b7) begin
nvramOE <= 1'b0;
end else begin
nvramOE <= 1'b1;
end
// vram address signals
// these will be mux'd with cpu addresses externally
vramAddr[12:6] <= vCount[6:0];
vramAddr[5:0] <= hCount[8:3];
end
endmodule