-
Notifications
You must be signed in to change notification settings - Fork 0
/
vga_ball.vhd
523 lines (465 loc) · 20 KB
/
vga_ball.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
522
523
-------------------------------------------------------------------------------
-- Title : exemplo
-- Project :
-------------------------------------------------------------------------------
-- File : exemplo.vhd
-- Author : Rafael Auler
-- Company :
-- Created : 2010-03-26
-- Last update: 2018-04-05
-- Platform :
-- Standard : VHDL'2008
-------------------------------------------------------------------------------
-- Description: Fornece um exemplo de uso do módulo VGACON para a disciplina
-- MC613.
-- Este módulo possui uma máquina de estados simples que se ocupa
-- de escrever na memória de vídeo (atualizar o quadro atual) e,
-- em seguida, de atualizar a posição de uma "bola" que percorre
-- toda a tela, quicando pelos cantos.
-------------------------------------------------------------------------------
-- Copyright (c) 2010
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-03-26 1.0 Rafael Auler Created
-- 2018-04-05 1.1 IBFelzmann Adapted for DE1-SoC
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.game_package.all;
entity vga_ball is
port (
CLOCK_50 : in std_logic;
KEY : in std_logic_vector(1 downto 0);
VGA_R, VGA_G, VGA_B : out std_logic_vector(7 downto 0);
VGA_HS, VGA_VS : out std_logic;
VGA_BLANK_N, VGA_SYNC_N : out std_logic;
VGA_CLK : out std_logic;
game_table : in vetor;
table_map_out : in std_logic_vector (79 downto 0);
linha, coluna : in integer range 0 to 9;
n_cards : in integer range 0 to 79
);
end vga_ball;
architecture comportamento of vga_ball is
signal cheats : std_logic; -- Mostra todas as cartas.
signal rstn : std_logic; -- reset active low para nossos
-- circuitos sequenciais.
-- Interface com a memória de vídeo do controlador
signal we : std_logic; -- write enable ('1' p/ escrita)
signal addr : integer range 0 to 12287; -- endereco mem. vga
signal pixel : std_logic_vector(2 downto 0); -- valor de cor do pixel
signal pixel_bit : std_logic; -- um bit do vetor acima
-- Sinais dos contadores de linhas e colunas utilizados para percorrer
-- as posições da memória de vídeo (pixels) no momento de construir um quadro.
signal line : integer range 0 to 95; -- linha atual
signal col : integer range 0 to 127; -- coluna atual
signal col_rstn : std_logic; -- reset do contador de colunas
signal col_enable : std_logic; -- enable do contador de colunas
signal line_rstn : std_logic; -- reset do contador de linhas
signal line_enable : std_logic; -- enable do contador de linhas
signal fim_escrita : std_logic; -- '1' quando um quadro terminou de ser
-- escrito na memória de vídeo
-- Sinais que armazem a posição de uma bola, que deverá ser desenhada
-- na tela de acordo com sua posição.
signal pos_x, pos_x1, pos_x2, pos_x3, pos_x4, pos_x5, pos_x6, pos_x7, pos_x8, pos_x9 : integer range 0 to 127; -- coluna atual da bola
signal pos_y, pos_y1, pos_y2, pos_y3, pos_y4, pos_y5, pos_y6, pos_y7, pos_y8, pos_y9 : integer range 0 to 95; -- linha atual da bola
signal atualiza_pos_x : std_logic; -- se '1' = bola muda sua pos. no eixo x
signal atualiza_pos_y : std_logic; -- se '1' = bola muda sua pos. no eixo y
-- Especificação dos tipos e sinais da máquina de estados de controle
type estado_t is (show_splash, inicio, constroi_quadro, move_bola);
signal estado: estado_t := show_splash;
signal proximo_estado: estado_t := show_splash;
-- Sinais para um contador utilizado para atrasar a atualização da
-- posição da bola, a fim de evitar que a animação fique excessivamente
-- veloz. Aqui utilizamos um contador de 0 a 1250000, de modo que quando
-- alimentado com um clock de 50MHz, ele demore 25ms (40fps) para contar até o final.
signal contador : integer range 0 to 1250000 - 1; -- contador
signal timer : std_logic; -- vale '1' quando o contador chegar ao fim
signal timer_rstn, timer_enable : std_logic;
signal sync, blank: std_logic;
signal color_int : integer range 0 to 7;
signal color_bin : std_logic_vector (2 downto 0);
signal y_color, x_color : integer range 0 to 63;
signal old_yc, old_xc : integer range 0 to 63;
-- 8 colunas e 4 linhas
CONSTANT col_margin : integer := 4;
CONSTANT col_width : integer := 11;
CONSTANT row_margin : integer := 4;
CONSTANT row_width : integer := 18;
CONSTANT num_y_margin: integer := 6;
CONSTANT num_x_margin: integer := 3;
signal num_matrix : std_logic_vector (0 to 249) := "0111001010010100101001110001000010000100001000010001110000100111001000011100111000010011100001001110010100101001110000100001001110010000111000010011100111001000011100101001110011100001000010000100001001110010100111001010011100111001010011100001001110";
type color_vector is array (0 to 100) of integer range 0 to 7;
-- preencher card_color(i) com as cores baseadas em game_table(i)
signal card_color : color_vector;
signal is_card_flipped : std_logic_vector (100 downto 0);
begin -- comportamento
-- Aqui instanciamos o controlador de vídeo, 128 colunas por 96 linhas
-- (aspect ratio 4:3). Os sinais que iremos utilizar para comunicar
-- com a memória de vídeo (para alterar o brilho dos pixels) são
-- write_clk (nosso clock), write_enable ('1' quando queremos escrever
-- o valor de um pixel), write_addr (endereço do pixel a escrever)
-- e data_in (valor do brilho do pixel RGB, 1 bit pra cada componente de cor)
vga_controller: entity work.vgacon port map (
clk50M => CLOCK_50,
rstn => '1',
red => VGA_R,
green => VGA_G,
blue => VGA_B,
hsync => VGA_HS,
vsync => VGA_VS,
write_clk => CLOCK_50,
write_enable => we,
write_addr => addr,
data_in => pixel,
vga_clk => VGA_CLK,
sync => sync,
blank => blank);
VGA_SYNC_N <= NOT sync;
VGA_BLANK_N <= NOT blank;
-----------------------------------------------------------------------------
-- Processos que controlam contadores de linhas e coluna para varrer
-- todos os endereços da memória de vídeo, no momento de construir um quadro.
-----------------------------------------------------------------------------
-- purpose: Este processo conta o número da coluna atual, quando habilitado
-- pelo sinal "col_enable".
-- type : sequential
-- inputs : CLOCK_50, col_rstn
-- outputs: col
conta_coluna: process (CLOCK_50, col_rstn)
begin -- process conta_coluna
if col_rstn = '0' then -- asynchronous reset (active low)
col <= 0;
elsif CLOCK_50'event and CLOCK_50 = '1' then -- rising clock edge
if col_enable = '1' then
if col = 127 then -- conta de 0 a 127 (128 colunas)
col <= 0;
else
col <= col + 1;
end if;
end if;
end if;
end process conta_coluna;
-- purpose: Este processo conta o número da linha atual, quando habilitado
-- pelo sinal "line_enable".
-- type : sequential
-- inputs : CLOCK_50, line_rstn
-- outputs: line
conta_linha: process (CLOCK_50, line_rstn)
begin -- process conta_linha
if line_rstn = '0' then -- asynchronous reset (active low)
line <= 0;
elsif CLOCK_50'event and CLOCK_50 = '1' then -- rising clock edge
-- o contador de linha só incrementa quando o contador de colunas
-- chegou ao fim (valor 127)
if line_enable = '1' and col = 127 then
if line = 95 then -- conta de 0 a 95 (96 linhas)
line <= 0;
else
line <= line + 1;
end if;
end if;
end if;
end process conta_linha;
-- Este sinal é útil para informar nossa lógica de controle quando
-- o quadro terminou de ser escrito na memória de vídeo, para que
-- possamos avançar para o próximo estado.
fim_escrita <= '1' when (line = 95) and (col = 127)
else '0';
-----------------------------------------------------------------------------
-- Abaixo estão processos relacionados com a atualização da posição da
-- bola. Todos são controlados por sinais de enable de modo que a posição
-- só é de fato atualizada quando o controle (uma máquina de estados)
-- solicitar.
-----------------------------------------------------------------------------
-- purpose: Este processo irá atualizar a coluna atual da bola,
-- alterando sua posição no próximo quadro a ser desenhado.
-- type : sequential
-- inputs : CLOCK_50, rstn
-- outputs: pos_x
p_atualiza_pos_x: process (CLOCK_50, rstn)
type direcao_t is (direita, esquerda);
variable direcao : direcao_t := direita;
begin -- process p_atualiza_pos_x
if rstn = '0' then -- asynchronous reset (active low)
pos_x <= 0;
elsif CLOCK_50'event and CLOCK_50 = '1' then -- rising clock edge
if atualiza_pos_x = '1' then
if direcao = direita then
if pos_x = 127 then
--change_color = not changecolor;
if x_color = 63 then
x_color <= 1;
else
x_color <= x_color + 1;
end if;
direcao := esquerda;
else
pos_x1 <= pos_x2;
pos_x2 <= pos_x3;
pos_x3 <= pos_x4;
pos_x4 <= pos_x5;
pos_x5 <= pos_x;
pos_x <= pos_x + 1;
end if;
else -- se a direcao é esquerda
if pos_x = 0 then
--change_color = not changecolor;
if x_color = 63 then
x_color <= 1;
else
x_color <= x_color + 1;
end if;
direcao := direita;
else
pos_x1 <= pos_x2;
pos_x2 <= pos_x3;
pos_x3 <= pos_x4;
pos_x4 <= pos_x5;
pos_x5 <= pos_x;
pos_x <= pos_x - 1;
end if;
end if;
end if;
end if;
end process p_atualiza_pos_x;
-- purpose: Este processo irá atualizar a linha atual da bola,
-- alterando sua posição no próximo quadro a ser desenhado.
-- type : sequential
-- inputs : CLOCK_50, rstn
-- outputs: pos_y
p_atualiza_pos_y: process (CLOCK_50, rstn)
type direcao_t is (desce, sobe);
variable direcao : direcao_t := desce;
begin -- process p_atualiza_pos_x
if rstn = '0' then -- asynchronous reset (active low)
pos_y <= 0;
elsif CLOCK_50'event and CLOCK_50 = '1' then -- rising clock edge
if atualiza_pos_y = '1' then
if direcao = desce then
if pos_y = 95 then
if y_color = 63 then
y_color <= 1;
else
y_color <= y_color + 1;
end if;
direcao := sobe;
else
pos_y1 <= pos_y2;
pos_y2 <= pos_y3;
pos_y3 <= pos_y4;
pos_y4 <= pos_y5;
pos_y5 <= pos_y;
pos_y <= pos_y + 1;
end if;
else -- se a direcao é para subir
if pos_y = 0 then
if y_color = 63 then
y_color <= 1;
else
y_color <= y_color + 1;
end if;
direcao := desce;
else
pos_y1 <= pos_y2;
pos_y2 <= pos_y3;
pos_y3 <= pos_y4;
pos_y4 <= pos_y5;
pos_y5 <= pos_y;
pos_y <= pos_y - 1;
end if;
end if;
end if;
end if;
end process p_atualiza_pos_y;
-----------------------------------------------------------------------------
-- Brilho do pixel
-----------------------------------------------------------------------------
cheats <= not KEY(1);
process (CLOCK_50, rstn)
variable pixel_color : integer range 0 to 7;
variable exit_loop: std_logic;
variable y_bound: integer range 0 to 200;
variable x_bound: integer range 0 to 200;
variable y_deref: integer range 0 to 200;
variable x_deref: integer range 0 to 200;
variable offset: integer range 0 to 500;
begin
exit_loop := '0';
pixel_color := 0; -- comeca com a cor preta
L1 : for i in 0 to 3 loop -- linhas
for j in 0 to 7 loop -- colunas
if ((line >= row_margin + row_width*i + row_margin*i) and (line <= row_margin + row_width*(i+1) + row_margin*i)) then -- nos boundaries do eixo y de uma carta
if ((col >= col_margin + col_width*j + col_margin*j) and (col <= col_margin + col_width*(j+1) + col_margin*j)) then -- nos boundaries do eixo x de uma carta
if (i*8+j < n_cards) then
if (table_map_out(i*8 + j) = '0' or cheats = '1') then -- printa numero e cor
-- boundaries dos numeros
y_bound := row_margin + row_width*i + row_margin*i + num_y_margin;
x_bound := col_margin + col_width*j + col_margin*j + num_x_margin;
if ((line >= y_bound) and (line <= 4 + y_bound) and (col >= x_bound) and (col <= 4 + x_bound)) then -- verifica boundaries da letra
-- dereferencia
y_deref := line-y_bound;
x_deref := col-x_bound;
offset := (game_table(i*8 + j) mod 10)*25;
-- verifica se eh 1 ou 0 na letra
if (num_matrix(offset + y_deref*5 + x_deref) = '1') then
if (game_table(i*8 + j)/10 = 0) then
pixel_color := 7;
else
pixel_color := 0;
end if;
else
pixel_color := game_table(i*8 + j)/10;
end if;
else
pixel_color := game_table(i*8 + j)/10;
end if;
else
pixel_color := 7;
end if;
if (linha = i and coluna = j) then
if ((line = row_margin + row_width*i + row_margin*i) or (line = row_margin + row_width*(i+1) + row_margin*i) or (col = col_margin + col_width*j + col_margin*j) or (col = col_margin + col_width*(j+1) + col_margin*j)) then
pixel_color := 4;
end if;
end if;
end if;
exit L1;
end if;
end if;
end loop;
end loop L1;
color_bin <= std_logic_vector(to_unsigned(pixel_color, 3));
end process;
pixel <= color_bin;
-- O endereço de memória pode ser construído com essa fórmula simples,
-- a partir da linha e coluna atual
addr <= col + (128 * line);
-----------------------------------------------------------------------------
-- Processos que definem a FSM (finite state machine), nossa máquina
-- de estados de controle.
-----------------------------------------------------------------------------
-- purpose: Esta é a lógica combinacional que calcula sinais de saída a partir
-- do estado atual e alguns sinais de entrada (Máquina de Mealy).
-- type : combinational
-- inputs : estado, fim_escrita, timer
-- outputs: proximo_estado, atualiza_pos_x, atualiza_pos_y, line_rstn,
-- line_enable, col_rstn, col_enable, we, timer_enable, timer_rstn
logica_mealy: process (estado, fim_escrita, timer)
begin -- process logica_mealy
case estado is
when inicio => if timer = '1' then
proximo_estado <= constroi_quadro;
else
proximo_estado <= inicio;
end if;
atualiza_pos_x <= '0';
atualiza_pos_y <= '0';
line_rstn <= '0'; -- reset é active low!
line_enable <= '0';
col_rstn <= '0'; -- reset é active low!
col_enable <= '0';
we <= '0';
timer_rstn <= '1'; -- reset é active low!
timer_enable <= '1';
when constroi_quadro=> if fim_escrita = '1' then
proximo_estado <= move_bola;
else
proximo_estado <= constroi_quadro;
end if;
atualiza_pos_x <= '0';
atualiza_pos_y <= '0';
line_rstn <= '1';
line_enable <= '1';
col_rstn <= '1';
col_enable <= '1';
we <= '1';
timer_rstn <= '0';
timer_enable <= '0';
when move_bola => proximo_estado <= inicio;
atualiza_pos_x <= '1';
atualiza_pos_y <= '1';
line_rstn <= '1';
line_enable <= '0';
col_rstn <= '1';
col_enable <= '0';
we <= '0';
timer_rstn <= '0';
timer_enable <= '0';
when others => proximo_estado <= inicio;
atualiza_pos_x <= '0';
atualiza_pos_y <= '0';
line_rstn <= '1';
line_enable <= '0';
col_rstn <= '1';
col_enable <= '0';
we <= '0';
timer_rstn <= '1';
timer_enable <= '0';
end case;
end process logica_mealy;
-- purpose: Avança a FSM para o próximo estado
-- type : sequential
-- inputs : CLOCK_50, rstn, proximo_estado
-- outputs: estado
seq_fsm: process (CLOCK_50, rstn)
begin -- process seq_fsm
if rstn = '0' then -- asynchronous reset (active low)
estado <= inicio;
elsif CLOCK_50'event and CLOCK_50 = '1' then -- rising clock edge
estado <= proximo_estado;
end if;
end process seq_fsm;
-----------------------------------------------------------------------------
-- Processos do contador utilizado para atrasar a animação (evitar
-- que a atualização de quadros fique excessivamente veloz).
-----------------------------------------------------------------------------
-- purpose: Incrementa o contador a cada ciclo de clock
-- type : sequential
-- inputs : CLOCK_50, timer_rstn
-- outputs: contador, timer
p_contador: process (CLOCK_50, timer_rstn)
begin -- process p_contador
if timer_rstn = '0' then -- asynchronous reset (active low)
contador <= 0;
elsif CLOCK_50'event and CLOCK_50 = '1' then -- rising clock edge
if timer_enable = '1' then
if contador = 1250000 - 1 then
contador <= 0;
else
contador <= contador + 1;
end if;
end if;
end if;
end process p_contador;
-- purpose: Calcula o sinal "timer" que indica quando o contador chegou ao
-- final
-- type : combinational
-- inputs : contador
-- outputs: timer
p_timer: process (contador)
begin -- process p_timer
if contador = 1250000 - 1 then
timer <= '1';
else
timer <= '0';
end if;
end process p_timer;
-----------------------------------------------------------------------------
-- Processos que sincronizam sinais assíncronos, de preferência com mais
-- de 1 flipflop, para evitar metaestabilidade.
-----------------------------------------------------------------------------
-- purpose: Aqui sincronizamos nosso sinal de reset vindo do botão da DE1
-- type : sequential
-- inputs : CLOCK_50
-- outputs: rstn
build_rstn: process (CLOCK_50)
variable temp : std_logic; -- flipflop intermediario
begin -- process build_rstn
if CLOCK_50'event and CLOCK_50 = '1' then -- rising clock edge
rstn <= temp;
temp := KEY(0);
end if;
end process build_rstn;
end comportamento;