aboutsummaryrefslogtreecommitdiff
path: root/models/vga_display.v
blob: 6e30248e7f2d2cc1cd4b7e3de9d766b241abfef0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
`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