diff --git a/rev3.sv b/rev3.sv new file mode 100644 index 0000000..1d7e836 --- /dev/null +++ b/rev3.sv @@ -0,0 +1,230 @@ +/****************************************************************************** + * SE-VGA + * Top-level module + * techav + * 2021-10-16 + ****************************************************************************** + * Trying again again again + *****************************************************************************/ + +module sevga ( + input wire nReset, // System reset signal + input wire pixClk, // 65MHz pixel clock + output reg nhSync, // HSync signal + output reg nvSync, // VSync signal + output reg vidOut, // 1-bit Monochrome video signal + + output logic [14:0] vramAddr, // VRAM Address bus + inout logic [7:0] vramData, // VRAM Data bus + output reg nvramOE, // VRAM Read strobe + output reg nvramWE, // VRAM Write strobe + output reg nvramCE0, // VRAM Main chip select signal + output reg nvramCE1, // VRAM Alt chip select signal + + input wire [23:1] cpuAddr, // CPU Address bus + input wire [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 logic [2:0] ramSize // Select installed RAM size +); + +/****************************************************************************** + * Initial Video Signal Timing + * The following functions establish the basic XGA signal timing and + * assert the horizontal and vertical sync signals as appropriate. + * These functions are the minimum required for a signal presence detect test. + *****************************************************************************/ + +// Primary sync counters +logic [10:0] hCount; // 0..1343 +logic [9:0] vCount; // 0..805 +always @(negedge pixClk) begin + if(hCount < 1343) hCount <= hCount + 1; + else begin + hCount <= 0; + if(vCount <= 805) vCount <= vCount + 1; + else vCount <= 0; + end +end + +// Horizontal sync +always @(negedge pixClk) begin + if(hCount == 0) nhSyncR <= 1; + else if(hCount == 1052) nhSync <= 0; + else if(hCount == 1186) nhSync <= 1; +end + +// Vertical sync +always @(negedge pixClk) begin + if(vCount == 0) nvSync <= 1; + else if(vCount == 729) nvSync <= 0; + else if(vCount == 734) nvSync <= 0; +end + +/****************************************************************************** + * Useful signals + * Here we break out a few useful signals, derived from the timing above, that + * will help us elsewhere. + *****************************************************************************/ + +// Horizontal active +reg hActive; +always @(negedge pixClk) begin + if(hCount == 0) hActive <= 1; + else if(hCount == 1023) hActive <= 0; + else if(hCount == 1343) hActive <= 1; +end + +// Vertical active +reg vActive; +always @(negedge pixClk) begin + if(vCount == 0) vActive <= 1; + else if(vCount == 683) vActive <= 0; + else if(vCount == 805) vActive <= 1; +end + +// Horizontal fetch active +// asserted just before active video to enable video data pre-fetch +reg fhActive; +always @(negedge pixClk) begin + if(hCount == 0) fhActive <= 1; + else if(hCount == 1022) fhActive <= 0; + else if(hCount == 1342) fhActive <= 1; +end + +// Vertical fetch active +// +reg fvActive; +always @(negedge pixClk) begin + if(vCount == 0) fvActive <= 1; + else if(vCount == 684) fvActive <= 0; + if(vCount == 805) fvActive <= 1; +end + +// combined active signals +wire vidActive = hActive & vActive; +wire fetchActive = fhActive & fvActive; + +/****************************************************************************** + * VRAM State Machine + * Coordinates VRAM load/store actions + *****************************************************************************/ + +// rising edge signals: nvramWE, nvramOE, nvramCE[1:0] +// falling edge signals: vramAddr, vramData + +// VRAM read signal +always @(posedge pixClk) begin nvramOE <= ~(hCount == 7); end + +// VRAM write signal +always @(posedge pixClk) begin + if(hCount[3:1] == 0) nvramWEr <= 1; + else if(hCount[3:1] == 1) nvramWE <= 0; + else if(hCount[3:1] == 6) nvramWE <= 1; +end + +// VRAM data/address busses +always @(negedge pixClk) begin + if(hCount[0] && !hCount[1]) begin + case(hCount[3:2]) + 3: begin + // start read cycle + vramData <= 8'hZ; + vramAddr[14:6] <= vCount[9:1]; + vramAddr[5:0] <= hCount[9:4]; + end + default: begin + // write slots + vramAddr[14:1] <= cpuAddr[14:1] - 14'h1380; + if(!ncpuUDSr && !cpuLDSsrv) begin + vramAddr[0] <= 0; + //cpuLDSsrv <= 1; + vramData <= cpuData[15:8]; + end else if(!ncpuLDSr && !cpuLDSsrv) begin + vramAddr[0] <= 1; + //cpuLDSsrv <= 1; + vramData <= cpuData[7:0]; + end + end + endcase + end +end + +// VRAM chip enable signals +always @(posedge pixClk) begin + if(!hCount[0]) begin + if(hCount[3:1] == 7) begin + // read cycle + if(fetchActive) begin + nvramCE0 <= ~vidBufSel; + nvramCE1 <= vidBufSel; + end else begin + nvramCE0 <= 1; + nvramCE1 <= 1; + end + end else if(hCount[1]) begin + // write cycle + if(!ncpuUDSr && !cpuUDSsrv) begin + nvramCE0 <= ~vramAddr[15]; + nvramCE1 <= vramAddr[15]; + cpuUDSsrv <= 1; + end else if(!ncpuLDSr && !cpuLDSsrv) begin + nvramCE0 <= ~vramAddr[15]; + nvramCE1 <= vramAddr[15]; + cpuLDSsrv <= 1; + end else begin + nvramCE0 <= 1; + nvramCE1 <= 1; + end + end + end else begin + nvramCE0 <= 1; + nvramCE1 <= 1; + end + // reset the upper/lower serve signals when cycle ended by CPU + if(ncpuLDS) cpuLDSsrv <= 0; + if(ncpuUDS) cpuUDSsrv <= 0; +end + +// Video data shift register & output +reg [7:0] vidShiftr; +always @(negedge pixClk) begin + if(hCount[3:0] == 4'hF) vidShiftr <= ~vramData; + else if(hCount[0]) begin + vidShiftr[7:1] <= vidShiftr[6:0]; + vidShiftr[0] <= 0; + end +end +always_comb begin + if(vidActive) vidOut = vidShiftr[7]; + else vidOut <= 0; +end + +/****************************************************************************** + * CPU Bus Snooping + * Watches the CPU bus and aligns its operations with the pixel clock + *****************************************************************************/ +reg ncpuUDSr, ncpuLDSr; +always @(negedge pixClk) begin + // this condition evaluates true when cpu is writing to video buffer + if(!ncpuAS && !cpuRnW + && !cpuAddr[23] && !cpuAddr[22] + && !(cpuAddr[21] ^ ramSize[2]) + && !(cpuAddr[20] ^ ramSize[1]) + && !(cpuAddr[19] ^ ramSize[0]) + && cpuAddr[18] && cpuAddr[17] + && cpuAddr[16] + && ((cpuAddr[14:1] >= 14'h1380) + && (cpuAddr[14:1] < 14'h3E40))) + begin + if(!ncpuUDS) ncpuUDSr <= 0; + else ncpuUDSr <= 1; + if(!ncpuLDS) ncpuLDSr <= 0; + else ncpuLDSr <= 1; + end else begin + ncpuUDSr <= 1; + ncpuLDSr <= 1; + end +end