Визуальная электроника

По доброй традиции, в третьей части проекта для нашей платы VE-LCMXO27000HC мы создадим видео игру. За основу возьмем проект PONG game on Nexys3, in Verilog. В основу этого дизайна заложена идея знаменитой игры PONG. Которая является одной из самых ранних аркадных видео игр, это теннисная спортивная игра с использованием простой двухмерной графики. До него были и другие видео игры, такие как Computer Space, однако PONG стал первой достаточно популярной видео игрой. В состав проекта входят следующие файлы:

  • top.v - модуль верхнего уровня, выполняет роль связующего между остальными модулями
  • clk_pixel.v - генератор тактовой частоты 25 МГц, для VGA сигнала
  • clk_test.v - модуль тестбенча тактовой частоты 25 МГц, для VGA сигнала
  • debounce.v - антидребезг для кнопок
  • vga_sync.v - генератор VGA сигналов
  • sync_test.v - модуль тестбенча генератора VGA сигналов
  • timer_1ms.v - генератор 1 мс. импульсов
  • graphic.v - собственно сама игра

Самым интересным файлом является graphic.v, рассмотрим его подробнее:

Verilog Code:
  1. `timescale 1ns / 1ps
  2.  
  3. // show pixel(x, y) on the screen
  4. module graphic(
  5. input wire clk, reset,
  6. input wire [1:0] miao,
  7. input wire [10:0] x, y,
  8. input wire [1:0] btn1, btn2,
  9. output wire [7:0] rgb
  10. );
  11.  
  12. // colors: [B1 B2 G1 G2 G3 R1 R2 R3]
  13. localparam COLOR_BG = 8'b01001000;
  14. localparam COLOR_BALL = 8'b11011101;
  15. localparam COLOR_LINE = 8'b11100001;
  16. localparam COLOR_LBAR = 8'b10010111;
  17. localparam COLOR_RBAR = 8'b00101011;
  18. localparam COLOR_NULL = 8'b00000000;
  19.  
  20. // sizes
  21. reg [10:0] BAR_H = 11'd60;
  22. reg [10:0] BAR_W = 11'd5;
  23. localparam BALL_R = 11'd5;
  24. localparam L_BOUND = 11'd60;
  25. localparam R_BOUND = 11'd580;
  26. localparam U_BOUND = 11'd40;
  27. localparam D_BOUND = 11'd440;
  28.  
  29. // velocities
  30. localparam BAR_V = 10'd1;
  31. localparam BALL_V = 10'd1;
  32.  
  33. // initialize values
  34. reg [10:0] ball_x, ball_y, lbar_y, rbar_y;
  35. reg ball_move_x, ball_move_y;
  36. reg [5:0] lscore, rscore;
  37. initial begin
  38. ball_x = 11'd320;
  39. ball_y = 11'd240;
  40. lbar_y = 11'd240;
  41. rbar_y = 11'd240;
  42. ball_move_x = 1'b1;
  43. ball_move_y = 1'b1;
  44. lscore = 1'b0;
  45. rscore = 1'b0;
  46. end
  47.  
  48. reg [7:0] rgb_now;
  49. wire clk_frame = (x == 0 && y == 0);
  50. always @(posedge clk) begin
  51.  
  52. if (clk_frame) begin
  53. // controls
  54. if (btn1[0] && lbar_y > U_BOUND + BAR_H / 2) lbar_y = lbar_y - BAR_V;
  55. if (btn1[1] && lbar_y < D_BOUND - BAR_H / 2) lbar_y = lbar_y + BAR_V;
  56. if (btn2[0] && rbar_y > U_BOUND + BAR_H / 2) rbar_y = rbar_y - BAR_V;
  57. if (btn2[1] && rbar_y < D_BOUND - BAR_H / 2) rbar_y = rbar_y + BAR_V;
  58.  
  59. if (miao[0]) BAR_H = 11'd150;
  60. else BAR_H = 11'd60;
  61. if (miao[1]) BAR_W = 11'd20;
  62. else BAR_W = 11'd5;
  63. if (reset) begin
  64. lscore = 0;
  65. rscore = 0;
  66. end
  67.  
  68. // ball move
  69. if (ball_move_x) ball_x = ball_x + BALL_V;
  70. else ball_x = ball_x - BALL_V;
  71. if (ball_move_y) ball_y = ball_y + BALL_V;
  72. else ball_y = ball_y - BALL_V;
  73.  
  74. // coliision detect
  75. if (ball_y <= U_BOUND + BALL_R || ball_y >= D_BOUND - BALL_R)
  76. ball_move_y = ~ball_move_y;
  77. if (ball_x == L_BOUND + BAR_W + BALL_R &&
  78. ball_y + BALL_R >= lbar_y - BAR_H / 2 && ball_y - BALL_R <= lbar_y + BAR_H / 2)
  79. ball_move_x = ~ball_move_x;
  80. if (ball_x == R_BOUND - BAR_W - BALL_R &&
  81. ball_y + BALL_R >= rbar_y - BAR_H / 2 && ball_y - BALL_R <= rbar_y + BAR_H / 2)
  82. ball_move_x = ~ball_move_x;
  83.  
  84. // bound detect
  85. if (ball_x < 3 || ball_x > 637) begin
  86. if (ball_x < 3)
  87. rscore = rscore + 1'b1;
  88. else if (ball_x > 637)
  89. lscore = lscore + 1'b1;
  90. ball_x = 320;
  91. ball_y = 240;
  92. ball_move_x = (rscore > lscore);
  93. ball_move_y = 1'b1;
  94. end
  95. end
  96.  
  97. if (x >= 0 && y >= 0 && x < 640 && y < 480) begin
  98.  
  99. rgb_now <= COLOR_BG;
  100.  
  101. // border
  102. if ((y == 40 || y == 440) && (x >= L_BOUND && x <= R_BOUND))
  103. rgb_now <= COLOR_LINE;
  104.  
  105. // bars
  106. if ((x >= L_BOUND && x <= L_BOUND + BAR_W) &&
  107. (y >= lbar_y - BAR_H / 2 && y <= lbar_y + BAR_H / 2))
  108. rgb_now <= COLOR_LBAR;
  109. if ((x >= R_BOUND - BAR_W && x <= R_BOUND) &&
  110. (y >= rbar_y - BAR_H / 2 && y <= rbar_y + BAR_H / 2))
  111. rgb_now <= COLOR_RBAR;
  112.  
  113. // ball
  114. if ((x >= ball_x - BALL_R && x <= ball_x + BALL_R) &&
  115. (y >= ball_y - BALL_R && y <= ball_y + BALL_R))
  116. rgb_now <= COLOR_BALL;
  117.  
  118. // score
  119. if (x >= 6 && x <= 12)
  120. if (y / 6 % 2 == 1 && lscore > y / 6 / 2)
  121. rgb_now <= COLOR_LBAR;
  122. if (x >= 628 && x <= 634)
  123. if (y / 6 % 2 == 1 && rscore > y / 6 / 2)
  124. rgb_now <= COLOR_RBAR;
  125.  
  126. end else begin
  127. // outside of the display area, fill black
  128. rgb_now <= COLOR_NULL;
  129. end
  130. end
  131.  
  132. assign rgb = rgb_now;
  133.  
  134. endmodule

Данный модуль реализует три основных функции, необходимых для реализации нашей игры: опрашивает клавиши управления, реализует логику игры и осуществляет формирование изображения игровых объектов.

Сопоставим выводы нашего проекта, с реальными выходами нашей платы:

Таблица выводов

Для управления игровым процессом, реализуем управление выводами нашего контроллера по USB порту. Для этого в функции инициализации портов static void GPIO_Init() добавим инициализацию битов 7-4 порта D:

C++ Code:
  1. SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK;
  2.  
  3. /* FPGAs port settings */
  4. PORTD_PCR7 = PORT_PCR_MUX(1);
  5. PORTD_PCR6 = PORT_PCR_MUX(1);
  6. PORTD_PCR5 = PORT_PCR_MUX(1);
  7. PORTD_PCR4 = PORT_PCR_MUX(1);
  8.  
  9. GPIOD_PDDR |= (1<<7);
  10. GPIOD_PDDR |= (1<<6);
  11. GPIOD_PDDR |= (1<<5);
  12. GPIOD_PDDR |= (1<<4);

Также изменим функцию обработки принятого USB пакета:

C++ Code:
  1. /******************************************************************************
  2.  *
  3.  * @name Virtual_Com_App
  4.  *
  5.  * @brief Implements Loopback COM Port
  6.  *
  7.  * @param None
  8.  *
  9.  * @return None
  10.  *
  11.  *****************************************************************************
  12.  * Receives data from USB Host and transmits back to the Host
  13.  *****************************************************************************/
  14. static void Virtual_Com_App(void)
  15. {
  16. static uint_8 status = 0;
  17. /* Loopback Application Code */
  18. if(g_recv_size)
  19. {
  20. /* Copy Received Buffer to Send Buffer */
  21. for (status = 0; status < g_recv_size; status++)
  22. {
  23. g_curr_send_buf[0]='С';
  24. g_curr_send_buf[1]='и';
  25. g_curr_send_buf[2]='м';
  26. g_curr_send_buf[3]='в';
  27. g_curr_send_buf[4]='о';
  28. g_curr_send_buf[5]='л';
  29. g_curr_send_buf[6]='=';
  30. g_curr_send_buf[status+7] = g_curr_recv_buf[status];
  31.  
  32. //Управление битом 7 порта D
  33. if(g_curr_recv_buf[0]=='q'){GPIOD_PSOR = 1 << 7;}
  34. else{GPIOD_PCOR = 1 << 7;}
  35. //Управление битом 6 порта D
  36. if(g_curr_recv_buf[0]=='a'){GPIOD_PSOR = 1 << 6;}
  37. else{GPIOD_PCOR = 1 << 6;}
  38. //Управление битом 5 порта D
  39. if(g_curr_recv_buf[0]=='p'){GPIOD_PSOR = 1 << 5;}
  40. else{GPIOD_PCOR = 1 << 5;}
  41. //Управление битом 4 порта D
  42. if(g_curr_recv_buf[0]=='l'){GPIOD_PSOR = 1 << 4;}
  43. else{GPIOD_PCOR = 1 << 4;}
  44.  
  45. }
  46. g_curr_send_buf[status+7]='\r';
  47. g_curr_send_buf[status+8]='\n';
  48.  
  49. g_send_size = g_recv_size+9;
  50. g_recv_size = 0;
  51. }
  52. if(g_send_size)
  53. {
  54. /* Send Data to USB Host*/
  55. uint_8 size = g_send_size;
  56. g_send_size = 0;
  57. status = USB_Class_CDC_Interface_DIC_Send_Data(CONTROLLER_ID,
  58. g_curr_send_buf,size);
  59. if(status != USB_OK)
  60. {
  61. /* Send Data Error Handling Code goes here */
  62. }
  63. }
  64.  
  65. return;
  66. }

Как не трудно догадаться, теперь для управления нашей игрой используются клавиши q,a,p,l. Ну и по традиции видео и исходники:

Проект игры PONG для FPGA: pong_game.zip

Проект управление по USB для микроконтроллера: usb_mk20_rom.zip

Добавить комментарий