URL
https://opencores.org/ocsvn/a-z80/a-z80/trunk
Subversion Repositories a-z80
[/] [a-z80/] [trunk/] [host/] [zxspectrum_de1/] [ula/] [video.sv] - Rev 8
Go to most recent revision | Compare with Previous | Blame | View Log
//============================================================================// Implementation of the Sinclair ZX Spectrum ULA//// This module contains video support.//// Note: There is no reset signal in this VGA design since all relevant// counters will reset themselves within one display frame as the// pixel clock keeps ticking.//// Copyright (C) 2014-2016 Goran Devic//// This program is free software; you can redistribute it and/or modify it// under the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 of the License, or (at your option)// any later version.//// This program is distributed in the hope that it will be useful, but WITHOUT// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for// more details.//// You should have received a copy of the GNU General Public License along// with this program; if not, write to the Free Software Foundation, Inc.,// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.//============================================================================module video(input wire clk_pix, // Input VGA pixel clock of 25.175 MHzoutput wire [3:0] VGA_R, // Output VGA R componentoutput wire [3:0] VGA_G, // Output VGA G componentoutput wire [3:0] VGA_B, // Output VGA B componentoutput reg VGA_HS, // Output VGA horizontal syncoutput reg VGA_VS, // Output VGA vertical syncoutput wire vs_nintr, // Vertical retrace interruptoutput wire [12:0] vram_address,// Address request to the video RAMinput wire [7:0] vram_data, // Data read from the video RAMinput wire [2:0] border // Border color index value);//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// VGA 640x480 Sync pulses generator//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~reg [9:0] vga_hc; // Horizontal counterreg [9:0] vga_vc; // Vertical counterreg [4:0] frame; // Frame counter, used for the flash attributealways @(posedge clk_pix)beginvga_hc <= vga_hc + 10'b1; // With each pixel clock, advance the horizontal counter//---------------------------------------------------------------// Horizontal sync and line end timings//---------------------------------------------------------------case (vga_hc)96: VGA_HS <= 1;800: beginVGA_HS <= 0;vga_hc <= 0;vga_vc <= vga_vc + 10'b1;endendcase//---------------------------------------------------------------// Vertical sync and display end timings//---------------------------------------------------------------case (vga_vc)2: VGA_VS <= 1;525: beginVGA_VS <= 0;vga_vc <= 0;frame <= frame + 5'b1;endendcaseend// Generate interrupt at around the time of the vertical retrace startassign vs_nintr = (vga_vc=='0 && vga_hc[9:7]=='0)? '0 : '1;//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// VGA active display area 640x480//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~wire disp_enable;assign disp_enable = vga_hc>=144 && vga_hc<784 && vga_vc>=35 && vga_vc<515;//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// Fetch screen data from RAM based on the current video counters// Spectrum resolution of 256x192 is line-doubled to 512x384 sub-frame//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~wire screen_en;assign screen_en = vga_hc>=208 && vga_hc<720 && vga_vc>=83 && vga_vc<467;reg [7:0] bits_prefetch; // Line bitmap data prefetch registerreg [7:0] attr_prefetch; // Attribute data prefetch register// At the first clock of each new character, prefetch values are latched into these:reg [7:0] bits; // Current line bitmap data registerreg [7:0] attr; // Current attribute data registerwire [4:0] pix_x; // Column 0-31wire [7:0] pix_y; // Active display pixel Y coordinate// We use 16 clocks for 1 byte of display; also prefetch 1 byte (+16)wire [9:0] xd = vga_hc-10'd192; // =vga_hc-208+16assign pix_x = xd[8:4]; // Effectively divide by 16wire [9:0] yd = vga_vc-10'd83; // Lines are (also) doubled verticallyassign pix_y = yd[8:1]; // Effectively divide by 2always @(posedge clk_pix)begincase (vga_hc[3:0])// Format the address into the bitmap which is a swizzle of coordinate parts10: vram_address <= {pix_y[7:6], pix_y[2:0], pix_y[5:3], pix_x};12: beginbits_prefetch <= vram_data;// Format the address into the attribute mapvram_address <= {3'b110, pix_y[7:3], pix_x};end14: attr_prefetch <= vram_data;// Last tick before a new character: load working bitmap and attribute registers15: beginattr <= attr_prefetch;bits <= bits_prefetch;endendcaseend//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// Pixel data generator//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~wire [2:0] ink; // INK color (index into the palette)wire [2:0] paper; // PAPER colorwire bright; // BRIGHT attribute bitwire flash; // FLASH attribute bitwire pixbit; // Current pixel to renderwire inverted; // Are the pixel's attributes inverted?// Output a pixel bit based on the VGA horizontal counter. This could have been// a shift register but a mux works as well since we are writing out each pixel// twice (required by this VGA clock rate)always @(*) // always_combbegincase (vga_hc[3:1])0: pixbit = bits[7];1: pixbit = bits[6];2: pixbit = bits[5];3: pixbit = bits[4];4: pixbit = bits[3];5: pixbit = bits[2];6: pixbit = bits[1];7: pixbit = bits[0];endcaseendassign flash = attr[7];assign bright = attr[6];assign inverted = flash & frame[4];assign ink = inverted? attr[5:3] : attr[2:0];assign paper = inverted? attr[2:0] : attr[5:3];// The final color index depends on where we are (active display area, border) and// whether we are rendering INK or PAPER color, including the brightness bitassign cindex = screen_en? pixbit? {bright,ink} : {bright,paper} : {1'b0,border[2:0]};//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// Color lookup table//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~wire [3:0] cindex;wire [11:0] pix_rgb;always @(*) // always_combbegincase (cindex[3:0])// Normal color0: pix_rgb = 12'h000; // BLACK1: pix_rgb = 12'h00D; // BLUE2: pix_rgb = 12'hD00; // RED3: pix_rgb = 12'hD0D; // MAGENTA4: pix_rgb = 12'h0D0; // GREEN5: pix_rgb = 12'h0DD; // CYAN6: pix_rgb = 12'hDD0; // YELLOW7: pix_rgb = 12'hDDD; // WHITE// "Bright" bit is set8: pix_rgb = 12'h000; // BLACK remains black9: pix_rgb = 12'h00F;10: pix_rgb = 12'hF00;11: pix_rgb = 12'hF0F;12: pix_rgb = 12'h0F0;13: pix_rgb = 12'h0FF;14: pix_rgb = 12'hFF0;15: pix_rgb = 12'hFFF;endcaseend//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// VGA RGB output drivers//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~assign VGA_R[3:0] = disp_enable? pix_rgb[11:8] : '0;assign VGA_G[3:0] = disp_enable? pix_rgb[7:4] : '0;assign VGA_B[3:0] = disp_enable? pix_rgb[3:0] : '0;endmodule
Go to most recent revision | Compare with Previous | Blame | View Log
