aboutsummaryrefslogtreecommitdiff
path: root/models/vga_display.v
diff options
context:
space:
mode:
Diffstat (limited to 'models/vga_display.v')
-rw-r--r--models/vga_display.v203
1 files changed, 203 insertions, 0 deletions
diff --git a/models/vga_display.v b/models/vga_display.v
new file mode 100644
index 0000000..bb683e2
--- /dev/null
+++ b/models/vga_display.v
@@ -0,0 +1,203 @@
+`default_nettype none
+`timescale 1ns/1ns
+
+`include "messages.vh"
+
+`ifndef SIMULATION
+ `error_SIMULATION_not_defined
+; /* Cause syntax error */
+`endif
+
+module VGA_640_480_60Hz(
+ input wire horizontal_sync,
+ input wire vertical_sync,
+
+ input wire [2:0] red,
+ input wire [2:0] green,
+ input wire [2:0] blue,
+
+ output reg [9:0] image_writes
+ );
+ initial
+ image_writes <= 0;
+
+ parameter FRONT_PORCH = 0;
+ parameter SYNC_PULSE = 1;
+ parameter BACK_PORCH = 2;
+ parameter ACTIVE_VIDEO = 3;
+ parameter UNKNOWN_STATE = 4;
+
+ integer h_state;
+ integer v_state;
+ initial begin
+ h_state <= UNKNOWN_STATE;
+ v_state <= UNKNOWN_STATE;
+ end
+
+ parameter H_SYNC_POLARITY = 1'b0;
+ parameter H_FRONT_PORCH_LENGTH = 16;
+ parameter H_SYNC_PULSE_LENGTH = 96;
+ parameter H_BACK_PORCH_LENGTH = 48;
+ parameter H_ACTIVE_VIDEO_LENGTH = 640;
+
+ parameter V_SYNC_POLARITY = 1'b1;
+ parameter V_FRONT_PORCH_LENGTH = 10;
+ parameter V_SYNC_PULSE_LENGTH = 2;
+ parameter V_BACK_PORCH_LENGTH = 33;
+ parameter V_ACTIVE_VIDEO_LENGTH = 480;
+
+ reg [8:0] picture
+ [V_ACTIVE_VIDEO_LENGTH - 1 : 0]
+ [H_ACTIVE_VIDEO_LENGTH - 1 : 0];
+
+ integer h_counter, v_counter;
+
+ reg error;
+
+ wire unexpected_h_sync_pulse;
+ wire missing_h_sync_pulse;
+ assign unexpected_h_sync_pulse = horizontal_sync == H_SYNC_POLARITY &&
+ h_state != SYNC_PULSE;
+ assign missing_h_sync_pulse = horizontal_sync != H_SYNC_POLARITY &&
+ h_state == SYNC_PULSE;
+
+ wire unexpected_v_sync_pulse;
+ wire missing_v_sync_pulse;
+ assign unexpected_v_sync_pulse = vertical_sync == V_SYNC_POLARITY &&
+ v_state != SYNC_PULSE;
+ assign missing_v_sync_pulse = vertical_sync != V_SYNC_POLARITY &&
+ v_state == SYNC_PULSE;
+
+ wire new_line;
+ assign new_line = h_state == BACK_PORCH &&
+ h_counter + 1 == H_BACK_PORCH_LENGTH;
+
+ wire new_screen;
+ assign new_screen = v_state == BACK_PORCH &&
+ v_counter + 1 == V_BACK_PORCH_LENGTH && new_line;
+
+ always #40 begin
+ /* First, horizontal stuff */
+ if (unexpected_h_sync_pulse) begin
+ h_state <= SYNC_PULSE;
+ h_counter <= 1;
+
+ if (h_state != UNKNOWN_STATE) begin
+ `MSG(({"VGA: error: unexpected horizontal sync pulse signal ",
+ "(tick %0d; state %0d)"}, h_counter, h_state));
+ end
+ end else if (missing_h_sync_pulse) begin
+ h_state <= BACK_PORCH;
+ h_counter <= 1;
+
+ `MSG(({"VGA: error: missing expected horizontal sync pulse signal ",
+ "(tick %0d of sync pulse)"}, h_counter));
+ end else begin
+ case (h_state)
+ FRONT_PORCH : begin
+ if (h_counter + 1 != H_FRONT_PORCH_LENGTH) begin
+ h_counter <= h_counter + 1;
+ end else begin
+ h_state <= SYNC_PULSE;
+ h_counter <= 0;
+ end
+ end
+ SYNC_PULSE : begin
+ if (h_counter + 1 != H_SYNC_PULSE_LENGTH) begin
+ h_counter <= h_counter + 1;
+ end else begin
+ h_state <= BACK_PORCH;
+ h_counter <= 0;
+ end
+ end
+ BACK_PORCH : begin
+ if (h_counter + 1 != H_BACK_PORCH_LENGTH) begin
+ h_counter <= h_counter + 1;
+ end else begin
+ h_state <= ACTIVE_VIDEO;
+ h_counter <= 0;
+ end
+ end
+ ACTIVE_VIDEO : begin
+ if (v_state == ACTIVE_VIDEO) begin
+ picture[v_counter][h_counter] <= {red, green, blue};
+ end
+
+ if (h_counter + 1 != H_ACTIVE_VIDEO_LENGTH) begin
+ h_counter <= h_counter + 1;
+ end else begin
+ h_state <= FRONT_PORCH;
+ h_counter <= 0;
+ end
+ end // case: ACTIVE_VIDEO
+ endcase // case (h_state)
+ end // else: !if(missing_h_sync_pulse)
+
+
+ /* Vertical stuff is almost entirely the same as horizontal */
+ if (new_line) begin
+ if (unexpected_v_sync_pulse) begin
+ v_state <= SYNC_PULSE;
+ v_counter <= 1;
+
+ if (v_state != UNKNOWN_STATE) begin
+ `MSG(({"VGA: error: unexpected vertical sync pulse signal ",
+ "(line %0d; state %0d)"}, v_counter, v_state));
+ end
+ end else if (missing_v_sync_pulse) begin
+ v_state <= BACK_PORCH;
+ v_counter <= 1;
+
+ `MSG(({"VGA: error: missing expected vertical sync pulse signal ",
+ "(line %0d of sync pulse)"}, v_counter));
+ end else begin
+ case (v_state)
+ FRONT_PORCH : begin
+ if (v_counter + 1 != V_FRONT_PORCH_LENGTH) begin
+ v_counter <= v_counter + 1;
+ end else begin
+ v_state <= SYNC_PULSE;
+ v_counter <= 0;
+ end
+ end
+ SYNC_PULSE : begin
+ if (v_counter + 1 != V_SYNC_PULSE_LENGTH) begin
+ v_counter <= v_counter + 1;
+ end else begin
+ v_state <= BACK_PORCH;
+ v_counter <= 0;
+ end
+ end
+ BACK_PORCH : begin
+ if (v_counter + 1 != V_BACK_PORCH_LENGTH) begin
+ v_counter <= v_counter + 1;
+ end else begin
+ v_state <= ACTIVE_VIDEO;
+ v_counter <= 0;
+ end
+ end
+ ACTIVE_VIDEO : begin
+ if (v_counter + 1 != V_ACTIVE_VIDEO_LENGTH) begin
+ v_counter <= v_counter + 1;
+ end else begin
+ v_state <= FRONT_PORCH;
+ v_counter <= 0;
+
+ if (!error) begin
+ $writememb("VGAdump.mem", picture);
+ `DBG(("VGA: written VGAdump.mem"));
+ image_writes <= image_writes + 1;
+ end
+ end // else: !if(v_counter + 1 != V_ACTIVE_VIDEO_LENGTH)
+ end // case: ACTIVE_VIDEO
+ endcase // case (v_state)
+ end // else: !if(missing_v_sync_pulse)
+ end // if (new_line)
+
+ if (unexpected_h_sync_pulse || unexpected_h_sync_pulse ||
+ ((unexpected_v_sync_pulse || missing_v_sync_pulse) && new_line))
+ error <= 1;
+ else if (new_screen)
+ error <= 0;
+ end // always #40
+endmodule // VGA_640_480_60Hz