2021/11/28
adder4を追加した。
2021/11/27
dsphex関連を追加した。
2021/11/25
blink関連を追加した。
2021/11/22
初版
verilog事始め(Gowin RUNBER board で始める)
verilog事始め(Gowin RUNBER board で始める)
概要
FPGAのプログラミングができる開発ボードとして以下を購入した。
Gowin RUNBER FPGA Development Board
注意:
現時点では、このボードはPCからフラッシュメモリへの書き込みをサポートしていないので
SRAMへの書き込みを使用することになる。
インタフェース2021年12月号別冊付録にこのボードの使用方法があるので、これを参照する。
Interface2021年12月号
ツールのインストールと起動
インタフェース2021年12月号別冊付録にインストール方法があるので
それを参照してインストールする。
以下がツールのダウンロードのURLになる。
https://www.gowinsemi.com/ja/support/home/
GOWIN EDA ホーム
ここからツールをダウンロードできる。(linux用もあり)
ツール関係のドキュメントもダウンロードできる。
(アカウント登録必要)
付録にあるライセンス申請URLがアクセスできなかったので
本家サイトでライセンス申請した。
数日後、代理店の丸文経由でライセンス・ファイルが送られてきたので
これを利用してツールが有効になった。
ツールの使用方法
付録にある使用方法を以下のように動作サンプルを元に使用方法を纏めた:
ツールは、Designer, PloorPlanner,Programmerの3つのウィンドウから構成される。
1.プロジェクト作成
ツールを起動する。
File/Newを選択して以下を選択する:
FPGA Desing Project
# Chip選択する
以下を設定する:
Name:hwtest (任意)
Crate in:C:\Gowin\ws (任意)
Nextをクリックする。
以下を設定する:
Series: GOW1N
Device: GW1N-4B
Package: LQFP144
Speed: Any
Part Number:
GW1N-UV4LQ144C6/15
Nextをクリックする。
Fishをクリックする。
# 以上でChipの設定が完了する
2.verilogファイル作成
File/Newから以下を選択する:
Verilog File
以下を設定する:
Name: hwtest (任意)
ディレクトリ設定はそのまま
以上で空のhwtest.vができる。
オンボードのハード(DISP-SW,LED,RGB-LED,7seg-LED)のテスト用に以下のhwtest.vを作成する:
hwtest.v
module test(
input [7:0] sw,
input [7:0] btn,
output [7:0] seg,
output [3:0] seg_dig,
output [7:0] led,
output [2:0] rgb0,
output [2:0] rgb1,
output [2:0] rgb2,
output [2:0] rgb3
);
assign rgb0 = 3'b110;
assign rgb1 = 3'b101;
assign rgb2 = 3'b011;
assign rgb3 = sw;
assign seg_dig = sw;
assign seg = ~btn;
assign led = btn;
endmodule
継続:
File/Saveで保存する。
3.論理合成
consoleウィンドウの上のメニューから以下を選択する:
Process
左のペインから以下を選択する:
Sythesizeで右クリックしてRunを選択する。
論理合成が実行される。
4.FloorPlanner(ピン配置の設定)
consoleウィンドウの上のメニューから以下を選択する:
Process
左のペインから以下を選択する:
User Constraints/Floor Planner で左クリックしてRunを選択する。
ファイルを作るか聞いてきたら、そのままOKにする
(FloorPlannerの)画面の最下行のメニューから「I/O Constraints」をクリックする
設定画面が出るので設定する:
(画面が小さい場合、ドラッグで画面を大きくする)
Location,Pull Mode を仕様に合わせて設定する
File/Saveで保存する。
(DesignerのConsole画面の上のメニューの)Designをクリックすると左のペインに
現在のプロジェクトのファイル・ディレクトリが出るので
ここから、*.cstを選択して、編集しても良い。
上のGUIで設定するよりもテキストをコピー&ペーストするほうが手っ取り早いかもしれない。
以下はオンボードのデバイスを設定した例である:
hwtest.cst
//Copyright (C)2014-2021 Gowin Semiconductor Corporation.
//All rights reserved.
//File Title: Physical Constraints file
//GOWIN Version: 1.9.8.01
//Part Number: GW1N-UV4LQ144C6/I5
//Device: GW1N-4B
//Created Time: Tue 11 23 10:51:34 2021
IO_LOC "led[7]" 30;
IO_PORT "led[7]" PULL_MODE=NONE DRIVE=8;
IO_LOC "led[6]" 29;
IO_PORT "led[6]" PULL_MODE=NONE DRIVE=8;
IO_LOC "led[5]" 28;
IO_PORT "led[5]" PULL_MODE=NONE DRIVE=8;
IO_LOC "led[4]" 27;
IO_PORT "led[4]" PULL_MODE=NONE DRIVE=8;
IO_LOC "led[3]" 26;
IO_PORT "led[3]" PULL_MODE=NONE DRIVE=8;
IO_LOC "led[2]" 25;
IO_PORT "led[2]" PULL_MODE=NONE DRIVE=8;
IO_LOC "led[1]" 24;
IO_PORT "led[1]" PULL_MODE=NONE DRIVE=8;
IO_LOC "led[0]" 23;
IO_PORT "led[0]" PULL_MODE=NONE DRIVE=8;
IO_LOC "seg_dig[3]" 7;
IO_PORT "seg_dig[3]" PULL_MODE=UP DRIVE=8;
IO_LOC "seg_dig[2]" 141;
IO_PORT "seg_dig[2]" PULL_MODE=UP DRIVE=8;
IO_LOC "seg_dig[1]" 140;
IO_PORT "seg_dig[1]" PULL_MODE=UP DRIVE=8;
IO_LOC "seg_dig[0]" 137;
IO_PORT "seg_dig[0]" PULL_MODE=UP DRIVE=8;
IO_LOC "seg[7]" 10;
IO_PORT "seg[7]" PULL_MODE=NONE DRIVE=8;
IO_LOC "seg[6]" 8;
IO_PORT "seg[6]" PULL_MODE=NONE DRIVE=8;
IO_LOC "seg[5]" 139;
IO_PORT "seg[5]" PULL_MODE=NONE DRIVE=8;
IO_LOC "seg[4]" 12;
IO_PORT "seg[4]" PULL_MODE=NONE DRIVE=8;
IO_LOC "seg[3]" 11;
IO_PORT "seg[3]" PULL_MODE=NONE DRIVE=8;
IO_LOC "seg[2]" 9;
IO_PORT "seg[2]" PULL_MODE=NONE DRIVE=8;
IO_LOC "seg[1]" 142;
IO_PORT "seg[1]" PULL_MODE=NONE DRIVE=8;
IO_LOC "seg[0]" 138;
IO_PORT "seg[0]" PULL_MODE=NONE DRIVE=8;
IO_LOC "sw[7]" 83;
IO_PORT "sw[7]" PULL_MODE=NONE;
IO_LOC "sw[6]" 82;
IO_PORT "sw[6]" PULL_MODE=NONE;
IO_LOC "sw[5]" 81;
IO_PORT "sw[5]" PULL_MODE=NONE;
IO_LOC "sw[4]" 80;
IO_PORT "sw[4]" PULL_MODE=NONE;
IO_LOC "sw[3]" 79;
IO_PORT "sw[3]" PULL_MODE=NONE;
IO_LOC "sw[2]" 78;
IO_PORT "sw[2]" PULL_MODE=NONE;
IO_LOC "sw[1]" 76;
IO_PORT "sw[1]" PULL_MODE=NONE;
IO_LOC "sw[0]" 75;
IO_PORT "sw[0]" PULL_MODE=NONE;
IO_LOC "btn[5]" 63;
IO_PORT "btn[5]" PULL_MODE=UP;
IO_LOC "btn[4]" 62;
IO_PORT "btn[4]" PULL_MODE=UP;
IO_LOC "btn[3]" 61;
IO_PORT "btn[3]" PULL_MODE=UP;
IO_LOC "btn[2]" 60;
IO_PORT "btn[2]" PULL_MODE=UP;
IO_LOC "btn[7]" 65;
IO_PORT "btn[7]" PULL_MODE=UP;
IO_LOC "btn[6]" 64;
IO_PORT "btn[6]" PULL_MODE=UP;
IO_LOC "btn[0]" 58;
IO_PORT "btn[0]" PULL_MODE=UP;
IO_LOC "btn[1]" 59;
IO_PORT "btn[1]" PULL_MODE=UP;
IO_LOC "rgb3[2]" 100;
IO_PORT "rgb3[2]" PULL_MODE=NONE DRIVE=8;
IO_LOC "rgb3[1]" 99;
IO_PORT "rgb3[1]" PULL_MODE=NONE DRIVE=8;
IO_LOC "rgb3[0]" 98;
IO_PORT "rgb3[0]" PULL_MODE=NONE DRIVE=8;
IO_LOC "rgb2[2]" 104;
IO_PORT "rgb2[2]" PULL_MODE=NONE DRIVE=8;
IO_LOC "rgb2[1]" 102;
IO_PORT "rgb2[1]" PULL_MODE=NONE DRIVE=8;
IO_LOC "rgb2[0]" 101;
IO_PORT "rgb2[0]" PULL_MODE=NONE DRIVE=8;
IO_LOC "rgb1[2]" 111;
IO_PORT "rgb1[2]" PULL_MODE=NONE DRIVE=8;
IO_LOC "rgb1[1]" 110;
IO_PORT "rgb1[1]" PULL_MODE=NONE DRIVE=8;
IO_LOC "rgb1[0]" 106;
IO_PORT "rgb1[0]" PULL_MODE=NONE DRIVE=8;
IO_LOC "rgb0[2]" 114;
IO_PORT "rgb0[2]" PULL_MODE=NONE DRIVE=8;
IO_LOC "rgb0[1]" 113;
IO_PORT "rgb0[1]" PULL_MODE=NONE DRIVE=8;
IO_LOC "rgb0[0]" 112;
IO_PORT "rgb0[0]" PULL_MODE=NONE DRIVE=8;
5.Place&Route(マッピング)
consoleウィンドウの上のメニューから以下を選択する:
Process
左のペインから以下を選択する:
Place & Route で右クリックしてRunを選択する。
6.書き込み
ボードをPCに接続する。
consoleウィンドウの上のメニューから以下を選択する:
Process
左のペインから以下を選択する:
Program Device で右クリックしてRunを選択する。
Programmer画面から書き込み(Program/Configure)アイコンをクリックする。
コンソールログ例:
Info: "SRAM Program" starting on device-1...
Warn: Compatible cable found
Warn: Compatible cable found
Info: User Code: 0x0000C642
Info: Status Code: 0x0001F020
Info: Cost 6.48 second(s)
以上で全ての完了してプログラム(verilog)が動作する。
今回のhwtest.vの仕様:
(1)DIP-SWはデフォルトはONでSW1-SW4のうち有効にしたい桁の
SWをOFFにする。
(2)特定のボタンを押すと、それに対応したLEDはオフになり、7セグメントは対応したセグメントが光る。
# 通称で7セグメントというが実際には小数点があるので
# 実際のセグメント数は8になる。
(3)RGB-LEDは上から以下のように光る:
1番目:赤
2番目:青
3番目:緑
4番目:SW1-SW3に連動していて
SW1-RED
SW2-Blue
SW3-Green
に対応している。
負論理なのでOFFにすると対応しているLEDが光る。
sample#1(blink)
別のプログラム例としてLEDを点滅させてみる。
プロジェクトを上の例を参考に作成する。
blink.v
module blink(
input clk,
input tc,
input [7:0] sw,
input [7:0] btn,
output [7:0] seg,
output [3:0] seg_dig,
output [7:0] led,
output [2:0] rgb0,
output [2:0] rgb1,
output [2:0] rgb2,
output [2:0] rgb3
);
wire clk10KHz;
reg [7:0] leds;
clkdiv(.clk(clk), .rst(1'b0), .max(24'd1200_000_10), .tc(clk10KHz));
always@(posedge(clk10KHz))
begin
if (tc == 0) begin
leds <= 0;
end else begin
leds <= ~leds;
end
end
assign seg_dig = sw;
assign seg = leds & ~btn;
assign led = leds & btn;
endmodule
全てのLEDを点滅することができるが、ドライブ能力の問題があるので
RGB-LEDの部分はコメントアウトしている。
clkdiv.v
module clkdiv(
input clk,
input rst,
input [23:0] max,
output tc
);
reg [23:0] count;
always @(posedge clk or posedge rst)
begin
if (rst == 1'b1) begin
count <= 24'd0;
end else begin
if (tc == 1'b1)
count <= 24'd0;
else
count <= count + 24'b1;
end
end
assign tc = (count >= max) ? 1'b1 : 1'b0 ;
endmodule
clkdiv.vは、インタフェースの付録のものを参考にした。
blink.cst
(従来のcstに以下の部分を追加する)
IO_LOC "clk" 4;
IO_PORT "clk" PULL_MODE=NONE;
<省略>
仕様:
hwtest.vの仕様にLEDの点滅を追加した仕様になるので
以下のようになる(RGB-LED部分はコメントアウトしているので機能しない)
(1)DIP-SWはデフォルトはONでSW1-SW4のうち有効にしたい桁の
SWをOFFにする。
(2)特定のボタンを押すと、それに対応したLEDはオフになり、7セグメントは対応したセグメントが光る。
# 通称で7セグメントというが実際には小数点があるので
# 実際のセグメント数は8になる。
(3)従来、LEDが単に光っていたところが点滅になる。
sample#2(dsphex)
別の例として、スイッチとボタンの内容を読み込み、7seg-LEDに16進で表示するプログラムを作成する。以下のプログラム(*.v)を用意する。
これらの他に、clkdiv.vが必要となるは、それはsample#1のものと同じものを使用する。(ここでは、インタフェースの付録のものを参考にした)
top_dsphex.v
module top_dsphex (
input clk,
input [7:0] sw,
input [7:0] btn,
output [7:0] seg,
output [3:0] seg_dig,
output [7:0] led
);
assign led = 8'b0000_0000;
wire [7:0] seg_a, seg_b, seg_c, seg_d;
wire [3:0] a, b, c, d;
assign a = {sw[0],sw[1],sw[2],sw[3]};
assign b = {sw[4],sw[5],sw[6],sw[7]};
assign c = ~{btn[0],btn[1],btn[2],btn[3]};
assign d = ~{btn[4],btn[5],btn[6],btn[7]};
drv7seg seg_1 (.in(a), .dp(1'b0), .seg(seg_a));
drv7seg seg_2 (.in(b), .dp(1'b0), .seg(seg_b));
drv7seg seg_3 (.in(c), .dp(1'b0), .seg(seg_c));
drv7seg seg_4 (.in(d), .dp(1'b0), .seg(seg_d));
mux7seg mux7seg_1 (
.clk(clk),
.seg_a(seg_a),
.seg_b(seg_b),
.seg_c(seg_c),
.seg_d(seg_d),
.seg(seg),
.seg_dig(seg_dig)
);
endmodule
mux7seg.v
module mux7seg (
input clk,
input [7:0] seg_a,
input [7:0] seg_b,
input [7:0] seg_c,
input [7:0] seg_d,
output [7:0] seg,
output [3:0] seg_dig
);
wire clkdig;
reg [2:0] seg_no;
clkdiv(.clk(clk), .rst(1'b0), .max(24'd120), .tc(clkdig));
always @ (posedge(clkdig))
begin
seg_no <= ((seg_no + 3'd1) % 8);
end
function [7:0] sel_seg;
input [7:0] a, b, c, d;
input [1:0] seg_no;
case(seg_no)
2'd0: sel_seg = a;
2'd1: sel_seg = b;
2'd2: sel_seg = c;
2'd3: sel_seg = d;
endcase
endfunction
function [3:0] sel_dig;
input [1:0] seg_no;
case(seg_no)
2'd0: sel_dig = 4'b1110;
2'd1: sel_dig = 4'b1101;
2'd2: sel_dig = 4'b1011;
2'd3: sel_dig = 4'b0111;
endcase
endfunction
assign seg = sel_seg(.a(seg_a), .b(seg_b), .c(seg_c), .d(seg_d), .seg_no(seg_no[1:0]));
assign seg_dig = sel_dig(.seg_no(seg_no[1:0]));
endmodule
drv7seg.v
module drv7seg (
input [3:0] in,
input dp,
output [7:0] seg
);
function [6:0] f;
input [3:0] sw;
begin
case(sw)
4'h0: f = 7'h3F;
4'h1: f = 7'h06;
4'h2: f = 7'h5B;
4'h3: f = 7'h4F;
4'h4: f = 7'h66;
4'h5: f = 7'h6D;
4'h6: f = 7'h7D;
4'h7: f = 7'h27;
4'h8: f = 7'h7F;
4'h9: f = 7'h6F;
4'hA: f = 7'h77;
4'hB: f = 7'h7C;
4'hC: f = 7'h58;
4'hD: f = 7'h5E;
4'hE: f = 7'h79;
4'hF: f = 7'h71;
endcase
end
endfunction
assign seg = {dp,f(in)};
endmodule
制約ファイルdsphex.cstはsample#1のものと同じ内容になる。
仕様:
DIPのSW1-SW4,SW5-SW8, ボタンの#1-#4,#5-#6が
7セグメントLEDの左から順に対応している。
SWやボタンの内容に対応して7セグメントLEDに16進で表示される。
(目障りなので)緑のLEDは消灯している。
sample#3(adder4)
例として、sample#2をベースに以下を追加して、4ビット加算器を実現する。
top_dsphex.vを以下のように変更する:
top_adder4.v
module top_adder4 (
input clk,
input [7:0] sw,
input [7:0] btn,
output [7:0] seg,
output [3:0] seg_dig,
output [7:0] led
);
assign led = 8'b0000_0000;
wire [7:0] seg_a, seg_b, seg_c, seg_d;
wire [3:0] a, b, c, d;
wire c_out;
wire [3:0] sum;
assign a = {sw[0],sw[1],sw[2],sw[3]};
assign b = {sw[4],sw[5],sw[6],sw[7]};
fulladder fa_1 (.a(a), .b(b), .c_in(1'b0), .c_out(c_out), .sum(sum) );
assign c = {3'b000, c_out};
assign d = sum;
drv7seg seg_1 (.in(a), .dp(1'b0), .seg(seg_a));
drv7seg seg_2 (.in(b), .dp(1'b0), .seg(seg_b));
drv7seg seg_3 (.in(c), .dp(1'b0), .seg(seg_c));
drv7seg seg_4 (.in(d), .dp(1'b0), .seg(seg_d));
mux7seg mux7seg_1 (
.clk(clk),
.seg_a(seg_a),
.seg_b(seg_b),
.seg_c(seg_c),
.seg_d(seg_d),
.seg(seg),
.seg_dig(seg_dig)
);
endmodule
以下を追加する:
fulladder.v
module fulladder(
input [3:0]a,
input [3:0]b,
input c_in,
output reg c_out,
output reg [3:0] sum
);
always @(a or b or c_in)
begin
{c_out, sum} = a + b + c_in;
end
endmodule
仕様:
DIPのSW1-SW4,SW5-SW8が入力のa,bに対応して
7セグメントLED#1,#2に、その内容が表示され
加算結果が、7セグメントLED#3,#4に16進で表示される。
(目障りなので)緑のLEDは消灯している。
参照情報
ボード関係:
Gowin RUNBER FPGA Development Board
RUNBER Development Board - Hardware Instructions
RUNBER Development Board - Instructions for Experiments
Gowin_device&Software User Guide
Gowin_RUNBER_BOARD Source Code
Runber_Development_Board_Schematics
GOWIN RUMBERのLチカを階層に分割してみる
linuxツール関係:
GOWIN GW1N-UV4LQ144C6/I5を動かす
verilog関係:
Verilog-HDL入門
Verilog入門(alwaysなど)
Getting Started with a free Verilog Simulator
Icarus Verilog - Getting Started
Icarus Verilogの導入とAND回路のシミュレーション
Icarus Verilogコンパイラを使う
verilog samples:
【問題1】 Verilog HDLをマスターしよう!!
【問題2】 4ビット加算器をVerilog HDLで記述しよう
【問題11】 パラメタライズによる回路の記述
Verilog Full Adder
Tools関連:
Analyzer Oscilloscopeの使い方
Tang Nanoで内部信号のモニタリング
以上