今日は、2進数カウンタ(ハードウェアでいう普通のカウンタですが)でエラーカウントした結果を周期的に7SEG-LED(7セグ)に10進数で表示するにはどうするか? です。
例えば、10(dec)は2進数で"1010b"で7SEGでは"Ah"でも良いのですが、10進数の"10d"と表示したいということです。
本当は元のデータは32bit(0~4,294,967,296)の表示が必要なのですが、規模が大きそうなのでとりあえず16bit(0~65,535)で作ります。
2進数16bitだと、7SEG-LEDに表示するには5個(5桁→0~65535)のLEDがあれば良いですね。1の位から万の位まで5桁なので。ちなみに16進数表示だと4個(0000~FFFF)の7SEG-LEDでOK。
※ 32bitだと10個必要ですが10個とかの7SEGはあまり無いので浮動小数点表示とかで・・考えるの大変なのでやめた。これはNiosIIとかのソフトウェアに任せた方が良さそう。
(1) 仕様
(a) 入力は2進数16bitの符号なしとする(10進:0~65,535、16進:0000~FFFF)
他には無いか・・
(2) RTL
verilogで設計してみました。(FlipFlop出力信号にsr_を付けてますが気にしなくてOKです)
//----------------------------------------------------------------------------- // Title : bin2dec // Project : none //----------------------------------------------------------------------------- // File : bin2dec.v // Author : shio // Created : 2013/02/16 // Last modified : 2013/02/16 //----------------------------------------------------------------------------- // Description : 16bit(16進数4桁)のバイナリ値を10進数5桁の値に変換する // 16bitカウント値を10進数にして7SEG-LEDに表示するためのBCD変換 // //----------------------------------------------------------------------------- // Copyright (c) 2013 by shio This model is the confidential and // proprietary property of shio and the possession or use of this // file requires a written license from shio. //------------------------------------------------------------------------------ // Modification history : // 2013/02/16 shio created //----------------------------------------------------------------------------- module bin2dec (/*AUTOARG*/ // Outputs DIGIT5, DIGIT4, DIGIT3, DIGIT2, DIGIT1, DIGITS, // Inputs CLK, XRST, LOAD, BINDT ); // Ports input CLK ; // clock input XRST ; // reset input LOAD ; // ロード input [15:0] BINDT ; // バイナリデータ(変換元) output [3:0] DIGIT5; // セグメント5(万の位) output [3:0] DIGIT4; // セグメント4(千の位) output [3:0] DIGIT3; // セグメント3(百の位) output [3:0] DIGIT2; // セグメント2(十の位) output [3:0] DIGIT1; // セグメント1(一の位) output [19:0] DIGITS; // セグメント5..1(見やすいようにマージ) // Signals reg [15:0] sr_bindt ; reg [3:0] sr_digit5; reg [3:0] sr_digit4; reg [3:0] sr_digit3; reg [3:0] sr_digit2; reg [3:0] sr_digit1; reg sr_end ; // 変換が終了したことを示すフラグ reg [19:0] sr_digits; // 各位毎に減算の繰返し always @(negedge XRST or posedge CLK)begin if(!XRST)begin sr_bindt <= {16{1'b0}}; sr_digit5 <= {4{1'b0}}; sr_digit4 <= {4{1'b0}}; sr_digit3 <= {4{1'b0}}; sr_digit2 <= {4{1'b0}}; sr_digit1 <= {4{1'b0}}; sr_end <= 1'b0; end else begin if(LOAD==1'b1)begin sr_bindt <= BINDT; sr_digit5 <= {4{1'b0}}; sr_digit4 <= {4{1'b0}}; sr_digit3 <= {4{1'b0}}; sr_digit2 <= {4{1'b0}}; sr_digit1 <= {4{1'b0}}; sr_end <= 1'b0; end else if(sr_bindt>=16'd10000)begin sr_bindt <= sr_bindt - 16'd10000; sr_digit5 <= sr_digit5 + 1'b1; end else if(sr_bindt>=16'd1000)begin sr_bindt <= sr_bindt - 16'd1000; sr_digit4 <= sr_digit4 + 1'b1; end else if(sr_bindt>=16'd100)begin sr_bindt <= sr_bindt - 16'd100; sr_digit3 <= sr_digit3 + 1'b1; end else if(sr_bindt>=16'd10)begin sr_bindt <= sr_bindt - 16'd10; sr_digit2 <= sr_digit2 + 1'b1; end //else if(sr_bindt>=16'd1)begin // sr_bindt <= sr_bindt - 16'd1; // sr_digit1 <= sr_digit1 + 1'b1; //end // 1の位は直接代入して終了信号を生成 else begin sr_digit1 <= sr_bindt; sr_end <= 1'b1; end end end // 終了信号でラッチ always @(negedge XRST or posedge CLK)begin if(!XRST)begin sr_digits = {20{1'b0}}; end else begin if(sr_end==1'b1)begin sr_digits = {sr_digit5,sr_digit4,sr_digit3,sr_digit2,sr_digit1}; end end end // 端子出力 assign DIGIT5 = sr_digit5; assign DIGIT4 = sr_digit4; assign DIGIT3 = sr_digit3; assign DIGIT2 = sr_digit2; assign DIGIT1 = sr_digit1; assign DIGITS = sr_digits; endmodule
(3) シミュレーション
テストベンチは以下の通り。ModelSim ALTERA STARTER EDITION 10.0c で確認。
//----------------------------------------------------------------------------- // Title : bin2dec // Project : none //----------------------------------------------------------------------------- // File : tb_top.sv // Author : shio // Created : 16.02.2013 // Last modified : 16.02.2013 //----------------------------------------------------------------------------- // Description : // //----------------------------------------------------------------------------- // Copyright (c) 2013 by shio This model is the confidential and // proprietary property of shio and the possession or use of this // file requires a written license from shio. //------------------------------------------------------------------------------ // Modification history : // 16.02.2013 : created //----------------------------------------------------------------------------- `timescale 1ps/1ps module tb_top; //-------------------------------------------------------------------------------- // 定数宣言 //-------------------------------------------------------------------------------- parameter C_CYC_CLK = 10.000ns; // クロック(100MHz) parameter C_RST_TIME = 105.000ns; // リセット時間 //-------------------------------------------------------------------------------- // シグナル宣言 //-------------------------------------------------------------------------------- // クロックとリセットの生成 bit s_CLK ; bit s_XRST ; bit LOAD ; bit [15:0] BINDT ; logic [3:0] DIGIT5 ; logic [3:0] DIGIT4 ; logic [3:0] DIGIT3 ; logic [3:0] DIGIT2 ; logic [3:0] DIGIT1 ; logic [19:0] DIGITS ; //-------------------------------------------------------------------------------- // クロックとリセットの生成 //-------------------------------------------------------------------------------- // マスタクロック(初期値+OFFSET+繰り返し) initial begin s_CLK = 0; forever #(C_CYC_CLK/2) s_CLK = ~s_CLK; end // リセット(fork~joinで並列処理) initial fork #0 s_XRST = 0; #C_RST_TIME s_XRST = 1; join //-------------------------------------------------------------------------------- // タスク //-------------------------------------------------------------------------------- //-------------------------------------------------------------------------------- // 外部端子設定 //-------------------------------------------------------------------------------- initial begin // リセット解除待ち repeat(20) @(posedge s_CLK); // message $display(""); $display("****************************************"); $display("* test *"); $display("****************************************"); // 1st-BINDT $display("1st-BINDT"); BINDT = 65535; repeat(2) @(posedge s_CLK); #(1ns); LOAD = 1; #(C_CYC_CLK);LOAD = 0; repeat(40) @(posedge s_CLK); // 2nd-BINDT $display("2nd-BINDT"); BINDT = 0; repeat(2) @(posedge s_CLK); #(1ns); LOAD = 1; #(C_CYC_CLK);LOAD = 0; repeat(10) @(posedge s_CLK); // 3rd-BINDT $display("3rd-BINDT"); BINDT = 64999; repeat(2) @(posedge s_CLK); #(1ns); LOAD = 1; #(C_CYC_CLK);LOAD = 0; repeat(40) @(posedge s_CLK); // 4th-BINDT $display("4th-BINDT"); BINDT = 10; repeat(2) @(posedge s_CLK); #(1ns); LOAD = 1; #(C_CYC_CLK);LOAD = 0; repeat(10) @(posedge s_CLK); // 5th-BINDT $display("5th-BINDT"); BINDT = 100; repeat(2) @(posedge s_CLK); #(1ns); LOAD = 1; #(C_CYC_CLK);LOAD = 0; repeat(10) @(posedge s_CLK); // 6th-BINDT $display("6th-BINDT"); BINDT = 10000; repeat(2) @(posedge s_CLK); #(1ns); LOAD = 1; #(C_CYC_CLK);LOAD = 0; repeat(10) @(posedge s_CLK); // sim終了 repeat(10) @(posedge s_CLK); $display("### Simulation end ###"); $finish; end //-------------------------------------------------------------------------------- // インスタンス //-------------------------------------------------------------------------------- //---------------------------------------- // DUTs //---------------------------------------- bin2dec u_bin2dec ( .CLK ( s_CLK ), .XRST ( s_XRST ), .* ); endmoduleシミュレーション結果です。
LOAD=1でBINDT[15:0]をロード。その後、万の位から順に1CLK毎に処理される。
1の位は直接代入で良く、1CLKで処理終わり、ついでに終了フラグsr_endを生成。
20bitのBCDデータとしてはsr_endでラッチ。(これは要らないと思うけど一応見やすいので)
レイテンシが入力する値により変わるので、最大の遅延を考慮して固定遅延後にラッチしてもいいかもしれませんね。そもそも7SEGを点灯する程度の速度ならラッチも不要か・・。
7SEGは1個当り100us~1ms程度で周期的に点灯させれば良いのかな? (10ms周期だと人間の目にはちらついて見えないようなので)
レイテンシは、万の位+千の位+百の位+十の位となる。
65535の場合は6+5+5+3=19CLK。0だと1CLK。10,100,1000,10000は2CLK。
最大は、64999で28CLKなので、30CLK後にラッチしても良いのかな~。
(3) その他
方法は他にもあって、減算を除算+余りで作ればレイテンシは最大5CLKとかになりますね・・。
また、0~BINDTまで回るカウンタを回し、10,100,1000,10000のイネーブルを作成、各位毎にカウントアップさせる方法もあります。最大65535CLKもかかるけど。
16bitくらいならレイテンシも回路規模も大したことない感じ。
32bitでは、レイテンシは69CLKくらいですが回路規模が大きいのかな?
大きなFPGAなら大丈夫かも。DE0-Nanoでインプリしても良いのですが・・そのうちということで^^;