mirror of
https://github.com/techav-homebrew/SE-VGA.git
synced 2025-02-12 11:30:25 +00:00
partial draft 1
This commit is contained in:
parent
eaf6747995
commit
77a0a23e1a
@ -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
108
cpusnoop.sv
Normal 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
76
primitives/primitives.sv
Normal 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
47
se-vga.sv
Normal 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
67
vgacount.sv
Normal 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
28
vgagen.sv
Normal 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
70
vgaout.sv
Normal 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
|
Loading…
x
Reference in New Issue
Block a user