-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathPong.vhd
521 lines (463 loc) · 16.6 KB
/
Pong.vhd
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 22:18:30 07/14/2009
-- Design Name:
-- Module Name: Pong - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity Pong is
Port (
clk : in STD_LOGIC;
hsync_out : out STD_LOGIC;
vsync_out : out STD_LOGIC;
red_out : out STD_LOGIC;
green_out : out STD_LOGIC;
blue_out : out STD_LOGIC;
-- leftPlayerInput : in STD_LOGIC;
-- rightPlayerInput : in STD_LOGIC;
soundPin : buffer STD_LOGIC := '0';
kb_clk : in STD_LOGIC;
kb_data : in STD_LOGIC
);
end Pong;
architecture Behavioral of Pong is
component KeyboardController is
Port ( Clock : in STD_LOGIC;
KeyboardClock : in STD_LOGIC;
KeyboardData : in STD_LOGIC;
LeftPaddleDirection : out integer;
RightPaddleDirection : out integer
);
end component;
signal halfClock : STD_LOGIC;
signal horizontalPosition : integer range 0 to 800 := 0;
signal verticalPosition : integer range 0 to 521 := 0;
signal hsyncEnable : STD_LOGIC;
signal vsyncEnable : STD_LOGIC;
signal photonX : integer range 0 to 640 := 0;
signal photonY : integer range 0 to 480 := 0;
constant leftPaddleX : integer := 25;
signal leftPaddleY : integer range 0 to 480 := 240;
constant rightPaddleX : integer := 615;
signal rightPaddleY : integer range 0 to 480 := 240;
signal rightPaddleDirection : integer := 0;
signal leftPaddleDirection : integer := 0;
signal paddleHalfHeight : integer range 0 to 50 := 30;
constant paddleHalfWidth : integer := 6;
constant leftPaddleBackX : integer := leftPaddleX-paddleHalfWidth;
constant leftPaddleFrontX : integer := leftPaddleX+paddleHalfWidth;
constant rightPaddleFrontX : integer := rightPaddleX-paddleHalfWidth;
constant rightPaddleBackX : integer := rightPaddleX+paddleHalfWidth;
constant paddleBottomLimit : integer := 474;
constant paddleTopLimit : integer := 4;
signal color : STD_LOGIC_VECTOR (2 downto 0) := "000";
signal ballMovementClockCounter : integer range 0 to 1000000 := 0;
signal ballMovementClock : STD_LOGIC := '0';
signal paddleMovementClockCounter : integer range 0 to 1000000 := 0;
signal paddleMovementClock : STD_LOGIC := '0';
constant ballMaxSpeed : integer := 8;
signal ballX : integer range -100 to 640 := 320;
signal ballY : integer range -100 to 480 := 240;
signal ballSpeedX : integer range -100 to 100 := 1;
signal ballSpeedY : integer range -100 to 100 := 1;
constant maxLeftLifes : integer := 5;
constant maxRightLifes : integer := 5;
signal leftLifes : integer range 0 to 5 := maxLeftLifes;
signal rightLifes : integer range 0 to 5 := maxRightLifes;
signal gameOver : STD_LOGIC := '0';
constant leftLifePosition : integer := 179;
constant rightLifePosition : integer := 359;
constant lifeBarWidth : integer := 100;
constant lifeBarHeight : integer := 3;
signal resetBall : STD_LOGIC := '0';
signal resetCounter : integer range 0 to 101 := 0;
signal soundCounter : integer range 0 to 1000000 := 0;
signal soundClock : STD_LOGIC := '0';
signal soundPlingCounter : integer range 0 to 100000000 := 0;
signal soundEnable : STD_LOGIC := '0';
signal playSound : STD_LOGIC := '0';
begin
kbController : KeyboardController port map ( clk, kb_clk, kb_data, leftPaddleDirection, rightPaddleDirection );
-- Controls length of beep tone
soundScaler : process(clk)
begin
if clk'event and clk='1' then
if soundCounter = 100000 then --adjust for length of beep
soundCounter <= 0;
soundClock <= not soundClock;
else
soundCounter <= soundCounter + 1;
end if;
end if;
end process soundScaler;
sound : process(soundClock)
begin
if soundClock'event and soundClock = '1' then
if soundEnable = '1' then
soundPin <= not soundPin;
else
soundPin <= '0';
end if;
end if;
end process sound;
soundPling : process(playSound, soundClock)
begin
if soundClock'event and soundClock = '1' then
if playSound='1' then
if soundPlingCounter >= 0 and soundPlingCounter < 20 then
soundEnable <= '1';
soundPlingCounter <= soundPlingCounter + 1;
else
soundEnable <= '0';
end if;
else
soundEnable <= '0';
soundPlingCounter <= 0;
end if;
end if;
end process soundPling;
-- Half the clock
clockScaler : process(clk)
begin
if clk'event and clk = '1' then
halfClock <= not halfClock;
end if;
end process clockScaler;
-- Allows Ball movement on clock pulse
-- Stops at VGA border
ballMovementClockScaler : process(clk)
begin
if clk'event and clk = '1' then
ballMovementClockCounter <= ballMovementClockCounter + 1;
if (ballMovementClockCounter = 500000) then
ballMovementClock <= not ballMovementClock;
ballMovementClockCounter <= 0;
end if;
end if;
end process ballMovementClockScaler;
-- Allows Paddle movement on clock pulse
-- Stops at VGA border
paddleMovementClockScaler : process(clk)
begin
if clk'event and clk = '1' then
paddleMovementClockCounter <= paddleMovementClockCounter + 1;
if (paddleMovementClockCounter = 100000) then
paddleMovementClock <= not paddleMovementClock;
paddleMovementClockCounter <= 0;
end if;
end if;
end process paddleMovementClockScaler;
signalTiming : process(halfClock)
begin
if halfClock'event and halfClock = '1' then
if horizontalPosition = 800 then
horizontalPosition <= 0;
verticalPosition <= verticalPosition + 1;
if verticalPosition = 521 then
verticalPosition <= 0;
else
verticalPosition <= verticalPosition + 1;
end if;
else
horizontalPosition <= horizontalPosition + 1;
end if;
end if;
end process signalTiming;
vgaSync : process(halfClock, horizontalPosition, verticalPosition)
begin
if halfClock'event and halfClock = '1' then
if horizontalPosition > 0 and horizontalPosition < 97 then
hsyncEnable <= '0';
else
hsyncEnable <= '1';
end if;
if verticalPosition > 0 and verticalPosition < 3 then
vsyncEnable <= '0';
else
vsyncEnable <= '1';
end if;
end if;
end process vgaSync;
coordinates : process(horizontalPosition, verticalPosition)
begin
photonX <= horizontalPosition - 144;
photonY <= verticalPosition - 31;
end process coordinates;
finishGame : process(leftLifes, rightLifes)
begin
if leftLifes = 0 or rightLifes = 0 then
gameOver <= '1';
end if;
end process finishGame;
colorSetter : process(photonX, photonY, halfClock)
begin
-- Paddle handling
if gameOver = '1' then
-- G
if photonX >= 20 and photonX <= 80 and photonY >= 180 and photonY <= 190 then
color <= "100";
elsif photonX >= 20 and photonX <= 30 and photonY >= 190 and photonY <= 300 then
color <= "100";
elsif photonX >= 20 and photonX <= 80 and photonY >= 290 and photonY <= 300 then
color <= "100";
elsif photonX >= 70 and photonX <= 80 and photonY >= 240 and photonY <= 300 then
color <= "100";
elsif photonX >= 50 and photonX <= 80 and photonY >= 240 and photonY <= 250 then
color <= "100";
-- A
elsif photonX >= 90 and photonX <= 150 and photonY >= 180 and photonY <= 190 then
color <= "100";
elsif photonX >= 90 and photonX <= 100 and photonY >= 190 and photonY <= 300 then
color <= "100";
elsif photonX >= 140 and photonX <= 150 and photonY >= 190 and photonY <= 300 then
color <= "100";
elsif photonX >= 90 and photonX <= 150 and photonY >= 240 and photonY <= 250 then
color <= "100";
-- M
elsif ((photonX >= 160 and photonX <= 170 and photonY >= 180 and photonY <= 300) or
(photonX >= 170 and photonX <= 220 and photonY >= 190 and photonY <= 200) or
(photonX >= 210 and photonX <= 220 and photonY >= 190 and photonY <= 300) or
(photonX >= 185 and photonX <= 195 and photonY >= 190 and photonY <= 300)) then
color <= "100";
-- erstes E
elsif photonX >= 230 and photonX <= 290 and photonY >= 180 and photonY <= 190 then
color <= "100";
elsif photonX >= 230 and photonX <= 290 and photonY >= 235 and photonY <= 245 then
color <= "100";
elsif photonX >= 230 and photonX <= 290 and photonY >= 290 and photonY <= 300 then
color <= "100";
elsif photonX >= 230 and photonX <= 240 and photonY >= 180 and photonY <= 300 then
color <= "100";
-- O
elsif photonX >= 348 and photonX <= 408 and photonY >= 180 and photonY <= 190 then
color <= "100";
elsif photonX >= 348 and photonX <= 358 and photonY >= 190 and photonY <= 290 then
color <= "100";
elsif photonX >= 398 and photonX <= 408 and photonY >= 190 and photonY <= 290 then
color <= "100";
elsif photonX >= 348 and photonX <= 408 and photonY >= 290 and photonY <= 300 then
color <= "100";
-- V
elsif photonX >= 418 and photonX <= 448 and photonY >= 270 and photonY <= 300 then
if (photonX - 418) = (photonY - 270) or
(photonX - 419) = (photonY - 270) or
(photonX - 420) = (photonY - 270) or
(photonX - 421) = (photonY - 270) or
(photonX - 422) = (photonY - 270) or
(photonX - 423) = (photonY - 270) or
(photonX - 424) = (photonY - 270) or
(photonX - 425) = (photonY - 270) or
(photonX - 426) = (photonY - 270) or
(photonX - 427) = (photonY - 270) or
(photonX - 428) = (photonY - 270) then
color <= "100";
else
color <= "000";
end if;
elsif photonX >= 449 and photonX <= 478 and photonY >= 270 and photonY <= 300 then
if (478 - photonX) = (photonY - 270) or
(477 - photonX) = (photonY - 270) or
(476 - photonX) = (photonY - 270) or
(475 - photonX) = (photonY - 270) or
(474 - photonX) = (photonY - 270) or
(473 - photonX) = (photonY - 270) or
(472 - photonX) = (photonY - 270) or
(471 - photonX) = (photonY - 270) or
(470 - photonX) = (photonY - 270) or
(469 - photonX) = (photonY - 270) or
(468 - photonX) = (photonY - 270) then
color <= "100";
else
color <= "000";
end if;
elsif (photonX >= 418 and photonX <= 428 and photonY >= 180 and photonY <= 270) or
(photonX >= 468 and photonX <= 478 and photonY >= 180 and photonY <= 270) then
color <= "100";
-- zweites E
elsif photonX >= 488 and photonX <= 548 and photonY >= 180 and photonY <= 190 then
color <= "100";
elsif photonX >= 488 and photonX <= 548 and photonY >= 235 and photonY <= 245 then
color <= "100";
elsif photonX >= 488 and photonX <= 548 and photonY >= 290 and photonY <= 300 then
color <= "100";
elsif photonX >= 488 and photonX <= 498 and photonY >= 180 and photonY <= 300 then
color <= "100";
-- R
elsif photonX >= 558 and photonX <= 618 and photonY >= 180 and photonY <= 190 then
color <= "100";
elsif photonX >= 558 and photonX <= 568 and photonY >= 190 and photonY <= 300 then
color <= "100";
elsif photonX >= 608 and photonX <= 618 and photonY >= 190 and photonY <= 250 then
color <= "100";
elsif photonX >= 558 and photonX <= 618 and photonY >= 245 and photonY <= 255 then
color <= "100";
elsif photonX >= 568 and photonX <= 618 and photonY >= 245 and photonY <= 300 then
if (photonX - 568) = (photonY - 255) or
(photonX - 567) = (photonY - 255) or
(photonX - 566) = (photonY - 255) or
(photonX - 565) = (photonY - 255) or
(photonX - 564) = (photonY - 255) or
(photonX - 563) = (photonY - 255) or
(photonX - 562) = (photonY - 255) or
(photonX - 561) = (photonY - 255) or
(photonX - 569) = (photonY - 255) or
(photonX - 570) = (photonY - 255) or
(photonX - 571) = (photonY - 255) or
(photonX - 572) = (photonY - 255) or
(photonX - 573) = (photonY - 255) or
(photonX - 574) = (photonY - 255) then
color <= "100";
else
color <= "000";
end if;
else
color <= "000";
end if;
elsif ((photonX >= leftPaddleBackX) and (photonX <= leftPaddleFrontX)
and (photonY >= leftPaddleY - paddleHalfHeight) and (photonY <= leftPaddleY + paddleHalfHeight)) or
((photonX >= rightPaddleFrontX) and (photonX <= rightPaddleBackX)
and (photonY >= rightPaddleY - paddleHalfHeight) and (photonY <= rightPaddleY + paddleHalfHeight)) then
color <= "111";
-- Dashed Line
elsif (photonX = 319 and photonY mod 16 <= 10) then
color <= "111";
-- Ball
elsif (photonY >= ballY - 2 and photonY <= ballY + 2) and (photonX >= ballX - 2 and photonX <= ballX + 2) then
color <= "111";
elsif (photonY >= ballY - 3 and photonY <= ballY + 3) and (photonX >= ballX - 1 and photonX <= ballX + 1) then
color <= "111";
elsif (photonY >= ballY - 1 and photonY <= ballY + 1) and (photonX >= ballX - 3 and photonX <= ballX + 3) then
color <= "111";
-- green lifebar
elsif (photonX>=leftLifePosition and photonX<leftLifePosition+(leftLifes*20) and photonY>=30 and photonY<=30+lifeBarHeight) or
(photonX>=rightLifePosition and photonX<rightLifePosition+(rightLifes*20) and photonY>=30 and photonY<=30+lifeBarHeight) then
color <= "010";
-- red lifebar
elsif (photonX >= (leftLifePosition+(leftLifes*20)) and photonX <= (leftLifePosition+(20*maxLeftLifes)) and photonY>=30 and photonY<=(30+lifeBarHeight)) or
(photonX>=(rightLifePosition+(rightLifes*20)) and photonX<= (rightLifePosition+(20*maxRightLifes)) and photonY>=30 and photonY<=(30+lifeBarHeight)) then
color <= "100";
-- background
else
color <= "000";
end if;
end process colorSetter;
-- Left Player Control
-- Stops at Limit
leftPaddleMovement : process(paddleMovementClock)
begin
if paddleMovementClock'event and paddleMovementClock = '1' then
if leftPaddleY + leftPaddleDirection < paddleBottomLimit - paddleHalfHeight
and leftPaddleY + leftPaddleDirection > paddleTopLimit + paddleHalfHeight then
leftPaddleY <= leftPaddleY + leftPaddleDirection;
end if;
end if;
end process leftPaddleMovement;
-- Right Player Control
-- Stops at limit
rightPaddleMovement : process(paddleMovementClock)
begin
if paddleMovementClock'event and paddleMovementClock = '1' then
if rightPaddleY + rightPaddleDirection < paddleBottomLimit - paddleHalfHeight
and rightPaddleY + rightPaddleDirection > paddleTopLimit + paddleHalfHeight then
rightPaddleY <= rightPaddleY + rightPaddleDirection;
end if;
end if;
end process rightPaddleMovement;
ballMovement : process(ballMovementClock,gameOver,soundPlingCounter)
begin
if gameOver = '1' then -- Centers and stops ball
ballX <= 319;
ballY <= 239;
ballSpeedX <= 0;
ballSpeedY <= 0;
elsif soundPlingCounter >= 10 then
playSound <= '0';
elsif ballMovementClock'event and ballMovementClock='1' then
if resetBall = '1' then
if resetCounter = 100 then
resetCounter <= 0;
ballX <= 319;
ballY <= 239;
resetBall <= '0';
else
resetCounter <= resetCounter + 1;
end if;
else
if ballX+4 > rightPaddleFrontX and ballX < rightPaddleBackX
and ballY+4 > rightPaddleY-paddleHalfHeight and ballY-4 < rightPaddleY+paddleHalfHeight then
ballX <= rightPaddleFrontX - 4;
ballSpeedY <= (ballY - rightPaddleY) / 8;
ballSpeedX <= -ballMaxSpeed + ballSpeedY;
playSound <= '1';
elsif ballX-4 < leftPaddleFrontX and ballX > leftPaddleBackX
and ballY+4 > leftPaddleY-paddleHalfHeight and ballY-4 < leftPaddleY+paddleHalfHeight then
ballX <= leftPaddleFrontX + 4;
ballSpeedY <= ((ballY - leftPaddleY) / 8);
ballSpeedX <= ballMaxSpeed - ballSpeedY;
playSound <= '1';
elsif ballX + ballSpeedX < 4 then
leftLifes <= leftLifes - 1;
ballX <= -20;
ballY <= -20;
resetBall <= '1';
elsif ballX + ballSpeedX > 635 then
rightLifes <= rightLifes - 1;
ballX <= -20;
ballY <= -20;
resetBall <= '1';
else
ballX <= ballX + ballSpeedX;
end if;
if ballY > 470 then
ballY <= 470;
ballSpeedY <= -ballSpeedY;
playSound <= '1';
elsif ballY < 10 then
ballY <= 10;
ballSpeedY <= -ballSpeedY;
playSound <= '1';
else
ballY <= ballY + ballSpeedY;
end if;
end if;
end if;
end process ballMovement;
-- VGA Controller
draw : process(photonX, photonY, halfClock)
begin
if halfClock'event and halfClock = '1' then
hsync_out <= hsyncEnable;
vsync_out <= vsyncEnable;
if (photonX < 640 and photonY < 480) then
red_out <= color(2);
green_out <= color(1);
blue_out <= color(0);
else
red_out <= '0';
green_out <= '0';
blue_out <= '0';
end if;
end if;
end process draw;
end Behavioral;