aboutsummaryrefslogtreecommitdiff
`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 similar to horizontal */
      if (h_state == ACTIVE_VIDEO) begin
	 if (unexpected_v_sync_pulse) begin
	    v_state <= SYNC_PULSE;
	    v_counter <= 0;

	    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 <= 0;

	    `MSG(({"VGA: error: missing expected vertical sync pulse signal ",
		   "(line %0d of sync pulse)"}, v_counter));
	 end
      end // if (h_state == ACTIVE_VIDEO)

      if (new_line) 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 // 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