diff --git a/README.md b/README.md index 32d5d4e..7e43b71 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,17 @@ Simple CPLD project to mirror the Mac SE video over VGA. No scaling is performed 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. \ No newline at end of file +Plugs into SE PDS slot and snoops writes to the frame buffer memory locations. Writes are cached and copied to VRAM. + +The Mac SE primary framebuffer starts at 0x5900 below the top of RAM. Since it's not in a static location for every system, the system's memory configuration is needed. This is set by three ramSize jumpers, which mask CPU address bits 21, 20, 19. Not all possible ramSize selections are valid memory sizes when using 30-pin SIMMs in the Mac SE. In theory, these combinations could be possible when using PDS memory expansion cards, but this is unlikely. The chart below indicates the valid & invalid ramSize configurations and the corresponding installed SIMM combinations. + +|ramSize|Framebuffer Start|RAM Top Address + 1|RAM Size|Installed SIMMs | +|:-----:|:---------------:|:-----------------:|:------:|------------------------------| +| 111 | 0x3fa700 | $400000 | 4.0MB | `[ 1MB 1MB ][ 1MB 1MB ]` | +| 110 | 0x37a700 | $380000 | 3.5MB | Invalid combination | +| 101 | 0x2fa700 | $300000 | 3.0MB | Invalid combination | +| 100 | 0x27a700 | $280000 | 2.5MB | `[ 1MB 1MB ][256kB 256kB]` | +| 011 | 0x1fa700 | $200000 | 2.0MB | `[ 1MB 1MB ][ --- --- ]` | +| 010 | 0x17a700 | $180000 | 1.5MB | Invalid combination | +| 001 | 0x0fa700 | $100000 | 1.0MB | `[256kB 256kB][256kB 256kB]` | +| 000 | 0x07a700 | $080000 | 0.5MB | `[256kB 256kB][ --- --- ]` | diff --git a/cpusnoop.sv b/cpusnoop.sv index a59d136..1efd67f 100644 --- a/cpusnoop.sv +++ b/cpusnoop.sv @@ -45,7 +45,7 @@ module cpusnoop ( // when cpu addresses the framebuffer, set our enable signal /* framebuffer starts $5900 below the top of RAM - * ramSize is used to mask the cpuAddr bits [21:9] to select the amount + * ramSize is used to mask the cpuAddr bits [21:19] to select the amount * of memory installed in the computer. Not all possible ramSize selections * are valid memory sizes when using 30-pin SIMMs in the Mac SE. * They may be possible using PDS RAM expansion cards. @@ -175,6 +175,12 @@ module cpusnoop ( end always_comb begin + // output VRAM address + // we actually do an endian swap here assigning the low-order bit of + // the VRAM address because the video shift register in the SE loads + // a full 16-bit word and shifts out starting with the MSB. + // An endian swap here ensures that when we load the VRAM for output + // the bits are in the right order. vramAddr[14:1] <= addrCache[13:0]; if(cycleState == S4) begin vramAddr[0] <= 0; @@ -182,12 +188,16 @@ module cpusnoop ( vramAddr[0] <= 1; end + // Assert VRAM Write signal during CPU Cycle states S3 & S4 if(cycleState == S3 || cycleState == S4) begin nvramWE <= 0; end else begin nvramWE <= 1; end + // Output our internal data cache registers on CPU Cycle states S3 & S4 + // Otherwise, just output 0. This will be muxed for the VRAM data bus + // in the next module outside of here. if(cycleState == S3) begin vramDataOut <= dataCacheLo; end else if(cycleState == S4) begin diff --git a/se-vga.sv b/se-vga.sv index abea33c..e1ef6b2 100644 --- a/se-vga.sv +++ b/se-vga.sv @@ -25,7 +25,6 @@ module sevga ( 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 (probably not needed) input logic [2:0] ramSize // Select installed RAM size ); @@ -35,7 +34,7 @@ wire hActive; wire hSEActive; wire vActive; wire vSEActive; -wire nvramWEpre; +wire nvramWEpre; // VRAM Write signal from cpu snoop logic [14:0] vidVramAddr; logic [14:0] cpuVramAddr; diff --git a/sevga.vwf b/sevga.vwf index d1a0107..570c336 100644 --- a/sevga.vwf +++ b/sevga.vwf @@ -1955,8 +1955,8 @@ TRANSITION_LIST("vramData[7]") NODE { REPEAT = 1; - LEVEL Z FOR 280.0; - LEVEL 1 FOR 80.0; + LEVEL Z FOR 320.0; + LEVEL 1 FOR 40.0; LEVEL Z FOR 240.0; LEVEL 0 FOR 80.0; LEVEL Z FOR 240.0; @@ -2018,8 +2018,8 @@ TRANSITION_LIST("vramData[6]") NODE { REPEAT = 1; - LEVEL Z FOR 280.0; - LEVEL 0 FOR 80.0; + LEVEL Z FOR 320.0; + LEVEL 0 FOR 40.0; LEVEL Z FOR 240.0; LEVEL 1 FOR 80.0; LEVEL Z FOR 240.0; @@ -2081,8 +2081,8 @@ TRANSITION_LIST("vramData[5]") NODE { REPEAT = 1; - LEVEL Z FOR 280.0; - LEVEL 0 FOR 80.0; + LEVEL Z FOR 320.0; + LEVEL 0 FOR 40.0; LEVEL Z FOR 240.0; LEVEL 0 FOR 80.0; LEVEL Z FOR 240.0; @@ -2146,8 +2146,8 @@ TRANSITION_LIST("vramData[4]") NODE { REPEAT = 1; - LEVEL Z FOR 280.0; - LEVEL 0 FOR 80.0; + LEVEL Z FOR 320.0; + LEVEL 0 FOR 40.0; LEVEL Z FOR 240.0; LEVEL 1 FOR 80.0; LEVEL Z FOR 240.0; @@ -2208,8 +2208,8 @@ TRANSITION_LIST("vramData[3]") NODE { REPEAT = 1; - LEVEL Z FOR 280.0; - LEVEL 0 FOR 80.0; + LEVEL Z FOR 320.0; + LEVEL 0 FOR 40.0; LEVEL Z FOR 240.0; LEVEL 0 FOR 80.0; LEVEL Z FOR 240.0; @@ -2274,8 +2274,8 @@ TRANSITION_LIST("vramData[2]") NODE { REPEAT = 1; - LEVEL Z FOR 280.0; - LEVEL 0 FOR 80.0; + LEVEL Z FOR 320.0; + LEVEL 0 FOR 40.0; LEVEL Z FOR 240.0; LEVEL 1 FOR 80.0; LEVEL Z FOR 240.0; @@ -2339,8 +2339,8 @@ TRANSITION_LIST("vramData[1]") NODE { REPEAT = 1; - LEVEL Z FOR 280.0; - LEVEL 1 FOR 80.0; + LEVEL Z FOR 320.0; + LEVEL 1 FOR 40.0; LEVEL Z FOR 240.0; LEVEL 0 FOR 80.0; LEVEL Z FOR 240.0; @@ -2406,8 +2406,8 @@ TRANSITION_LIST("vramData[0]") NODE { REPEAT = 1; - LEVEL Z FOR 280.0; - LEVEL 1 FOR 80.0; + LEVEL Z FOR 320.0; + LEVEL 1 FOR 40.0; LEVEL Z FOR 240.0; LEVEL 1 FOR 80.0; LEVEL Z FOR 240.0; diff --git a/vgacount.sv b/vgacount.sv index a60a069..bdff37e 100644 --- a/vgacount.sv +++ b/vgacount.sv @@ -19,12 +19,12 @@ module vgacount ( output wire activeSE // secondary active video signal (SE) ); -parameter COUNTMAX=800, - SYNCBEGIN=592, - SYNCEND=688, - ACTBEGIN=576, - ACTEND=736, - SEACTBEGIN=512; +parameter COUNTMAX=800, // Total dot count per line or line count per frame + SYNCBEGIN=592, // Dot/Line count where sync pulse begins + SYNCEND=688, // Dot/Line count +1 where sync pulse ends + ACTBEGIN=576, // Dot/Line count where VGA active video begins + ACTEND=736, // Dot/Line count +1 where VGA active video ends + SEACTBEGIN=512; // Dot/Line count +1 where SE video window ends logic [9:0] counter; diff --git a/vgagen.sv b/vgagen.sv index 06d2b08..06f25c3 100644 --- a/vgagen.sv +++ b/vgagen.sv @@ -25,26 +25,11 @@ module vgagen ( output wire nvSync // vertical sync pulse signal ); +// Generate horizontal signal timing vgacount #(800,592,688,576,736,512) hoz(nReset,pixClk,hCount,nhSync,hActive,hSEActive); +// Generate vertical signal timing vgacount #(525,421,423,411,456,342) ver(nReset,nhSync,vCount,nvSync,vActive,vSEActive); -/* -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; -*/ - endmodule `endif \ No newline at end of file diff --git a/vgaout.sv b/vgaout.sv index 3e42b1b..aa24dc4 100644 --- a/vgaout.sv +++ b/vgaout.sv @@ -22,14 +22,13 @@ module vgaout ( output wire vidOut ); -//reg [7:0] rVid; -wire vidMuxOut; +wire vidMuxOut; // pixel data shift out wire vidActive; // combined active video signal -//wire vgaShiftEn; // Enable pixel shift out wire vgaShiftL1; // Load VRAM data into register wire vgaShiftL2; // Load VRAM data into shifter +// connect module for video out shift register vgaShiftOut vOut( .nReset(nReset), .clk(pixClock), diff --git a/vgashiftout.sv b/vgashiftout.sv index ea66db2..4cbcece 100644 --- a/vgashiftout.sv +++ b/vgashiftout.sv @@ -23,11 +23,16 @@ module vgaShiftOut ( reg [7:0] inReg; reg [7:0] outReg; + // load data into first stage register on rising edge of pixel clock + // if nLoad1 is asserted always @(posedge clk or negedge nReset) begin if(!nReset) inReg <= 0; else if(!nLoad1) inReg <= parIn; end + // load data into second stage register on falling edge of pixel clock + // if nLoad2 is asserted, otherwise if shiftEn is asserted, then shift + // video data out. Shift in 0 to fill empty registers always @(negedge clk or negedge nReset) begin if(!nReset) outReg <= 0; else begin @@ -45,60 +50,8 @@ module vgaShiftOut ( end end + // high-order bit of the shift register (second stage) is the serial output assign out = outReg[7]; endmodule -// module vgaShiftOut ( -// input wire nReset, -// input wire clk, -// input wire vidActive, -// input logic [2:0] seq, -// input logic [7:0] parIn, -// output wire out -// ); -// /* Shift register functioning similar to a 74597, with 8-bit input latch -// * and 8-bit PISO shift register output stage. -// * In sequence 0 new data is loaded from VRAM into the input stage, and in -// * sequence 1 the input stage is copied to the output stage to be shifted. -// */ -// reg [7:0] inReg; -// reg [7:0] outReg; - -// // to meet VRAM timing requirements, data from VRAM has to be clocked into -// // our input register on the rising edge of the pixel clock -// always @(posedge clk or negedge nReset) begin -// if(nReset == 0) begin -// inReg <= 0; -// end else begin -// if(seq == 0) begin -// inReg <= parIn; -// end -// end -// end - -// // pixels are shifted out on the falling edge of the pixel clock -// always @(negedge clk or negedge nReset) begin -// if(nReset == 1'b0) begin -// //inReg <= 0; -// outReg <= 0; -// end else begin -// if(vidActive == 1'b1) begin -// if(seq == 0) begin -// outReg <= inReg; -// end else begin -// outReg[7] <= outReg[6]; -// outReg[6] <= outReg[5]; -// outReg[5] <= outReg[4]; -// outReg[4] <= outReg[3]; -// outReg[3] <= outReg[2]; -// outReg[2] <= outReg[1]; -// outReg[1] <= outReg[0]; -// outReg[0] <= 1'b0; -// end -// end -// end -// end -// assign out = outReg[7]; -// endmodule - `endif \ No newline at end of file