まごころせいじつ堂

浜町庄金 研究開発  マイコンで遊んでばっかりで

2013年01月

DE0 FPGAでFizzBuzz 任意の数値で判定

続き。DE0 FPGAでFizzBuzz
 前回は3進5進カウンターを使ってFizzBuzzを判定していたが、これはリセットと同期してカウントアップしなければならないという制限がある。では4桁の任意のBCD入力に対して簡単に判定することはできるか?
 ソフトでは3の剰余を求めたりするがこれは除算でありそんな大げさなものは動かしたくない。ではテーブル?buzzなら5の倍数なので、最後の桁が0または5で判断できる。
 では3の倍数であるfizzは?ちょっとこねくりまわしてみた。

3の倍数だけ取り出す。
$ awk 'BEGIN{for(i=1;i<10000;i++) printf("%04d\n",i)}' > fizz.txt

それぞれの桁をすべて足して3の剰余を求めると
$ awk '{print substr($1,1,1) substr($1,2,1) substr($1,3,1) substr($1,4,1)}' fizz.txt | gawk '{print $1%3}' 

なんかいけそう。

組み合わせ回路で実現できる。
BCDの4桁それぞれに対して3の剰余を求める。それぞれの桁は0,1,2になる。これの総和は最大で8なので、これに対して3の剰余を求める。こうするとfizzが判定できる。
module bcdmod3(BCD,BCDout);
	input [3:0] BCD;
	output [3:0] BCDout;

	function [3:0] mod3;
		input [3:0] bcdin;
		begin
			case (bcdin)
				1: mod3=1;
				2: mod3=2;
				4: mod3=1;
				5: mod3=2;
				7: mod3=1;
				8: mod3=2;
				default: mod3=0;
			endcase
		end
	endfunction

	assign BCDout=mod3(BCD);

	endmodule


module chkfizz(BCD3,BCD2,BCD1,BCD0, fizz);
	input [3:0] BCD3;
	input [3:0] BCD2;
	input [3:0] BCD1;
	input [3:0] BCD0;
	output fizz;

	wire [3:0] sBCD3;
	wire [3:0] sBCD2;
	wire [3:0] sBCD1;
	wire [3:0] sBCD0;
	wire [3:0] tBCD;
	wire [3:0] aBCD;
	
	bcdmod3 bcdmod3_3(BCD3,sBCD3);
	bcdmod3 bcdmod3_2(BCD2,sBCD2);
	bcdmod3 bcdmod3_1(BCD1,sBCD1);
	bcdmod3 bcdmod3_0(BCD0,sBCD0);
	
	assign tBCD=sBCD3+sBCD2+sBCD1+sBCD0;
	
	bcdmod3 bcdmod3_a(tBCD,aBCD);
	
	assign fizz=(aBCD==4'd0);
endmodule


 確認のためにトップモジュールではスライドスイッチによりBCDを入力してボタン2を押すと、その設定値からFizzBuzzのカウントを開始するようにした。

 QuartusIIで[Project]→[Archive Project...]を選択するとプロジェクトをひとまとめにしてくれる。ダイアログで[Advanced]ボタンを押し、一番上のFileset:はService Requestを選択。これで出力するとoutout_filesディレクトリ以下にfizzbuzz.qarというようなファイルができる。これを他のQuartusIIがインストールされているマシンに持って行ってダブルクリックするとプロジェクトが展開される。

 以下に置いてみました。
fizzbuzz.qar(Googls Docs)

追記:
それぞれの桁をa,b,c,dとおく。a+b+c+d=mod3なら1000a+100b+10c+dもmod3か?
999a+99b+9c + a+b+c+dとすると、9(111a+11b+c) + a+b+c+d で 3で割り切れて0 と + mod3となる。
ってことでよいのかな。中学二年の範囲。

DE0 FPGAでFizzBuzz

やりたいと思って約二年。やっとやる気が出て一週間。verilogの記述でFizzBuzzができた。

ソース。
https://gist.github.com/4649209 

1〜9999までの数字を右詰めゼロサプレスで表示。3の倍数はFizz、5の倍数はBuzz、両方の倍数はFzBzとそれっぽく7セグメントのLEDで表示。
Fizz判定は3進カウンタ、Buzz判定は5進カウンタを使い、BCD4桁カウンタと同じクロックで同時に進む。
数字が0の場合を表示するとまずいので、この時は7セグメントデコーダをoffにして何も表示しないようにした。



 色々ハマったけどwarningは全て見て無視出来る理由がないものは調査。1つのモジュールに複数の機能を入れない。複雑になり作っていてよくわからなくなったので単一機能のモジュールに分割し、上位モジュールで配線する。
 別の方法として、BCD出力を受けてこの中でFizzBuzz判定し、表示を差し替えるようにすれば3進5進カウンタを使わずに任意のBCDに対して判定ができるが、テーブルを作ることになるかな。5の判定は最後の桁が0 or 5でよさそうだがちょっと考えよう。

DE0 QuartusIIでのコンパイル結果をちょっと見る

QuartusII 12.1 Windows 32bit

 ゼロサプレスのデコーダ作ってて、どんな回路が作られてるのだろうと覗いてみた。QuartusIIの[Tools]→[Netlist Viewers]→[RTL Viewer]

追記:
※この回路はゼロサプレス部分にミスがあります。 

入力がすべて0の判定を三項演算子でやると、コンパレータになってる。
 assign bout=(bcd==4'b0000)?1'b1:1'b0;
2013decoder_eq0
Flow Status Successful - Sat Jan 26 18:40:00 2013
Quartus II 32-bit Version 12.1 Build 177 11/07/2012 SJ Web Edition
Revision Name fizzbuzz
Top-level Entity Name fizzbuzz
Family Cyclone III
Device EP3C16F484C6
Timing Models Final
Total logic elements 112 / 15,408 ( < 1 % )
Total combinational functions 101 / 15,408 ( < 1 % )
Dedicated logic registers 67 / 15,408 ( < 1 % )
Total registers 67
Total pins 57 / 347 ( 16 % )
Total virtual pins 0
Total memory bits 0 / 516,096 ( 0 % )
Embedded Multiplier 9-bit elements 0 / 112 ( 0 % )
Total PLLs 0 / 4 ( 0 % )
 

ゲートレベルで考えるとちゃんとゲートになっている。
assign bout=(~(|bcd));
2013decorder_or0
 Flow Status Successful - Sat Jan 26 18:37:14 2013
Quartus II 32-bit Version 12.1 Build 177 11/07/2012 SJ Web Edition
Revision Name fizzbuzz
Top-level Entity Name fizzbuzz
Family Cyclone III
Device EP3C16F484C6
Timing Models Final
Total logic elements 110 / 15,408 ( < 1 % )
Total combinational functions 99 / 15,408 ( < 1 % )
Dedicated logic registers 67 / 15,408 ( < 1 % )
Total registers 67
Total pins 57 / 347 ( 16 % )
Total virtual pins 0
Total memory bits 0 / 516,096 ( 0 % )
Embedded Multiplier 9-bit elements 0 / 112 ( 0 % )
Total PLLs 0 / 4 ( 0 % )

 LEが2個少なくなった。差はないと思っていたんだけど、記述での最適化は効くということだろうか。 

DE0 ゼロサプレス付きカウンタ

続き。カウンタと7セグメントLEDに表示するデコーダ、スイッチ入力のチャタリング除去のモジュールを作成した。

 QuartusIIで新規プロジェクトを作成。[Assignment]→[Import Assignment...]で前回作成したピンアサインを取り込む。

20130126追記:肝心のゼロサプレス部分に間違いがあります。
このままだと4桁の1001表示で10□1の様になります。ゼロサプレスは直前ではなくずっと前の桁がすべて0でなければならないので、segleddec.vは以下書き換え。

assign bout=(bcd==4'b0000)?bin:0;

https://gist.github.com/4639707 

 segleddec.vは4bitの入力を0~Fの16パターンと解釈し、それぞれのパターンに対応する7セグメントのLEDを点灯させる。DE0の7セグメントLEDはアノードコモンなので'0'で点灯。
 TTLの7447はゼロサプレスの機能を持っている。これは普通の電卓の表示のように、桁の左側の余計なゼロを表示しないというもの。左側に位置する桁が'0'で、自分自身が'0'ならば表示を抑止する。ただし1桁目は'0'も表示する。

segleddec.v
assign bout=(bcd==4'b0000)?1'b1:1'b0; // ~&bcd
assign led=(bout&&bin)?8'b11111111:ALED(bcd,dp);

 左側の桁は'0000'ならboutを出力。右側の桁はそれをbinで受ける。右側の桁は自分が'0000'かつ左側の桁が'0000'(bin='1')なら表示を抑止。たくさん並んでいる桁なら、一番左側の桁のbinは'1'に吊ってあとはカスケード接続。ただし一番右、最後の桁はbinを'0'にして切り離す。

hexcounter.v:
segleddec seg0(cnt[27:24],1'b0,1'b0, hled0,bout0_0); // Digit xxx0 always on
segleddec seg1(cnt[31:28],1'b0,bout2_1, hled1,bout1_0);
segleddec seg2(cnt[35:32],1'b0,bout3_2, hled2,bout2_1);
segleddec seg3(cnt[39:36],1'b0,1'b1, hled3,bout3_2);

 こんな感じ。モジュールを定義しておいてこのように書くとインスタンスseg0,seg1,seg2,seg3を生成できる。
 

 二進カウンターは特に問題ないが、パラメータ化して任意のビット長まで指定できるようにしてある。非同期リセット付き。
 TTLなどは非同期リセットがかかるまでは値を保持するFFの内容は'1'か'0'かわからないものとして扱うが、パワーオン後にスキャンを行い初期設定するFPGAやASICは値が確定している。ただし'1'か'0'かは設定によるし、昔パワーオン直後のすべてのFFの値は'1'というPLDを使ったことがあった。

 ついでにスイッチ入力をFF受けで同期化してチャタリングを抑止するunchat.vを組み込んだ。同期回路に非同期の信号を直接入れるのは気持ち悪い。以下の様なトラブルを調査したことがあるが、こんなことがありえるのだ。

入力信号は必ずFF受けで 

 ここではカウンターで16分周した(50MHz÷65536=20ns×65536=1.3ms)間隔でスイッチの入力をサンプリングする。チャタリングはこの周期内には収まっている前提。
 パラメータ化はしていない。


DE0 オンボードのLED、スイッチ類のピンアサイン

「超入門!FPGAスタータ・キット DE0で始めるVerilog HDL」を見ながらDE0ボードで遊び始めているが、色々な実験をする前にピンアサインを入れてしまおう。毎回Pin Plannerで設定するのも嫌なので、本の途中を飛ばして第17章へ。最上位階層(top module)でないとFPGAのI/Oには接続できないが、ここで最上位階層の枠を決めて対応するピンもPin Plannerで定義してやると、あとはこれを保存しておけば別のデザインを始めるときに呼び出すだけでよい。ついでにLEDやスイッチのテストも兼ねた記述を入れた。

https://gist.github.com/4620609

// terasIC DE0 topmodule skeleton
// onboard I/O 3-button,10-sw,10-LED,4-7SEG
//
module Skeleton(clk,btn,sw,led,hled0,hled1,hled2,hled3,lcd_bl);
  input clk;
	input [2:0] btn;
	input [9:0] sw;
	output [9:0] led;
	output [7:0] hled0;
	output [7:0] hled1;
	output [7:0] hled2;
	output [7:0] hled3;
	output lcd_bl;
	
	assign led=(btn[2]==1'b1) ? sw: ~sw; // button2 press, then invert all LED
	assign hled0[7:0]=(btn[1:0]==2'b11) ? ~sw[7:0]: 8'b11111111; // 7segment digit xxx0
	assign hled1[7:0]=(btn[1:0]==2'b10) ? ~sw[7:0]: 8'b11111111; // 7segment digit xx0x press button 0
	assign hled2[7:0]=(btn[1:0]==2'b01) ? ~sw[7:0]: 8'b11111111; // 7segment digit x0xx press button 1
	assign hled3[7:0]=(btn[1:0]==2'b00) ? ~sw[7:0]: 8'b11111111; // 7segment digit 0xxx press button 1,0
	assign lcd_bl=sw[9]; // optiona LCD backlight
 
endmodule

プッシュボタンは押すと'0'、離した状態で'1'。
スライドスイッチは上の位置で'1'、下の位置で'0'。
緑のLEDは'1'で点灯。
7セグメントLEDはアノードコモンなので'0'で点灯。セグメントは上から時計回りにa,b,c,d,e,f、中央はg、小数点はdp。

 ピンプランナーでの画面。
pinplanner


せっかくピンアサインの対応表を作ったので以下にcsvファイルを置いときます。お手持ちの表計算ソフトで読み込んで下さい。

https://gist.github.com/4620569

動画はこちら。

terasIC DE0評価ボードで何か動かすまでのメモ

 2年ほど触らないままでいたFPGAの評価ボード(terasicのDE0)、ちょっときっかけがあったので使ってみた。サンプルの記述を論理合成してボードに転送し、スイッチとLEDを連動させるまでの手順。

terasIC Altera DE0 Board

DE0のマニュアルなど

以降Windows7(64bit)で作業。

開発用ソフトのダウンロード 最新はQuartus II v12.1 ウェブ・エディションをインストール
ALTERA

※これが約4GBと大きいのでウチなんかだと一晩コース


 「超入門!FPGAスタータ・キット DE0で始めるVerilog HDL」を参照しながら開始。
この本はQuartus II v9.0を例に説明してある。インストールと動作確認は1章、2章。
 論理回路がわかっている人は3〜6章は飛ばしていい。

 DE0をPCに接続する。デバイスがインストールされなかったら、 コントロールパネル>すべてのコントロールパネル項目>システム>デバイスマネージャーからUSB Blusterを探し、再インストール。C:\altera\12.1\quartus\drivers以下を指定。

☆最初のハマリどころ
[File]→[New Project Wizard...]でディレクトリを指定するが、ここがデスクトップだとパーミッションがないと言われ作成できなかった。自分のホームディレクトリだとOKだが、そこにプロジェクト用のファイルが散らばってしまうのでサブディレクトリを指定。

 FPGAデバイスは Family: CycloneIII で Available devices: から EP3C16F484C6を選択。
 他は設定しなくていい。


 プロジェクトウィザードが終了したら[File]→[New]でVerilog HDL Fileを選択。

この本のとおりにするとLesson1.vというファイル名で一旦保存。
次に以下のソースを入力。

module Lesson1( sw, led );
  input [9:0] sw ;
	output [9:0] led ;
 
	assign led=sw;
	
endmodule
 
/*
module Lesson1(
sw0,sw1,sw2,sw3,sw4,sw5,sw6,sw7,sw8,sw9,
led0,led1,led2,led3,led4,led5,led6,led7,led8,led9);
	input sw0,sw1,sw2,sw3,sw4,sw5,sw6,sw7,sw8,sw9;
	output led0,led1,led2,led3,led4,led5,led6,led7,led8,led9;
	
	assign led0=sw0;
	assign led1=sw1;
	assign led2=sw2;
	assign led3=sw3;
	assign led4=sw4;
	assign led5=sw5;
	assign led6=sw6;
	assign led7=sw7;
	assign led8=sw8;
	assign led9=sw9;
	
endmodule
*/

※コメント内は入出力をバラで書いた場合。

保存してから[Processing]→[Start]→[Start Anarysis & Elaboration]を実行。成功したら次はピンアサイン。
ピンアサインは[Assignments]→[Pin Planner]でピンプランナーを開く。
ここで NodeNameに対し以下のLocationを入力する。

NodeName Location
led[9] PIN_B1
led[8] PIN_B2
led[7] PIN_C2
led[6] PIN_C1
led[5] PIN_E1
led[4] PIN_F2
led[3] PIN_H1
led[2] PIN_J3
led[1] PIN_J2
led[0] PIN_J1
sw[9] PIN_D2
sw[8] PIN_E4
sw[7] PIN_E3
sw[6] PIN_H7
sw[5] PIN_J7
sw[4] PIN_G5
sw[3] PIN_G4
sw[2] PIN_H6
se[1] PIN_H5
sw[0] PIN_J6

このピン割当てについてはDE0_User_manualを参照。

[Processing]→[Start Compilation]でビルドする。

☆次のハマりどころ
[Processing]→[Start Compilation]でいきなりビルドするとピンアサインも勝手に割り当てられてしまい、ピンプランナーで付け替えることができない。
[Assignments]→[Remove Assignments]で□Pin,Location & Routing Assignmentsにチェックを入れて[OK]で解除。このあとピンプランナーで入力。

 あとはDE0に転送する。左側のスライドスイッチが[RUN]の位置にあることを確認し、DE0の電源を入れる。
[Tools]→[Programmer]で画面を開き、左上にある[Hardware Setup...]ボタンを押して USB-Blaster [USB-0] をダブルクリック。ここの設定は一回だけでよい。
転送はこの画面を開いて[Start]のボタンを押す。これでFPGAにConfigureが転送される。

 DE0の電源を入れるとデモがスタートするが、これは基板上のConfiguration用ROMからFPGAにデモが書いてあるイメージが転送されるため。上記操作だとDE0基板上のUSB-Bluster経由でPCからFPGAに直接転送される。

スライドスイッチをONにすると対応したLEDが点灯する。(動画)


 ビルド時のWarinigに関しては、今回はclockは使用していないので
332068 No clocks defines in design.
は無視。
332012 Synopsys Design Constraints File fine not found: ... 
は制約ファイルといってディレイのタイミングを調整するのに使うが今回は意識しないのでこれも無視。
(ってSynopsysの技術使ってるんだこれ)

 感想。こんなに気軽に出来るとは思ってなかった。身構え過ぎでした。
大昔、元職場の同僚がアルテラのPentium60/66MHzに似たパッケージの石を486DX100MHzのWindows3.1マシンで一生懸命設計しコンパイルに一晩かかっていたのを思い出しましたが、そんな話ではなかった。こんなに簡単に出来ていいのか、としばらくは興奮状態。

なつたんさん、今頃使いはじめてごめんなさい。これから使い潰します。

超入門!FPGAスタータ・キットDE0で始めるVerilog HDL: すぐ始められる!USB対応・書き込み器不要・大容量FPGA搭載! (トライアルシリーズ)超入門!FPGAスタータ・キットDE0で始めるVerilog HDL: すぐ始められる!USB対応・書き込み器不要・大容量FPGA搭載! (トライアルシリーズ)
芹井 滋喜

CQ出版 2011-07-22
売り上げランキング : 115091

Amazonで詳しく見る
by G-Tools

FONTX関連メモ

FONTX関連のメモ。
 本当は漢字ROMのイメージがあればいいのだけれども。手元の古いマシンから吸い出すこともできるができれば一般に再現可能な方法でやってみたい。

FONTXの使いかた 
グラフィックLCDモジュール 日本語フォント編 
IPAフォントを元としたLXで使える32/24/16ドットフォント 

電工:ファストン端子

平べったいACプラグの先みたいなのに着脱するのをファストン端子という。
普通はこんなコードコネクタボディで接続するけど、省スペースを狙ってサイズの合うメス端子を探してやってみた。
ベター小型コードコネクタボディ (MonotaRO)

312ファストン端子というのが、ACプラグとうまく接続できそう。
312型ファストン端子 (MonotaRO)
こちらの平型端子は小さかった。
平型端子 (MonoTARO)

2013faston

 で、ケーブル(心線が1.25mm2径のより線)を圧着してみたのだがスッポ抜けた。説明をよく見ると適合電線3.0mm2〜と書いてある。失敗。

 あと、圧着はより線の場合よらないでするらしい。

圧着工具 (Wikipedia) 

電工関係は独学だときびしいなあ。危ないし。

lcd.write(0)でerror: call of overloaded 'write(int)' is ambiguousと言われる

キャラクタ液晶を扱うライブラリLiquidCrystalには、ユーザ定義文字を設定するcreateChar(num,data)という関数がある。これを試したらなぜかエラーになった。

createChar(num,data) Arduino日本語リファレンス
createChar() (原文)

Arduino1.0.3で以下のメッセージ。(MacOSX) Windowsでも同様

sketch_jan04b.ino: In function 'void setup()':
sketch_jan04b:18: error: call of overloaded 'write(int)' is ambiguous
/Applications/Arduino1.0.3.app/Contents/Resources/Java/libraries/LiquidCrystal/LiquidCrystal.h:82: note: candidates are: virtual size_t LiquidCrystal::write(uint8_t)
/Applications/Arduino1.0.3.app/Contents/Resources/Java/hardware/arduino/cores/arduino/Print.h:49: note:                 size_t Print::write(const char*)

??サンプルがそのまま動かないのナンデ? 0x00に書き換えても同様。

調べたら定数0を指定した時だけの問題。lcdに限らない。
call of overloaded 'write(int) is ambigous?

lcd.write(0); を lcd.write((byte)0);にして解決。1〜の定数を指定した時はエラーが発生しない。
もちろん、変数で指定した場合は問題ない。
サンプルのコピペでちょっとハマッてしまった。
 2013smile

記事検索
プロフィール

hardyboy

カテゴリ別アーカイブ
月別アーカイブ
QRコード
QRコード
  • ライブドアブログ