福野泰介の一日一創 - create every day

Macで開発、FPGAで作る4bit学習用CPU「GMC-4」 - Parallels x Ubuntu x Quartus x Verilog

2018/09/26
#FPGA #maker #Verilog 

Intel/ALTERAのFPGA開発環境「Quartus」は、Windows/Linux対応、Mac非対応。
でも、仮想環境 Parallels Desktop を使えば、Mac上でLinuxが動かし、開発できます。
以前はIchigoJamで作った学習用4bitCPU「GMC-4」を、今度はハードウェアで実現!

50MHzで動作する4bitマイコン「GMC-4 - Vol.24 4ビットマイコン | 大人の科学マガジン | 大人の科学.net
音やウェイトは未実装。次は、回路シミュレーターで遊んでみる予定。

MacでFPGA開発する手順 (GMC-4)
1. Parallels Desktop を Mac にインストール(Windowsを使わなければ無料版のLiteでOK)
2. Parallelsのインストールアシスタントで、Ubuntu Linuxを選ぶだけで簡単インストール
3. MacのファイルシステムをUbuntuと共有設定する
4. 仮想環境で使うメモリを1GBから4GBに変更する(Quratusのインストールで落ちた)
5. Quartus Prime Lite をUbuntuでセットアップする(要、ユーザー登録)
6. 書き込み器「USB Blaster」が使えるように設定して、Ubuntuを再起動(末尾に設定方法)
7. VerilogでGMC-4を作り、ピン設定する
8. コンパイル(MacBook Pro 2.3GHz Intel Core i5で、論理合成40秒、Windows環境でもほぼ同じ時間)
9. QuartusのProgrammerで書き込み、動く!


Mac上で動くUbuntu Linux、マウスもキーボードもシームレスに動いてくれるので、普通にアプリケーションを使う感覚で使えて便利! 速度差も思ったほどなく、いつでもどこでもFPGAプログラミングができるようになって嬉しい!


Intel® Programmable Acceleration Card with Stratix® 10 SX FPGAより)
IntelだけどArmも入ってる!(Overview)

FPGAニュース「インテル、「多機能アクセラレータ」のFPGA新モデルを追加 - ZDNet Japan
本気で使うFPGA、サーバーマシンに接続し、ソフトウェアでは到達不可能な処理速度を実現!
なんと、回路規模はトランジスタ換算で6600万コ!(2755k LE x 12ゲート/LE x 2トランジスタ/ゲート)
25Gbpsの通信路に、2.4GbpsでアクセスできるRAM、ArmのプロセッサCortex-A53も入っている豪華仕様。
お値段、約100万円。
解説書付きで5,000円書き込み器内蔵のものも3,000円などの手頃なFPGAと比較し、回路規模だけで340倍違うので、なかなかいい値段。

サーバー処理のボトルネックをハードウェア化する時代、到来!

(おまけ)
4bitCPU「GMC-4」をVerilogで書いたプログラム。
gmc4_top.v

module gmc4_top( input clk, output [3:0] outport); reg n_reset; poweronreset por(clk, n_reset); wire cpuclk; clockdivider clkdiv(clk, n_reset, 4, cpuclk); reg [3:0] key; wire [7:0] ledbin; wire [3:0] lednum; gmc4 cpu(cpuclk, n_reset, key, ledbin, lednum); assign outport = ~lednum; endmodule

gmc4.v

module gmc4( input clk, input n_reset, input [3:0] key, output reg [7:0] ledbin, output reg [3:0] lednum); reg [3:0] mem[0:8'h5f]; reg [7:0] pc; reg [3:0] rega, regb, regy, regz, rega2, regb2, regy2, regz2; reg flg; wire [3:0] op1, op2, op3; assign op1 = mem[pc]; assign op2 = mem[pc + 1]; assign op3 = mem[pc + 2]; always @(posedge clk, negedge n_reset) begin if (!n_reset) begin // rom_blink; rom_count; pc <= 0; flg <= 0; lednum <= 0; ledbin <= 0; end else begin case (op1) 4'h0: begin rega <= key; flg <= key != 0; end 4'h1: begin lednum <= rega; flg <= 1; end 4'h2: begin rega <= regb; regb <= rega; regy <= regz; regz <= regy; flg <= 1; end 4'h3: begin rega <= regy; regy <= rega; flg <= 1; end 4'h4: begin mem[regy] <= rega; flg <= 1; end 4'h5: begin rega <= mem[regy]; flg <= 1; end 4'h6: { flg, mem[regy] } <= mem[regy] + rega; 4'h7: begin mem[regy] <= mem[regy] < rega ? 0 : mem[regy] - rega; flg <= mem[regy] < rega; end 4'h8: begin rega <= op2; flg <= 1; end 4'h9: { flg, rega } <= rega + op2; 4'hA: begin regy <= op2; flg <= 1; end 4'hB: { flg, regy } <= regy + op2; 4'hC: flg <= rega != op2; 4'hD: flg <= regy != op2; 4'hE: begin case (op2) 4'h0: lednum <= 0; 4'h1: ledbin[regy] <= 1; 4'h2: ledbin[regy] <= 0; 4'h3: ; // none 4'h4: rega <= ~rega; 4'h5: begin rega <= rega2; rega2 <= rega; regb <= regb2; regb2 <= regb; regy <= regy2; regy2 <= regy; regz <= regz2; regz2 <= regz; end 4'h6: begin rega <= rega >> 1; flg <= ~rega[1]; end 4'h7: ; // sound end 4'h8: ; // sound err 4'h9: ; // sound pi 4'hA: ; // sound piii 4'hB: ; // sound rega 4'hC: ; // wait (rega + 1) * 0.1sec 4'hD: begin ledbin[3:0] <= mem[8'h5e]; ledbin[7:4] <= mem[8'h5f]; end 4'hE: mem[regy] <= mem[regy] - rega; 4'hF: { mem[regy - 1], mem[regy] } <= { mem[regy - 1], mem[regy] } + rega; endcase if (op2 != 4'h6) flg <= 1; end 4'hF: begin pc <= flg ? { op2, op3 } : pc + 3; flg <= 1; end endcase if (op1 < 4'h8) pc <= pc + 1; else if (op1 < 4'hF) pc <= pc + 2; end end task rom_blink; mem[0] <= 4'h8; mem[1] <= 4'h1; mem[2] <= 4'h1; mem[3] <= 4'h8; mem[4] <= 4'h0; mem[5] <= 4'h1; mem[6] <= 4'hF; mem[7] <= 4'h0; mem[8] <= 4'h0; endtask task rom_count; mem[0] <= 4'h8; mem[1] <= 4'h0; mem[2] <= 4'h9; mem[3] <= 4'h1; mem[4] <= 4'h1; mem[5] <= 4'hF; mem[6] <= 4'h0; mem[7] <= 4'h2; endtask endmodule

poweronreset.v

module poweronreset( input clk, output n_reset); reg [7:0] counter; always @(posedge clk) begin if (counter != 8'b11111111) counter <= counter + 8'b1; end assign n_reset = counter == 8'b11111111; endmodule

clockdivider.v

`define LEN_CLOCK 50_000_000 module clockdivider( input clk, input n_reset, input [3:0] div, output reg outclk); reg [31:0] counter; always @(posedge clk, negedge n_reset) begin if (!n_reset) begin outclk <= 0; counter <= 0; end else if (counter == (`LEN_CLOCK >> div) - 1) begin counter <= 0; outclk <= ~outclk; end else counter <= counter + 1'b1; end endmodule

USB Blaster設定 for Ubuntu Linux

su cat > /etc/udev/rules.d/51-usbblaster.rules # Intel/Altera USB-Blaster SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6001", MODE="0666", SYMLINK+="usbblaster/%k" SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6002", MODE="0666", SYMLINK+="usbblaster/%k" SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6003", MODE="0666", SYMLINK+="usbblaster/%k" # Intel/Altera USB-Blaster II SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6010", MODE="0666", SYMLINK+="usbblaster2/%k" SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6810", MODE="0666", SYMLINK+="usbblaster2/%k"

links
- プログラムたった64行、FPGAで創るオレオレ32bitCPU「TF32CPU r1」90Mhz x 2コア動作 on MAX10
- 最大動作周波数468MHz!? 書籍の付録とUSB BlasterではじめるFPGA「MAX10-FB」の組み立て方

Tweet
クリエイティブ・コモンズ・ライセンス
この作品は「Creative Commons — CC BY 4.0」の下に提供されています。
CC BY 福野泰介 - Taisuke Fukuno / @taisukef / アイコン画像 / プロフィール画像