Fixed video, kbd and buzzer
This commit is contained in:
+201
@@ -0,0 +1,201 @@
|
||||
//============================================================================
|
||||
// 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 MHz
|
||||
|
||||
output wire [3:0] VGA_R, // Output VGA R component
|
||||
output wire [3:0] VGA_G, // Output VGA G component
|
||||
output wire [3:0] VGA_B, // Output VGA B component
|
||||
output reg VGA_HS, // Output VGA horizontal sync
|
||||
output reg VGA_VS, // Output VGA vertical sync
|
||||
output wire vs_nintr, // Vertical retrace interrupt
|
||||
|
||||
output wire [12:0] vram_address,// Address request to the video RAM
|
||||
input wire [7:0] vram_data, // Data read from the video RAM
|
||||
|
||||
input wire [2:0] border // Border color index value
|
||||
);
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// VGA 640x480 Sync pulses generator
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
reg [9:0] vga_hc; // Horizontal counter
|
||||
reg [9:0] vga_vc; // Vertical counter
|
||||
reg [4:0] frame; // Frame counter, used for the flash attribute
|
||||
|
||||
always @(posedge clk_pix)
|
||||
begin
|
||||
vga_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: begin
|
||||
VGA_HS <= 0;
|
||||
vga_hc <= 0;
|
||||
vga_vc <= vga_vc + 10'b1;
|
||||
end
|
||||
endcase
|
||||
//---------------------------------------------------------------
|
||||
// Vertical sync and display end timings
|
||||
//---------------------------------------------------------------
|
||||
case (vga_vc)
|
||||
2: VGA_VS <= 1;
|
||||
525: begin
|
||||
VGA_VS <= 0;
|
||||
vga_vc <= 0;
|
||||
frame <= frame + 5'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// Generate interrupt at around the time of the vertical retrace start
|
||||
assign 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 register
|
||||
reg [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 register
|
||||
reg [7:0] attr; // Current attribute data register
|
||||
|
||||
wire [4:0] pix_x; // Column 0-31
|
||||
wire [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+16
|
||||
assign pix_x = xd[8:4]; // Effectively divide by 16
|
||||
wire [9:0] yd = vga_vc-10'd83; // Lines are (also) doubled vertically
|
||||
assign pix_y = yd[8:1]; // Effectively divide by 2
|
||||
|
||||
always @(posedge clk_pix)
|
||||
begin
|
||||
case (vga_hc[3:0])
|
||||
// Format the address into the bitmap which is a swizzle of coordinate parts
|
||||
10: vram_address <= {pix_y[7:6], pix_y[2:0], pix_y[5:3], pix_x};
|
||||
12: begin
|
||||
bits_prefetch <= vram_data;
|
||||
// Format the address into the attribute map
|
||||
vram_address <= {3'b110, pix_y[7:3], pix_x};
|
||||
end
|
||||
14: attr_prefetch <= vram_data;
|
||||
// Last tick before a new character: load working bitmap and attribute registers
|
||||
15: begin
|
||||
attr <= attr_prefetch;
|
||||
bits <= bits_prefetch;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Pixel data generator
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
wire [2:0] ink; // INK color (index into the palette)
|
||||
wire [2:0] paper; // PAPER color
|
||||
wire bright; // BRIGHT attribute bit
|
||||
wire flash; // FLASH attribute bit
|
||||
wire pixbit; // Current pixel to render
|
||||
wire 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_comb
|
||||
begin
|
||||
case (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];
|
||||
endcase
|
||||
end
|
||||
|
||||
assign 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 bit
|
||||
assign 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_comb
|
||||
begin
|
||||
case (cindex[3:0])
|
||||
// Normal color
|
||||
0: pix_rgb = 12'h000; // BLACK
|
||||
1: pix_rgb = 12'h00D; // BLUE
|
||||
2: pix_rgb = 12'hD00; // RED
|
||||
3: pix_rgb = 12'hD0D; // MAGENTA
|
||||
4: pix_rgb = 12'h0D0; // GREEN
|
||||
5: pix_rgb = 12'h0DD; // CYAN
|
||||
6: pix_rgb = 12'hDD0; // YELLOW
|
||||
7: pix_rgb = 12'hDDD; // WHITE
|
||||
// "Bright" bit is set
|
||||
8: pix_rgb = 12'h000; // BLACK remains black
|
||||
9: 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;
|
||||
endcase
|
||||
end
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// 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
|
||||
Reference in New Issue
Block a user