1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-11-22 14:33:51 +00:00

verilog-vga

This commit is contained in:
Steven Hugg 2019-01-27 14:47:03 -05:00
parent 3ecaa57b9a
commit e44a0734dd
6 changed files with 228 additions and 10 deletions

View File

@ -91,6 +91,8 @@ TODO:
- Safari: scope doesn't show while CRT in use - Safari: scope doesn't show while CRT in use
- recording video indicator - recording video indicator
- verilog: support VGA/multisync monitor? - verilog: support VGA/multisync monitor?
- stego shareable images (http://pico-8.wikia.com/wiki/P8PNGFileFormat)
- https://makecode.com/language?
WEB WORKER FORMAT WEB WORKER FORMAT

View File

@ -0,0 +1,69 @@
`ifndef HVSYNC_GENERATOR_H
`define HVSYNC_GENERATOR_H
/*
Video sync generator, used to drive a simulated CRT.
To use:
- Wire the hsync and vsync signals to top level outputs
- Add a 3-bit (or more) "rgb" output to the top level
*/
module hvsync_generator(clk, reset, hsync, vsync, display_on, hpos, vpos);
input clk;
input reset;
output reg hsync, vsync;
output display_on;
output reg [8:0] hpos;
output reg [8:0] vpos;
// declarations for TV-simulator sync parameters
// horizontal constants
parameter H_DISPLAY = 256; // horizontal display width
parameter H_BACK = 23; // horizontal left border (back porch)
parameter H_FRONT = 7; // horizontal right border (front porch)
parameter H_SYNC = 23; // horizontal sync width
// vertical constants
parameter V_DISPLAY = 240; // vertical display height
parameter V_TOP = 5; // vertical top border
parameter V_BOTTOM = 14; // vertical bottom border
parameter V_SYNC = 3; // vertical sync # lines
// derived constants
parameter H_SYNC_START = H_DISPLAY + H_FRONT;
parameter H_SYNC_END = H_DISPLAY + H_FRONT + H_SYNC - 1;
parameter H_MAX = H_DISPLAY + H_BACK + H_FRONT + H_SYNC - 1;
parameter V_SYNC_START = V_DISPLAY + V_BOTTOM;
parameter V_SYNC_END = V_DISPLAY + V_BOTTOM + V_SYNC - 1;
parameter V_MAX = V_DISPLAY + V_TOP + V_BOTTOM + V_SYNC - 1;
wire hmaxxed = (hpos == H_MAX) || reset; // set when hpos is maximum
wire vmaxxed = (vpos == V_MAX) || reset; // set when vpos is maximum
// horizontal position counter
always @(posedge clk)
begin
hsync <= (hpos>=H_SYNC_START && hpos<=H_SYNC_END);
if(hmaxxed)
hpos <= 0;
else
hpos <= hpos + 1;
end
// vertical position counter
always @(posedge clk)
begin
vsync <= (vpos>=V_SYNC_START && vpos<=V_SYNC_END);
if(hmaxxed)
if (vmaxxed)
vpos <= 0;
else
vpos <= vpos + 1;
end
// display_on is set when beam is in "safe" visible frame
assign display_on = (hpos<H_DISPLAY) && (vpos<V_DISPLAY);
endmodule
`endif

View File

@ -0,0 +1,31 @@
`ifndef LFSR_V
`define LFSR_V
/*
Configurable Linear Feedback Shift Register.
*/
module LFSR(clk, reset, enable, lfsr);
parameter TAPS = 8'b11101; // bitmask for taps
parameter INVERT = 0; // invert feedback bit?
localparam NBITS = $size(TAPS); // bit width (derived from TAPS)
input clk, reset;
input enable; // only perform shift when enable=1
output reg [NBITS-1:0] lfsr; // shift register
wire feedback = lfsr[NBITS-1] ^ INVERT;
always @(posedge clk)
begin
if (reset)
lfsr <= {lfsr[NBITS-2:0], 1'b1}; // reset loads with all 1s
else if (enable)
lfsr <= {lfsr[NBITS-2:0], 1'b0} ^ (feedback ? TAPS : 0);
end
endmodule
`endif

80
presets/verilog-vga/ram.v Normal file
View File

@ -0,0 +1,80 @@
`ifndef RAM_H
`define RAM_H
/*
RAM_sync - Synchronous RAM module.
RAM_async - Asynchronous RAM module.
RAM_async_tristate - Async RAM module with bidirectional data bus.
Module parameters:
A - number of address bits (default = 10)
D - number of data bits (default = 8)
*/
module RAM_sync(clk, addr, din, dout, we);
parameter A = 10; // # of address bits
parameter D = 8; // # of data bits
input clk; // clock
input [A-1:0] addr; // address
input [D-1:0] din; // data input
output [D-1:0] dout; // data output
input we; // write enable
reg [D-1:0] mem [0:(1<<A)-1]; // (1<<A)xD bit memory
always @(posedge clk) begin
if (we) // if write enabled
mem[addr] <= din; // write memory from din
dout <= mem[addr]; // read memory to dout (sync)
end
endmodule
module RAM_async(clk, addr, din, dout, we);
parameter A = 10; // # of address bits
parameter D = 8; // # of data bits
input clk; // clock
input [A-1:0] addr; // address
input [D-1:0] din; // data input
output [D-1:0] dout; // data output
input we; // write enable
reg [D-1:0] mem [0:(1<<A)-1]; // (1<<A)xD bit memory
always @(posedge clk) begin
if (we) // if write enabled
mem[addr] <= din; // write memory from din
end
assign dout = mem[addr]; // read memory to dout (async)
endmodule
module RAM_async_tristate(clk, addr, data, we);
parameter A = 10; // # of address bits
parameter D = 8; // # of data bits
input clk; // clock
input [A-1:0] addr; // address
inout [D-1:0] data; // data in/out
input we; // write enable
reg [D-1:0] mem [0:(1<<A)-1]; // (1<<A)xD bit memory
always @(posedge clk) begin
if (we) // if write enabled
mem[addr] <= data; // write memory from data
end
assign data = !we ? mem[addr] : {D{1'bz}}; // read memory to data (async)
endmodule
`endif

View File

@ -0,0 +1,32 @@
`include "hvsync_generator.v"
/*
A simple test pattern using the hvsync_generator module.
*/
module test_hvsync_top(clk, reset, hsync, vsync, rgb);
input clk, reset;
output hsync, vsync;
output [2:0] rgb;
wire display_on;
wire [8:0] hpos;
wire [8:0] vpos;
hvsync_generator hvsync_gen(
.clk(clk),
.reset(0),
.hsync(hsync),
.vsync(vsync),
.display_on(display_on),
.hpos(hpos),
.vpos(vpos)
);
wire r = display_on && (((hpos&7)==0) || ((vpos&7)==0));
wire g = display_on && vpos[4];
wire b = display_on && hpos[4];
assign rgb = {b,g,r};
endmodule

View File

@ -295,7 +295,7 @@ var VerilogPlatform = function(mainElement, options) {
ctx.fillText(txt, x, y); ctx.fillText(txt, x, y);
ctx.shadowOffsetX = 0; ctx.shadowOffsetX = 0;
} }
// inner Platform class // inner Platform class
class _VerilogPlatform extends BasePlatform implements WaveformProvider { class _VerilogPlatform extends BasePlatform implements WaveformProvider {
@ -308,6 +308,13 @@ var VerilogPlatform = function(mainElement, options) {
getPresets() { return VERILOG_PRESETS; } getPresets() { return VERILOG_PRESETS; }
setVideoParams(width:number, height:number, clock:number) {
videoWidth = width;
videoHeight = height;
cyclesPerFrame = clock;
maxVideoLines = height+40;
}
start() { start() {
video = new RasterVideo(mainElement,videoWidth,videoHeight,{overscan:true}); video = new RasterVideo(mainElement,videoWidth,videoHeight,{overscan:true});
video.create(); video.create();
@ -751,24 +758,21 @@ var VerilogPlatform = function(mainElement, options) {
//////////////// ////////////////
var VERILOG_SIM_PRESETS = [ var VERILOG_VGA_PRESETS = [
{id:'clock_divider.v', name:'Clock Divider'},
{id:'lfsr.v', name:'Linear Feedback Shift Register'},
{id:'hvsync_generator.v', name:'Video Sync Generator'}, {id:'hvsync_generator.v', name:'Video Sync Generator'},
{id:'test_hvsync.v', name:'Test Pattern'}, {id:'test_hvsync.v', name:'Test Pattern'},
{id:'starfield.v', name:'Scrolling Starfield'},
{id:'chardisplay.v', name:'RAM Text Display'},
{id:'sound_generator.v', name:'Sound Generator'},
]; ];
var VerilogSimulatorPlatform = function(mainElement, options) { var VerilogVGAPlatform = function(mainElement, options) {
this.__proto__ = new (VerilogPlatform as any)(mainElement, options); this.__proto__ = new (VerilogPlatform as any)(mainElement, options);
this.getPresets = function() { return VERILOG_SIM_PRESETS; } this.getPresets = function() { return VERILOG_VGA_PRESETS; }
this.setVideoParams(800-64, 520, 25000000);
} }
//////////////// ////////////////
PLATFORMS['verilog'] = VerilogPlatform; PLATFORMS['verilog'] = VerilogPlatform;
PLATFORMS['verilog.sim'] = VerilogSimulatorPlatform; PLATFORMS['verilog-vga'] = VerilogVGAPlatform;