1 | `default_nettype none //disable implicit definitions by Verilog
|
2 |
|
3 | module top( //top module and signals wired to FPGA pins
|
4 | CLK100MHz,
|
5 | vga_r,
|
6 | vga_g,
|
7 | vga_b,
|
8 | vga_hs,
|
9 | vga_vs,
|
10 | ps2_clk,
|
11 | ps2_data
|
12 | );
|
13 |
|
14 | input CLK100MHz; // Oscillator input 100Mhz
|
15 | output [2:0] vga_r; // VGA Red 3 bit
|
16 | output [2:0] vga_g; // VGA Green 3 bit
|
17 | output [2:0] vga_b; // VGA Blue 3 bit
|
18 | output vga_hs; // H-sync pulse
|
19 | output vga_vs; // V-sync pulse
|
20 | input ps2_clk; // PS2 clock
|
21 | input ps2_data; // PS2 data
|
22 |
|
23 |
|
24 | parameter h_pulse = 96; //H-SYNC pulse width 96 * 40 ns (25 Mhz) = 3.84 uS
|
25 | parameter h_bp = 48; //H-BP back porch pulse width
|
26 | parameter h_pixels = 640; //H-PIX Number of pixels horisontally
|
27 | parameter h_fp = 16; //H-FP front porch pulse width
|
28 | parameter h_pol = 1'b0; //H-SYNC polarity
|
29 | parameter h_frame = 800; //800 = 96 (H-SYNC) + 48 (H-BP) + 640 (H-PIX) + 16 (H-FP)
|
30 | parameter v_pulse = 2; //V-SYNC pulse width
|
31 | parameter v_bp = 33; //V-BP back porch pulse width
|
32 | parameter v_pixels = 480; //V-PIX Number of pixels vertically
|
33 | parameter v_fp = 10; //V-FP front porch pulse width
|
34 | parameter v_pol = 1'b1; //V-SYNC polarity
|
35 | parameter v_frame = 525; // 525 = 2 (V-SYNC) + 33 (V-BP) + 480 (V-PIX) + 10 (V-FP)
|
36 |
|
37 | parameter square_size = 10; //size of the square we will move
|
38 | parameter init_x = 320; //initial square position X
|
39 | parameter init_y = 240; //initial square position Y
|
40 |
|
41 | reg [1:0] clk_div; // 2 bit counter
|
42 | wire vga_clk;
|
43 |
|
44 | assign vga_clk = clk_div[1]; // 25Mhz clock = 100Mhz divided by 2-bit counter
|
45 |
|
46 | always @ (posedge CLK100MHz) begin // 2-bt counter ++ on each positive edge of 100Mhz clock
|
47 | clk_div <= clk_div + 2'b1;
|
48 | end
|
49 |
|
50 | reg [2:0] vga_r_r; //VGA color registers R,G,B x 3 bit
|
51 | reg [2:0] vga_g_r;
|
52 | reg [2:0] vga_b_r;
|
53 | reg vga_hs_r; //H-SYNC register
|
54 | reg vga_vs_r; //V-SYNC register
|
55 |
|
56 | assign vga_r = vga_r_r; //assign the output signals for VGA to the VGA registers
|
57 | assign vga_g = vga_g_r;
|
58 | assign vga_b = vga_b_r;
|
59 | assign vga_hs = vga_hs_r;
|
60 | assign vga_vs = vga_vs_r;
|
61 |
|
62 | reg [7:0] timer_t = 8'b0; // 8 bit timer with 0 initialization
|
63 | reg reset = 1;
|
64 | reg [9:0] c_row; //complete frame register row
|
65 | reg [9:0] c_col; //complete frame register colum
|
66 | reg [9:0] c_hor; //visible frame register horisontally
|
67 | reg [9:0] c_ver; //visible frame register vertically
|
68 |
|
69 | reg disp_en; //display enable flag
|
70 |
|
71 | reg [9:0] sq_pos_x; //position of square center X, Y
|
72 | reg [9:0] sq_pos_y;
|
73 |
|
74 | wire [9:0] l_sq_pos_x; //upper left and down right corners of the square
|
75 | wire [9:0] r_sq_pos_x;
|
76 | wire [9:0] u_sq_pos_y;
|
77 | wire [9:0] d_sq_pos_y;
|
78 |
|
79 | assign l_sq_pos_x = sq_pos_x - square_size;
|
80 | assign r_sq_pos_x = sq_pos_x + square_size;
|
81 | assign u_sq_pos_y = sq_pos_y - square_size;
|
82 | assign d_sq_pos_y = sq_pos_y + square_size;
|
83 |
|
84 | reg [3:0] ps2_cntr; // 4-bit PS2 clock counter
|
85 | reg [7:0] ps2_data_reg; // 8-bit PS2 data register
|
86 | reg [7:0] ps2_data_reg_prev; // previous 8-bit PS data register
|
87 | reg [7:0] ps2_data_reg_prev1; // previous previous 8-bit data register
|
88 | reg [10:0] ps2_dat_r; // 11-bit complete PS2 frame register
|
89 |
|
90 | reg [1:0] ps2_clk_buf; // PS2 clock buffer
|
91 | wire ps2_clk_pos; // PS2 positive edge detected signal
|
92 |
|
93 | reg u_arr = 0; //PS2 arrow keys detect flags
|
94 | reg l_arr = 0;
|
95 | reg d_arr = 0;
|
96 | reg r_arr = 0;
|
97 |
|
98 | reg [20:0] arr_timer; // delay between key service
|
99 |
|
100 | reg [19:0] sq_figure [0:19];
|
101 |
|
102 | wire [4:0] sq_fig_x;
|
103 | wire [4:0] sq_fig_y;
|
104 |
|
105 | assign sq_fig_x = c_col - l_sq_pos_x; // our figure's x axis when in square boundary
|
106 | assign sq_fig_y = c_row - u_sq_pos_y; // our figure's y axis when in square boundary
|
107 |
|
108 | assign ps2_clk_pos = (ps2_clk_buf == 2'b01); // edge detector positive edge is when the buffer is '10'
|
109 |
|
110 | always @ (posedge vga_clk) begin //25Mhz clock
|
111 |
|
112 | if(timer_t > 250) begin // generate 10 uS RESET signal
|
113 | reset <= 0;
|
114 | end
|
115 | else begin
|
116 | reset <= 1; //while in reset display is disabled, suare is set to initial position
|
117 | timer_t <= timer_t + 1;
|
118 | disp_en <= 0;
|
119 | sq_pos_x <= init_x;
|
120 | sq_pos_y <= init_y;
|
121 | end
|
122 |
|
123 | if(reset == 1) begin //while RESET is high init counters
|
124 |
|
125 |
|
126 | sq_figure[0][19:0] <= 20'b00000000000000000000;
|
127 | sq_figure[1][19:0] <= 20'b00000001111100000000;
|
128 | sq_figure[2][19:0] <= 20'b00000111111111000000;
|
129 | sq_figure[3][19:0] <= 20'b00011111111111110000;
|
130 | sq_figure[4][19:0] <= 20'b00111111111111111000;
|
131 | sq_figure[5][19:0] <= 20'b00111111111111111000;
|
132 | sq_figure[6][19:0] <= 20'b01111111111111111100;
|
133 | sq_figure[7][19:0] <= 20'b01111111111111111100;
|
134 | sq_figure[8][19:0] <= 20'b11111111111111111110;
|
135 | sq_figure[9][19:0] <= 20'b11111111111111111110;
|
136 | sq_figure[10][19:0] <= 20'b11111111111111111110;
|
137 | sq_figure[11][19:0] <= 20'b11111111111111111110;
|
138 | sq_figure[12][19:0] <= 20'b11111111111111111110;
|
139 | sq_figure[13][19:0] <= 20'b01111111111111111100;
|
140 | sq_figure[14][19:0] <= 20'b01111111111111111100;
|
141 | sq_figure[15][19:0] <= 20'b00111111111111111000;
|
142 | sq_figure[16][19:0] <= 20'b00111111111111111000;
|
143 | sq_figure[17][19:0] <= 20'b00011111111111110000;
|
144 | sq_figure[18][19:0] <= 20'b00000111111111000000;
|
145 | sq_figure[19][19:0] <= 20'b00000001111100000000;
|
146 |
|
147 | c_hor <= 0;
|
148 | c_ver <= 0;
|
149 | vga_hs_r <= 1;
|
150 | vga_vs_r <= 0;
|
151 | c_row <= 0;
|
152 | c_col <= 0;
|
153 | end
|
154 | else begin // update current beam position
|
155 | if(c_hor < h_frame - 1) begin
|
156 | c_hor <= c_hor + 1;
|
157 | end
|
158 | else begin
|
159 | c_hor <= 0;
|
160 | if(c_ver < v_frame - 1) begin
|
161 | c_ver <= c_ver + 1;
|
162 | end
|
163 | else begin
|
164 | c_ver <= 0;
|
165 | end
|
166 | end
|
167 | end
|
168 | if(c_hor < h_pixels + h_fp + 1 || c_hor > h_pixels + h_fp + h_pulse) begin // H-SYNC generator
|
169 | vga_hs_r <= ~h_pol;
|
170 | end
|
171 | else begin
|
172 | vga_hs_r <= h_pol;
|
173 | end
|
174 | if(c_ver < v_pixels + v_fp || c_ver > v_pixels + v_fp + v_pulse) begin //V-SYNC generator
|
175 | vga_vs_r <= ~v_pol;
|
176 | end
|
177 | else begin
|
178 | vga_vs_r <= v_pol;
|
179 | end
|
180 | if(c_hor < h_pixels) begin //c_col and c_row counters are updated only in the visible time-frame
|
181 | c_col <= c_hor;
|
182 | end
|
183 | if(c_ver < v_pixels) begin
|
184 | c_row <= c_ver;
|
185 | end
|
186 | if(c_hor < h_pixels && c_ver < v_pixels) begin //VGA color signals are enabled only in the visible time frame
|
187 | disp_en <= 1;
|
188 | end
|
189 | else begin
|
190 | disp_en <= 0;
|
191 | end
|
192 | if(disp_en == 1 && reset == 0) begin
|
193 | if(c_row == 0 || c_col == 0 || c_row == v_pixels-1 || c_col == h_pixels-1) begin //generate red frame with size 640x480
|
194 | vga_r_r <= 7;
|
195 | vga_g_r <= 0;
|
196 | vga_b_r <= 0;
|
197 | end
|
198 | else if(c_col > l_sq_pos_x && c_col < r_sq_pos_x && c_row > u_sq_pos_y && c_row < d_sq_pos_y) begin //generate blue square
|
199 | //vga_r_r <= 7;
|
200 | //vga_g_r <= 0;
|
201 | //vga_b_r <= 7;
|
202 | if(sq_figure[sq_fig_y][sq_fig_x] == 1) begin
|
203 | vga_r_r <= 7;
|
204 | vga_g_r <= 0;
|
205 | vga_b_r <= 7;
|
206 | end
|
207 | else begin
|
208 | vga_r_r <= 0;
|
209 | vga_g_r <= 0;
|
210 | vga_b_r <= 0;
|
211 | end
|
212 | end
|
213 | else begin //everything else is black
|
214 | vga_r_r <= 0;
|
215 | vga_g_r <= 0;
|
216 | vga_b_r <= 0;
|
217 | end
|
218 | end
|
219 | else begin //when display is not enabled everything is black
|
220 | vga_r_r <= 0;
|
221 | vga_g_r <= 0;
|
222 | vga_b_r <= 0;
|
223 | end
|
224 |
|
225 | if(c_row == 1 && c_col == 1) begin //once per video frame
|
226 | if(u_arr) begin
|
227 | if (sq_pos_y > square_size) begin
|
228 | sq_pos_y <= sq_pos_y - 1;
|
229 | end
|
230 | else begin
|
231 | u_arr <= 0;
|
232 | d_arr <= 1;
|
233 | end
|
234 | end;
|
235 |
|
236 | if(d_arr) begin
|
237 | if (sq_pos_y < (v_pixels - 1 - square_size)) begin
|
238 | sq_pos_y <= sq_pos_y + 1;
|
239 | end
|
240 | else begin
|
241 | d_arr <= 0;
|
242 | u_arr <= 1;
|
243 | end
|
244 | end;
|
245 |
|
246 | if(l_arr) begin
|
247 | if (sq_pos_x > square_size) begin
|
248 | sq_pos_x <= sq_pos_x - 1;
|
249 | end
|
250 | else begin
|
251 | l_arr <= 0;
|
252 | r_arr <= 1;
|
253 | end
|
254 | end;
|
255 |
|
256 | if(r_arr) begin
|
257 | if (sq_pos_x < (h_pixels - 1 - square_size)) begin
|
258 | sq_pos_x <= sq_pos_x + 1;
|
259 | end
|
260 | else begin
|
261 | r_arr <= 0;
|
262 | l_arr <= 1;
|
263 | end
|
264 | end;
|
265 |
|
266 | end
|
267 |
|
268 | ps2_clk_buf[1:0] <= {ps2_clk_buf[0], ps2_clk}; // shift old value left and get current value of ps2_clk
|
269 | if(ps2_clk_pos == 1) begin // on positive edge
|
270 | ps2_cntr <= ps2_cntr + 1;
|
271 | if(ps2_cntr == 10) begin // when we got 10 clocks save the PS2 data to ps2_data_reg, ps2_data_reg_prev and ps2_data_reg_prev1
|
272 | ps2_cntr <= 0; // so we have last 3 data values captured from PS2 keyboard
|
273 | ps2_data_reg[7] <= ps2_dat_r[0];
|
274 | ps2_data_reg[6] <= ps2_dat_r[1];
|
275 | ps2_data_reg[5] <= ps2_dat_r[2];
|
276 | ps2_data_reg[4] <= ps2_dat_r[3];
|
277 | ps2_data_reg[3] <= ps2_dat_r[4];
|
278 | ps2_data_reg[2] <= ps2_dat_r[5];
|
279 | ps2_data_reg[1] <= ps2_dat_r[6];
|
280 | ps2_data_reg[0] <= ps2_dat_r[7];
|
281 | ps2_data_reg_prev <= ps2_data_reg;
|
282 | ps2_data_reg_prev1 <= ps2_data_reg_prev;
|
283 | end
|
284 | ps2_dat_r <= {ps2_dat_r[9:0], ps2_data}; // data shift left
|
285 | end
|
286 |
|
287 | /* if(ps2_data_reg_prev1 == 8'he0 && ps2_data_reg_prev == 8'hf0) begin // 0xE0 0xF0 sequaence means key released
|
288 | if(ps2_data_reg == 8'h75) begin
|
289 | u_arr <= 0; //0x75 up key
|
290 | end
|
291 | else if(ps2_data_reg == 8'h6b) begin
|
292 | l_arr <= 0; //0x6B left key
|
293 | end
|
294 | else if(ps2_data_reg == 8'h72) begin
|
295 | d_arr <= 0; //0x72 down key
|
296 | end
|
297 | else if(ps2_data_reg == 8'h74) begin
|
298 | r_arr <= 0; //0x74 right key
|
299 | end
|
300 | end
|
301 | */
|
302 | arr_timer <= arr_timer + 1;
|
303 |
|
304 | if(arr_timer == 0) begin
|
305 |
|
306 | sq_figure[8][19:0] <= sq_figure[8][19:0] ^ 20'b00000001111000000000;
|
307 | sq_figure[9][19:0] <= sq_figure[9][19:0] ^ 20'b00000001111000000000;
|
308 | sq_figure[10][19:0] <= sq_figure[10][19:0] ^ 20'b00000001111000000000;
|
309 | sq_figure[11][19:0] <= sq_figure[11][19:0] ^ 20'b00000001111000000000;
|
310 |
|
311 |
|
312 | if(ps2_data_reg_prev == 8'he0) begin //0xE0 means key pressed
|
313 | if(ps2_data_reg == 8'h75) begin
|
314 | if(u_arr == 1) begin
|
315 | u_arr <= 1; //0x75 up key
|
316 | d_arr <= 0;
|
317 | l_arr <= 0;
|
318 | r_arr <= 0;
|
319 | end
|
320 | else begin
|
321 | u_arr <= 1; //0x75 up key
|
322 | d_arr <= 0;
|
323 | end
|
324 | ps2_data_reg <= 0;
|
325 | end
|
326 | if(ps2_data_reg == 8'h6b) begin
|
327 | if(l_arr == 1) begin
|
328 | l_arr <= 1; //0x6B left key
|
329 | r_arr <= 0;
|
330 | u_arr <= 0;
|
331 | d_arr <= 0;
|
332 | end
|
333 | else begin
|
334 | l_arr <= 1; //0x6B left key
|
335 | r_arr <= 0;
|
336 | end
|
337 | ps2_data_reg <= 0;
|
338 | end
|
339 | if(ps2_data_reg == 8'h72) begin
|
340 | if(d_arr == 1) begin
|
341 | d_arr <= 1; //0x72 down key
|
342 | u_arr <= 0;
|
343 | l_arr <= 0;
|
344 | r_arr <= 0;
|
345 | end
|
346 | else begin
|
347 | d_arr <= 1; //0x72 down key
|
348 | u_arr <= 0;
|
349 | end
|
350 | ps2_data_reg <= 0;
|
351 | end
|
352 | if(ps2_data_reg == 8'h74) begin
|
353 | if(r_arr == 1) begin
|
354 | r_arr <= 1; //0x74 right key
|
355 | l_arr <= 0;
|
356 | u_arr <= 0;
|
357 | d_arr <= 0;
|
358 | end
|
359 | else begin
|
360 | r_arr <= 1; //0x74 right key
|
361 | l_arr <= 0;
|
362 | end
|
363 | ps2_data_reg <= 0;
|
364 | end
|
365 | end
|
366 | end
|
367 |
|
368 |
|
369 | end
|
370 |
|
371 | endmodule
|