MIPSfpgaプロジェクトの移植について





あるコンピューターアーキテクチャから別のコンピューターアーキテクチャにソフトウェアを転送することは、原則として、ある程度の予約があれば比較的簡単です。 autoconf / automake / libtool / gnulibのような有名なツールがここで助けになります。 Raspberry / ARMのソースからプログラムをコンパイルするのは、Ubuntu / x86-64を搭載したPCと同じくらい簡単です。



しかし、あるボード用に設計されたFPGAプロジェクトを別のボードで動作させるにはどうすればよいでしょうか? そこでは、FPGA自体が異なる場合があり、完全に異なるコンポーネントをボード上に配置できます。 プロジェクトの単純な再コンパイルは不可欠です。



インテルMAX10 FPGAを使用したMars rover3ボード用のMIPSfpgaプロジェクトの移植における私の経験についてお話しします。 MIPSfpgaプロジェクトに関する記事がハブに繰り返し登場しました 彼らはとても面白かったので、このプロジェクトを既存のボードで自分で試してみたかったのです。 私の仕事では、ハブロフスクの記事に依存していました





そして、他の多くの...



それでは、FPGAプロジェクトを別のボードに移植するには何をする必要がありますか?



1)プロジェクトで使用されるFPGAのタイプを再割り当てする必要があります



元のプロジェクトがマザーボードとまったく同じFPGAチップに焦点を合わせていれば幸運です。 MIPSfpgaプロジェクトは、ザイリンクスFPGAおよびIntel / Altera FPGAボードを搭載したマザーボードを含む、さまざまなメーカーのマザーボードに既に移植されています。 それにもかかわらず、私は「運が悪い」と言ってみましょう。 はい、DE10-liteボード用のプロジェクトがあり、私のボードのようにMAX10 FPGAを使用します。 しかし、これはまったく異なるMAX10です。DE10-liteには10M50DAF484C7Gがかかり、Mars rover3ボードにはFPGA MAX1050SAE144C8があります。 両方のチップには5万個の論理ゲートがありますが、最初のチップにははるかに多くの入出力信号があります。 FPGAチップのタイプの再割り当てとともに、チップの特定のピンへのすべての信号の割り当てが「飛ぶ」ことは明らかです。







Intel Quartus CAD環境で使用されるチップのタイプは、[デバイス]ダイアログボックスの[割り当て] => [デバイス]メニューで割り当てられます。



ここには[デバイスとピンのオプション]ボタンもあります。次のダイアログボックスに移動し、プロジェクト内の未使用のピンを入力トライステートにする必要があることをすぐに示すことを強くお勧めします。







ボードがあまり馴染みがない場合、たとえば、回路を十分に検討していない場合は、ボードの回路から未使用のFPGAの結論を切り離した方が良いでしょう。



2)入力と出力に新しい割り当てを行う



超小型回路のタイプが再割り当てされたため、FPGAプロジェクトの特定の信号にどの入力/出力を使用するかを指定する必要があります。 各FPGAプロジェクトには、最高レベルのモジュールがあります。 このモジュールの信号は、FPGAチップの端子に接続され、プロジェクト設定で指定された端子を使用します。



ここで、たとえば私のプロジェクトでは:



module m3 ( input MAX10_CLK_100, input [ 1:0] KEY, output [ 7:0] LEDR, input wire FTDI_RX, output wire FTDI_TX, inout wire [7:0]FTD, `ifdef MFP_USE_SDRAM_MEMORY output [11:0] DRAM_ADDR, output [ 1:0] DRAM_BA, output DRAM_CAS_N, //output DRAM_CKE, output DRAM_CLK, //output DRAM_CS_N, inout [15:0] DRAM_DQ, output DRAM_LDQM, output DRAM_RAS_N, output DRAM_UDQM, output DRAM_WE_N, `endif `ifdef UNUSED input ADC_CLK_10, input MAX10_CLK1_50, input MAX10_CLK2_50, input [ 9:0] SW, output [ 7:0] HEX0, output [ 7:0] HEX1, output [ 7:0] HEX2, output [ 7:0] HEX3, output [ 7:0] HEX4, output [ 7:0] HEX5, output [ 3:0] VGA_B, output [ 3:0] VGA_G, output VGA_HS, output [ 3:0] VGA_R, output VGA_VS, output GSENSOR_CS_N, input [ 2:1] GSENSOR_INT, output GSENSOR_SCLK, inout GSENSOR_SDI, inout GSENSOR_SDO, inout [15:0] ARDUINO_IO, inout ARDUINO_RESET_N, inout [35:0] GPIO, `endif inout [15:0] GPIO, //HDMI output output wire [7:0]TMDS );
      
      





Mars rover3ボードには、SWスイッチも、7セグメントインジケータHEX0..HEX5も、VGAコネクタもありません。 これらの信号をプロジェクトから直接削除しませんでしたが、「if UNUSED ...」endifコンストラクトを使用した条件付きコンパイルによって削除しました。 Mars rover3ボードにはLED、ボタン、FTDI信号、さらにはHDMI信号さえあります。これらは私のプロジェクトにあります。







Quartus環境では、Assigments => Assignment Editorメニューを使用して、チップの連絡先番号に対応する信号を設定する必要があります。 もちろん、これは回路基板の回路図に従って行わなければなりません。 超小型回路のピン番号を指定することに加えて、必要に応じて、I / O標準やプルアップ抵抗などの他の予約が必要になる場合があります。



3)クロック周波数への注意



元のプロジェクトは、水晶発電機の公称値が当社のボードと同じではないボード用に作成された可能性があります。 そして、私の場合は判明しました。 DE10-liteボードには50MHzの発振器があり、私のボードは100MHzです。 このプロジェクトのPLLモジュールインスタンスを再作成する必要があります。 quartusメニューで、[Tools] => [IP Catalog]を選択します。そこには、インストール済みIPの中に[= Librarys]、[Basic Functions] => [Clocks]があります。 PLLおよびリセット=> PLL => ALTPLLを選択し、ウィザードを実行します。







正しいソース周波数を指定し、PLLで目的の出力周波数を設定する必要があります。 考慮すべき多くの要因があります。 元のプロジェクトにはなかったHDMIディスプレイへの出力をプロジェクトに追加することにしました。つまり、TMDSビデオ信号(74 MHzおよび370 MHz)を直接生成するために必要な追加の周波数が必要でした。



次に、作成したPLLコンポーネントのバリエーションをプロジェクトに挿入する必要があります。



4)機能をトリミングまたは拡張しますか?



FPGAプロジェクトを他のボードに移植する場合、プロジェクトを1対1で繰り返すことができないという事実にしばしば遭遇します。 最も単純な理由は、たとえば、元のプロジェクトが16個のLEDおよび/または7セグメントインジケーターを備えたボード用に作成されたが、たとえば、ボード上にはまったくないか、LEDがありますが、16個ではなく、8個しかありません。 または、ボード上に異なる量のRAMまたはフラッシュがあります...ここで何かを考え出す必要があり、何らかの形で制限を回避します。



MIPSfpgaプロジェクトのトレーニングと情報の表示は何らかの形で行う必要があるため、そうしないと「プロジェクトの可視性」が失われるため、モニターに情報を表示することにしました。



この目的のために、Verilogで仮想LEDと7セグメントインジケーターのモジュールを作成しました。



ここにモジュールテキスト全体を記載します。



仮想LEDおよびインジケータモジュール
 //marsohod3 board has only 8 yellow LEDs //but sample MIPS needs red/green LEDs and 7-segment indicators //so try display LEDs and 7-segment info on HDMI output of Marsohod3 board module display ( input wire reset, input wire clk_video, //74MHz input wire clk_hdmi, //370MHz input wire [NUM_RED_LEDS-1:0]red_leds, input wire [NUM_GREEN_LEDS-1:0]green_leds, input wire [NUM_SEGMENTS*4-1:0]segments, //HDMI output output wire [7:0]TMDS ); parameter NUM_RED_LEDS = 16; parameter NUM_GREEN_LEDS = 16; parameter NUM_SEGMENTS = 6; wire w_hsync; wire w_vsync; wire w_active; wire [11:0]w_pixel_count; wire [11:0]w_line_count; wire w_video_clk5; assign w_video_clk5 = clk_hdmi; wire w_video_clk; assign w_video_clk = clk_video; hvsync u_hvsync( .reset( reset ), .pixel_clock( w_video_clk ), .hsync(w_hsync), .vsync(w_vsync), .active(w_active), .pixel_count(w_pixel_count), .line_count(w_line_count), .dbg( ) ); reg d_active; reg r_hsync; reg r_vsync; reg r_vsync_; reg [NUM_RED_LEDS-1:0]red_leds_fixed; reg [NUM_GREEN_LEDS-1:0]green_leds_fixed; reg [NUM_SEGMENTS*4-1:0]segments_fixed; always @(posedge w_video_clk) begin r_hsync <= w_hsync; r_vsync <= w_vsync; r_vsync_ <= r_vsync; d_active <= w_active; if( r_vsync_==1'b0 && r_vsync==1'b1 ) begin red_leds_fixed <= red_leds; green_leds_fixed <= green_leds; segments_fixed <= segments; end end reg [9:0]red_word; reg [9:0]green_word; reg [9:0]blue_word; wire led_visible; assign led_visible = w_pixel_count<512 && w_pixel_count[4]==1'b1; wire [3:0]led_idx; assign led_idx = NUM_RED_LEDS-1-w_pixel_count[8:5]; wire current_green_led = (green_leds_fixed >> led_idx)&1; wire current_red_led = (red_leds_fixed >> led_idx)&1; wire h_seg_line5; assign h_seg_line5 = w_pixel_count<(64*1-8) && w_pixel_count>(64*0+32); wire h_seg_line4; assign h_seg_line4 = w_pixel_count<(64*2-8) && w_pixel_count>(64*1+32); wire h_seg_line3; assign h_seg_line3 = w_pixel_count<(64*3-8) && w_pixel_count>(64*2+32); wire h_seg_line2; assign h_seg_line2 = w_pixel_count<(64*4-8) && w_pixel_count>(64*3+32); wire h_seg_line1; assign h_seg_line1 = w_pixel_count<(64*5-8) && w_pixel_count>(64*4+32); wire h_seg_line0; assign h_seg_line0 = w_pixel_count<(64*6-8) && w_pixel_count>(64*5+32); wire vl_seg_line5; assign vl_seg_line5 = w_pixel_count<(64*1-32) && w_pixel_count>(64*0+24); wire vl_seg_line4; assign vl_seg_line4 = w_pixel_count<(64*2-32) && w_pixel_count>(64*1+24); wire vl_seg_line3; assign vl_seg_line3 = w_pixel_count<(64*3-32) && w_pixel_count>(64*2+24); wire vl_seg_line2; assign vl_seg_line2 = w_pixel_count<(64*4-32) && w_pixel_count>(64*3+24); wire vl_seg_line1; assign vl_seg_line1 = w_pixel_count<(64*5-32) && w_pixel_count>(64*4+24); wire vl_seg_line0; assign vl_seg_line0 = w_pixel_count<(64*6-32) && w_pixel_count>(64*5+24); wire vr_seg_line5; assign vr_seg_line5 = w_pixel_count<(64*1) && w_pixel_count>(64*0+56); wire vr_seg_line4; assign vr_seg_line4 = w_pixel_count<(64*2) && w_pixel_count>(64*1+56); wire vr_seg_line3; assign vr_seg_line3 = w_pixel_count<(64*3) && w_pixel_count>(64*2+56); wire vr_seg_line2; assign vr_seg_line2 = w_pixel_count<(64*4) && w_pixel_count>(64*3+56); wire vr_seg_line1; assign vr_seg_line1 = w_pixel_count<(64*5) && w_pixel_count>(64*4+56); wire vr_seg_line0; assign vr_seg_line0 = w_pixel_count<(64*6) && w_pixel_count>(64*5+56); function [7:0]seg7; input [3:0]a; begin case(a) 0: seg7 = 63; 1: seg7 = 6; 2: seg7 = 91; 3: seg7 = 79; 4: seg7 = 102; 5: seg7 = 109; 6: seg7 = 125; 7: seg7 = 7; 8: seg7 = 127; 9: seg7 = 111; 10: seg7 = 119; 11: seg7 = 124; 12: seg7 = 57; 13: seg7 = 94; 14: seg7 = 121; 15: seg7 = 113; endcase end endfunction reg [6:0]seg7_0; reg [6:0]seg7_1; reg [6:0]seg7_2; reg [6:0]seg7_3; reg [6:0]seg7_4; reg [6:0]seg7_5; always @(posedge clk_video) begin seg7_0 <= seg7( segments_fixed[ 3: 0] ); seg7_1 <= seg7( segments_fixed[ 7: 4] ); seg7_2 <= seg7( segments_fixed[11: 8] ); seg7_3 <= seg7( segments_fixed[15:12] ); seg7_4 <= seg7( segments_fixed[19:16] ); seg7_5 <= seg7( segments_fixed[23:20] ); end reg [2:0]color; always @* begin if( w_line_count>64 && w_line_count<80 ) begin //green led line if(led_visible) color = current_green_led ? 1 : 2; else color=0; end else if( w_line_count>96 && w_line_count<112 ) begin //red led line if(led_visible) color = current_red_led ? 3 : 4; else color=0; end else if( w_line_count>118+32 && w_line_count<126+32 ) begin // 7seg top line if(h_seg_line0) color = seg7_0[0] ? 5 : 6; else if(h_seg_line1) color = seg7_1[0] ? 5 : 6; else if(h_seg_line2) color = seg7_2[0] ? 5 : 6; else if(h_seg_line3) color = seg7_3[0] ? 5 : 6; else if(h_seg_line4) color = seg7_4[0] ? 5 : 6; else if(h_seg_line5) color = seg7_5[0] ? 5 : 6; else color=0; end else if( w_line_count>126+32 && w_line_count<148+32 ) begin if(vr_seg_line0) color = seg7_0[1] ? 5 : 6; else if(vr_seg_line1) color = seg7_1[1] ? 5 : 6; else if(vr_seg_line2) color = seg7_2[1] ? 5 : 6; else if(vr_seg_line3) color = seg7_3[1] ? 5 : 6; else if(vr_seg_line4) color = seg7_4[1] ? 5 : 6; else if(vr_seg_line5) color = seg7_5[1] ? 5 : 6; else if(vl_seg_line0) color = seg7_0[5] ? 5 : 6; else if(vl_seg_line1) color = seg7_1[5] ? 5 : 6; else if(vl_seg_line2) color = seg7_2[5] ? 5 : 6; else if(vl_seg_line3) color = seg7_3[5] ? 5 : 6; else if(vl_seg_line4) color = seg7_4[5] ? 5 : 6; else if(vl_seg_line5) color = seg7_5[5] ? 5 : 6; else color=0; end else if( w_line_count>148+32 && w_line_count<156+32 ) begin // 7seg middle line if(h_seg_line0) color = seg7_0[6] ? 5 : 6; else if(h_seg_line1) color = seg7_1[6] ? 5 : 6; else if(h_seg_line2) color = seg7_2[6] ? 5 : 6; else if(h_seg_line3) color = seg7_3[6] ? 5 : 6; else if(h_seg_line4) color = seg7_4[6] ? 5 : 6; else if(h_seg_line5) color = seg7_5[6] ? 5 : 6; else color=0; end else if( w_line_count>156+32 && w_line_count<180+32 ) begin if(vr_seg_line0) color = seg7_0[2] ? 5 : 6; else if(vr_seg_line1) color = seg7_1[2] ? 5 : 6; else if(vr_seg_line2) color = seg7_2[2] ? 5 : 6; else if(vr_seg_line3) color = seg7_3[2] ? 5 : 6; else if(vr_seg_line4) color = seg7_4[2] ? 5 : 6; else if(vr_seg_line5) color = seg7_5[2] ? 5 : 6; else if(vl_seg_line0) color = seg7_0[4] ? 5 : 6; else if(vl_seg_line1) color = seg7_1[4] ? 5 : 6; else if(vl_seg_line2) color = seg7_2[4] ? 5 : 6; else if(vl_seg_line3) color = seg7_3[4] ? 5 : 6; else if(vl_seg_line4) color = seg7_4[4] ? 5 : 6; else if(vl_seg_line5) color = seg7_5[4] ? 5 : 6; else color=0; end else if( w_line_count>180+32 && w_line_count<188+32 ) begin // 7seg bottom line if(h_seg_line0) color = seg7_0[3] ? 5 : 6; else if(h_seg_line1) color = seg7_1[3] ? 5 : 6; else if(h_seg_line2) color = seg7_2[3] ? 5 : 6; else if(h_seg_line3) color = seg7_3[3] ? 5 : 6; else if(h_seg_line4) color = seg7_4[3] ? 5 : 6; else if(h_seg_line5) color = seg7_5[3] ? 5 : 6; else color=0; end else color=0; end reg [2:0]color_fixed; always @(posedge clk_video) color_fixed<=color; always @* begin case(color_fixed) 0: begin //gray red_word = 10'b0000011111; green_word = 10'b0000011111; blue_word = 10'b0000111111; end 1: begin //bright green red_word = 10'b0000011111; green_word = 10'b1111111111; blue_word = 10'b0000011111; end 2: begin //dark green red_word = 10'b0000011111; green_word = 10'b0000111111; blue_word = 10'b0000011111; end 3: begin //bright red red_word = 10'b1111111111; green_word = 10'b0000011111; blue_word = 10'b0000011111; end 4: begin //dark red red_word = 10'b0000111111; green_word = 10'b0000011111; blue_word = 10'b0000011111; end 5: begin //bright yellow red_word = 10'b1111111111; green_word = 10'b1111111111; blue_word = 10'b0000011111; end 6: begin //dark yellow red_word = 10'b0000111111; green_word = 10'b0000111111; blue_word = 10'b0000011111; end 7: begin //gray red_word = 10'b0000011111; green_word = 10'b0000011111; blue_word = 10'b0000111111; end endcase end wire w_tmds_bh; wire w_tmds_bl; wire w_tmds_gh; wire w_tmds_gl; wire w_tmds_rh; wire w_tmds_rl; hdmi u_hdmi( .pixclk( w_video_clk ), .clk_TMDS2( w_video_clk5 ), .hsync( r_hsync ), .vsync( r_vsync ), .active( d_active ), .red( red_word ), .green( green_word ), .blue( blue_word ), .TMDS_bh( w_tmds_bh ), .TMDS_bl( w_tmds_bl ), .TMDS_gh( w_tmds_gh ), .TMDS_gl( w_tmds_gl ), .TMDS_rh( w_tmds_rh ), .TMDS_rl( w_tmds_rl ) ); altddio_out1 u_ddio1( .datain_h( w_video_clk), .datain_l( w_video_clk), .outclock(w_video_clk5), .dataout( TMDS[1] ) ); altddio_out1 u_ddio0( .datain_h(~w_video_clk), .datain_l(~w_video_clk), .outclock(w_video_clk5), .dataout( TMDS[0] ) ); altddio_out1 u_ddio3( .datain_h( w_tmds_bh), .datain_l( w_tmds_bl), .outclock(w_video_clk5), .dataout( TMDS[3] ) ); altddio_out1 u_ddio2( .datain_h(~w_tmds_bh), .datain_l(~w_tmds_bl), .outclock(w_video_clk5), .dataout( TMDS[2] ) ); altddio_out1 u_ddio5( .datain_h( w_tmds_gh), .datain_l( w_tmds_gl), .outclock(w_video_clk5), .dataout( TMDS[5] ) ); altddio_out1 u_ddio4( .datain_h(~w_tmds_gh), .datain_l(~w_tmds_gl), .outclock(w_video_clk5), .dataout( TMDS[4] ) ); altddio_out1 u_ddio7( .datain_h( w_tmds_rh), .datain_l( w_tmds_rl), .outclock(w_video_clk5), .dataout( TMDS[7] ) ); altddio_out1 u_ddio6( .datain_h(~w_tmds_rh), .datain_l(~w_tmds_rl), .outclock(w_video_clk5), .dataout( TMDS[6] ) ); endmodule
      
      





以下に、Mars rover3ボードのプロジェクトソースコード全体を示します。これは、仮想LED上のバイナリカウンターの表示を示しています。



そして、ここに彼のビデオデモがあります。





それはかなりいい結果になったように思えます。



このように、物理的に32個のLEDがなく、7個のセグメントインジケーターがないボードに移植する場合、仮想LEDと7セグメントインジケーターの助けを借りて、MIPSfpgaプロジェクトの大部分を節約できました。



次に、MIPSfpgaプロジェクトがボードにロードされる方法を示します。





このビデオデモでは、Quartus Prime CAD環境のラップトップからFPGAボードをロードする方法と、FPGAをロードした直後に、接続されたHDMIモニターが同期を受信する方法を示します。 次に、カウンターテストプログラムがラップトップでコンパイルされ、ボードにロードされて、FPGAのMIPSプロセッサーで起動されます。



MIPSのサンプルプログラムは次のとおりです。





  1. メモリテストプログラム04_memtestが起動し、
  2. MIPSfpga SoCおよびPCからのシリアルポート用の05_uart通信プログラムを検討しています。
  3. プログラム06_timer_irqは、ハードウェア割り込みを使用して動作します
  4. 09_adc_0は、FPGA MAX10 ADCに組み込まれたテストプログラムです。


また、外部MBFTDIプログラマーとOpenOCDおよびGDBプログラムを使用して、MIPSプログラムのインサーキットデバッグを実行する方法も示したいと思います。





Mars rover3ボードのMIPSfpgaプロジェクトの詳細については、 こちらをご覧ください



結論として、 MIPSfpgaに関する素晴らしい一連の記事について、 SparFYuriPanchulFrantonyに感謝します。 これらの記事がなければ、これは私の仕事ではなかったでしょう。



All Articles