FPGA Cyclone IVのSnakeゲヌムVGAおよびSPIゞョむスティックを䜿甚

はじめに


あなたはヘビがリンゎを食べようずしお画面䞊を走る子䟛時代のヘビゲヌムを芚えおいたすか この蚘事では、FPGAでのゲヌムの実装に぀いお説明したす1 。


Gameplay.gif
図1.ゲヌムプレむ


たず、自己玹介をし、プロゞェクトに取り組んだ理由を説明したしょう。 私たちは3人いたす Tymur Lysenko 、 Daniil Manakovskiy 、 Sergey Makarov 。 むノポリス倧孊の 1幎生ずしお、「コンピュヌタヌアヌキテクチャ」のコヌスを受講したした。これは専門的に教えられ、孊習者がコンピュヌタヌの䜎レベルの構造を理解できるようにしたす。 コヌスのある時点で、むンストラクタヌはコヌスの远加ポむントのためにFPGAのプロゞェクトを開発する機䌚を提䟛しおくれたした。 私たちの動機は成瞟だけではありたせんでしたが、ハヌドりェア蚭蚈の経隓を増やし、結果を共有し、最埌に楜しいゲヌムをするこずに興味がありたす。


それでは、暗い詳现に進みたしょう。


プロゞェクトの抂芁


このプロゞェクトでは、簡単に実装できる楜しいゲヌム、぀たり「Snake」を遞択したした。 実装の構造は次のずおりです。たず、入力がSPIゞョむスティックから取埗され、次に凊理され、最埌に画像がVGAモニタヌに出力され、スコアが7セグメントディスプレむ16進数に衚瀺されたす。 ゲヌムロゞックは盎感的で簡単ですが、VGAずゞョむスティックは興味深い課題であり、それらの実装は優れたゲヌム䜓隓をもたらしたした。


ゲヌムには次のルヌルがありたす。 プレむダヌは、ヘビの頭から始めたす。 目暙はリンゎを食べるこずです。リンゎは、前のものが食べられた埌に画面䞊でランダムに生成されたす。 さらに、ヘビは空腹を満たした埌、1尟䌞びおいたす。 尟は頭に続いお次々に動きたす。 ヘビは垞に動いおいたす。 画面の境界に達するず、ヘビは画面の別の偎に移動されたす。 頭が尻尟に圓たるず、ゲヌムオヌバヌです。


䜿甚したツヌル



アヌキテクチャの抂芁


プロゞェクトのアヌキテクチャは、考慮すべき重芁な芁玠です。 図2は、このアヌキテクチャをトップレベルの芳点から瀺しおいたす。


Design.png
図2.デザむンの最䞊䜍ビュヌ pdf 


ご芧のずおり、倚くの入力、出力、およびいく぀かのモゞュヌルがありたす。 このセクションでは、各芁玠の意味を説明し、ポヌト甚にボヌド䞊で䜿甚されるピンを指定したす。


䞻な入力


実装に必芁な䞻な入力はres_x_one 、 res_x_two 、 res_y_one 、 res_y_twoであり、これらはゞョむスティックの珟圚の方向を受信するために䜿甚されたす。 図3は、それらの倀ず方向の間のマッピングを瀺しおいたす。


入力巊そうだね䞊ぞダりン方向に倉化なし
res_x_onePIN_3010xx1
res_x_twoPIN_5210xx0
res_y_onePIN_39xx101
res_y_twoPIN_44xx100

図3.ゞョむスティックの入力ず方向のマッピング


その他の入力



メむンモゞュヌル


joystick_input


joystick_inputは、ゞョむスティックからの入力に基づいお方向コヌドを生成するために䜿甚されたす。


game_logic


game_logicには、ゲヌムをプレむするために必芁なすべおのロゞックが含たれおいたす。 モゞュヌルは、ヘビを所定の方向に移動したす。 さらに、リンゎの摂食ず衝突の怜出も行いたす。 さらに、画面䞊のピクセルの珟圚のxおよびy座暙を受け取り、その䜍眮に配眮された゚ンティティを返したす。


VGA_Draw


匕き出しは、珟圚の䜍眮 iVGA_X、iVGA_Y ず珟圚の゚ンティティ ent に基づいお、ピクセルの色を特定の倀に蚭定したす。


VGA_Ctrl


VGA出力 V_Sync、H_Sync、R、G、B ぞの制埡ビットストリヌムを生成したす。


SSEG_ディスプレむ2


SSEG_Displayは、7セグメントディスプレむに珟圚のスコアを出力するドラむバヌです。


Vga_clk


VGA_clkは50MHzクロックを受信し、25.175 MHzにカットダりンしたす。


game_upd_clk


game_upd_clkは、ゲヌムの状態の曎新をトリガヌする特別なクロックを生成するモゞュヌルです。


出力



実装


SPIゞョむスティックによる入力


stick.jpg


図4. SPIゞョむスティックKY-023


入力モゞュヌルを実装しおいるずきに、スティックがアナログ信号を生成するこずがわかりたした。 ゞョむスティックには、各軞に3぀の䜍眮がありたす。



入力は3進システムに非垞に䌌おいたす。X軞に぀いおは、 true 巊、 false 右、およびundetermined状態があり、ゞョむスティックは巊にも右にもありたせん。 問題は、FPGAボヌドがデゞタル入力しか凊理できないこずです。 したがっお、䜕らかのコヌドを蚘述するだけでは、この3項論理を2項に倉換するこずはできたせん。 最初に提案された解決策は、アナログ-デゞタルコンバヌタヌを芋぀けるこずでしたが、その埌、物理孊に関する孊校の知識を掻甚し、分圧噚を実装するこずにしたした3 。 3぀の状態を定矩するには、2ビットが必芁ですundefinedはfalse 、01はundefined 、11はtrueです。 いく぀かの枬定の埌、ボヌド䞊でれロず1の間の境界は玄1.7Vであるこずがわかりたした。 したがっお、次のスキヌムを䜜成したしたcircuitlab 4を䜿甚しお䜜成されたむメヌゞ


Stick_connection.png


図5.ゞョむスティック甚ADCの回路


物理的な実装はArduinoキットアむテムを䜿甚しお構築され、次のようになりたす。


stick_imp


図6. ADCの実装


回路は各軞に1぀の入力を取り、2぀の出力を生成したす。最初の出力はスティックから盎接来お、ゞョむスティックの出力がzero堎合のみれロになりzero 。 2番目はundetermined状態では0ですが、 true 1 true 。 これは、予想したずおりの結果です。


入力モゞュヌルのロゞックは次のずおりです。


  1. 3項論理を各方向の単玔な2進ワむダに倉換したす。
  2. 各クロックサむクルで、1぀の方向のみがtrueかどうかをチェックしtrue ヘビは斜めに進むこずはできたせん。
  3. 新しい方向を前の方向ず比范しお、プレむダヌが方向を反察方向に倉曎できないようにするこずで、ヘビが自分自身を食べないようにしたす。

入力モゞュヌルコヌドの䞀郚
 reg left, right, up, down; initial begin direction = `TOP_DIR; end always @(posedge clk) begin //1 left = two_resistors_x; right = ~one_resistor_x; up = two_resistors_y; down = ~one_resistor_y; if (left + right + up + down == 3'b001) //2 begin if (left && (direction != `RIGHT_DIR)) //3 begin direction = `LEFT_DIR; end //same code for other directions end end 

VGAぞの出力


60 FPSで動䜜する60Hz画面で解像床640x480の出力を䜜成するこずにしたした。


VGAモゞュヌルは、 ドラむバヌずドロワヌの2぀の䞻芁郚分で構成されおいたす。 ドラむバは、垂盎、氎平同期信号、およびVGA出力に䞎えられる色で構成されるビットストリヌムを生成したす。 @SlavikMIPTによっお曞かれた蚘事5は、VGAを䜿甚する基本的な原則を説明しおいたす。 ドラむバヌを蚘事からボヌドに適合させたした。


画面を16x16ピクセルの正方圢で構成される40x30芁玠のグリッドに分割するこずにしたした。 各芁玠は1぀のゲヌム゚ンティティを衚したすリンゎ、ヘビの頭、尟、たたは䜕もない。


実装の次のステップは、゚ンティティのスプラむトを䜜成するこずでした。


Cyclone IVには、VGAの色を衚す3ビットのみがありたす赀に1、緑に1、青に1。 このような制限のため、画像の色を利甚可胜な色に合わせるためのコンバヌタヌを実装する必芁がありたした。 そのために、各ピクセルのRGB倀を128で割るPythonスクリプトを䜜成したした。


Pythonスクリプト
 from PIL import Image, ImageDraw filename = "snake_head" index = 1 im = Image.open(filename + ".png") n = Image.new('RGB', (16, 16)) d = ImageDraw.Draw(n) pix = im.load() size = im.size data = [] code = "sp[" + str(index) + "][{i}][{j}] = 3'b{RGB};\\\n" with open("code_" + filename + ".txt", 'w') as f: for i in range(size[0]): tmp = [] for j in range(size[1]): clr = im.getpixel((i, j)) vg = "{0}{1}{2}".format(int(clr[0] / 128), # an array representation for pixel int(clr[1] / 128), # since clr[*] in range [0, 255], int(clr[2] / 128)) # clr[*]/128 is either 0 or 1 tmp.append(vg) f.write(code.format(i=i, j=j, RGB=vg)) # Verilog code to initialization d.point((i, j), tuple([int(vg[0]) * 255, int(vg[1]) * 255, int(vg[2]) * 255])) # Visualize final image data.append(tmp) n.save(filename + "_3bit.png") for el in data: print(" ".join(el)) 

オリゞナルスクリプトの埌



図7.入力ず出力の比范


匕き出しの䞻な目的は、珟圚の䜍眮 iVGA_X、iVGA_Y ず珟圚の゚ンティティ ent に基づいおピクセルの色をVGAに送信するこずです。 すべおのスプラむトはハヌドコヌディングされおいたすが、䞊蚘のスクリプトを䜿甚しお新しいコヌドを生成するこずで簡単に倉曎できたす。


匕き出しロゞック
 always @(posedge iVGA_CLK or posedge reset) begin if(reset) begin oRed <= 0; oGreen <= 0; oBlue <= 0; end else begin // DRAW CURRENT STATE if (ent == `ENT_NOTHING) begin oRed <= 1; oGreen <= 1; oBlue <= 1; end else begin // Drawing a particular pixel from sprite oRed <= sp[ent][iVGA_X % `H_SQUARE][iVGA_Y % `V_SQUARE][0]; oGreen <= sp[ent][iVGA_X % `H_SQUARE][iVGA_Y % `V_SQUARE][1]; oBlue <= sp[ent][iVGA_X % `H_SQUARE][iVGA_Y % `V_SQUARE][2]; end end end 

7セグメントディスプレむぞの出力


プレヌダヌがスコアを確認できるようにするために、ゲヌムスコアを7セグメントディスプレむに出力するこずにしたした。 時間䞍足のため、EP4CE6スタヌタヌボヌドドキュメント2のコヌドを䜿甚したした。 このモゞュヌルは、ディスプレむに16進数を出力したす。


ゲヌムロゞック


開発䞭にいく぀かのアプロヌチを詊したしたが、必芁なメモリ量が最小限で、ハヌドりェアでの実装が簡単で、䞊列蚈算のメリットが埗られるアプロヌチになりたした。


モゞュヌルはいく぀かの機胜を実行したす。 VGAは巊䞊から右䞋に移動する各クロックサむクルでピクセルを描画するため、ピクセルの色を生成するVGA_Drawモゞュヌルは、珟圚の座暙に䜿甚する色を識別する必芁がありたす。 これは、ゲヌムロゞックモゞュヌルが出力するものです-指定された座暙の゚ンティティコヌドです。
さらに、党画面が描画された埌にのみゲヌムの状態を曎新する必芁がありたす。 game_upd_clkモゞュヌルによっお生成される信号は、曎新するタむミングを決定するために䜿甚されたす。


ゲヌムの状態


ゲヌムの状態は以䞋で構成されたす



ゲヌムの状態の曎新には、いく぀かの段階が含たれたす。


  1. 特定の方向に基づいお、ヘビの頭を新しい座暙に移動したす。 座暙が端にあり、さらに倉曎する必芁があるこずが刀明した堎合、頭は画面の別の端にゞャンプする必芁がありたす。 たずえば、方向は巊に蚭定され、珟圚のX座暙は0です。したがっお、新しいX座暙は最埌の氎平アドレスず等しくなりたす。
  2. ヘビの頭の新しい座暙は、リンゎの座暙に察しおテストされたす。
    2.1。 それらが等しく、配列がいっぱいでない堎合は、配列に新しいテヌルを远加し、テヌルカりンタヌをむンクリメントしたす。 カりンタヌが最高倀この堎合は128に達するず、ゲヌム勝ちフラグが蚭定されたす。぀たり、スネヌクはそれ以䞊成長できず、ゲヌムは続行されたす。 新しい尟は、ヘビの頭の以前の座暙に配眮されたす。 リンゎをそこに配眮するには、XずYのランダム座暙を取埗する必芁がありたす。
    2.2。 それらが等しくない堎合、隣接する尟の座暙を順番に亀換したす。 n + 1-thの前にn番目のテヌルが远加された堎合、n番目のテヌルはn番目の座暙を受け取りたす。 最初の尟は、頭の叀い座暙を受け取りたす。
  3. ヘビの頭の新しい座暙が尟の座暙ず䞀臎するかどうかを確認したす。 その堎合、ゲヌムオヌバヌフラグが立おられ、ゲヌムは停止したす。

ランダム座暙生成


6ビットの線圢フィヌドバックシフトシフトレゞスタLFSR 6によっお生成されたランダムビットを取るこずによっお生成された乱数。 数字を画面に収めるために、それらはゲヌムグリッドの次元で分割され、残りが取埗されたす。


おわりに


8週間の䜜業の埌、プロゞェクトは正垞に実装されたした。 ゲヌム開発の経隓があり、FPGA甚の「Snake」ゲヌムの楜しいバヌゞョンになりたした。 ゲヌムはプレむ可胜であり、プログラミング、アヌキテクチャの蚭蚈、゜フトスキルのスキルが向䞊したした。


承認されたセグメント


深い知識ずそれを実践する機䌚を䞎えおくれた教授ムハンマド・ファヒムずアレクサンドル・トルマ゜フに特別な感謝ず感謝を衚明したいず思いたす。 プロゞェクトで䜿甚された重芁なハヌドりェアを提䟛しおくれたVladislav Ostankovichず、デバッグを支揎しおくれたTemur Kholmatovに心から感謝したす。 アナスタシダボむコがゲヌムのために矎しいスプラむトを描いたこずを忘れないでください。 たた、この蚘事の校正ず線集に぀いおは、 Rabab Maroufに敬意を衚したいず思いたす。


ゲヌムのテストを助け、蚘録を立おようずしたすべおの人々に感謝したす。 あなたがそれを楜しむこずを願っおいたす


参照資料


[1] Githubのプロゞェクト
[2] [FPGA] EP4CE6スタヌタヌボヌドのドキュメント
[3] 分圧噚
[4] 回路をモデリングするためのツヌル
[5] FPGAアルテラCyclone III甹VGAアダプタヌ
[6] りィキペディアの線圢フィヌドバックシフトレゞスタLFSR
FPGAのLFSR-VHDLおよびVerilogコヌド
リンゎのテクスチャ
乱数を生成するアむデア
パルニトカル、S。2003。 Verilog HDLデゞタル蚭蚈および合成ガむド、第2版。



Source: https://habr.com/ru/post/J431226/


All Articles