2進からBCDへの変換回路 のバックアップソース(No.1)

更新

[[公開メモ]]

#contents

* 概要 [#y15acbf7]

marsee さんから頂いたお題で、通常の2進数表現符号なし整数を BCD (二進化十進表現) 
に変換する回路を書いてみました。

http://ja.wikipedia.org/wiki/%E4%BA%8C%E9%80%B2%E5%8C%96%E5%8D%81%E9%80%B2%E8%A1%A8%E7%8F%BE

* ソース [#ebed19cc]

 LANG:verilog(linenumber)
 // 2進数を BCD に直す回路
 // bin に変換元の符号なし整数をセットして start に1を立てる
 // 次クロックで busy が立つので、降りるまで待って bcd を読む
 // BITS により、任意ビット数数値を変換可能
 // 計算時間は BITS * 6 クロック程度
 module bin2bcd #(
     parameter  BITS        = 10
     ) (clk, rst, start, busy, bin, bcd);
 
     // log 16 = 1.20412 < 1205/1000 を使って BCD 表現に必要な桁数を求める
     localparam BCD_DIGITS  = ( BITS * 1205 / 1000 - 1 ) / 4 + 1; 
     localparam BCD_DIGITS_BITS 
                            = BCD_DIGITS < 2   ? 1 :
                              BCD_DIGITS < 4   ? 2 :
                              BCD_DIGITS < 8   ? 3 :
                              BCD_DIGITS < 16  ? 4 :
                              BCD_DIGITS < 32  ? 5 :
                              BCD_DIGITS < 64  ? 6 :
                              BCD_DIGITS < 128 ? 7 : 8;
 
     input  wire clk;
     input  wire rst;
     input  wire start;
     output wire busy;
     input  wire [BITS-1:0]         bin;
     output wire [BCD_DIGITS*4-1:0] bcd;
 
     // 割り算用レジスタ
     reg [BITS-1:0]   numerator;     // 分子
     reg [BITS+4-1:0] denominator;   // 分母
     reg [3:0]        quotient;      // 商
 
     // 10^n << 3 を保持する ROM
     reg [BITS+4-1:0] denominators[0:BCD_DIGITS-1];
     integer i;
     initial // ROM の初期化
         for (i=0; i<BCD_DIGITS; i=i+1) 
             denominators[i] = ( 10 ** i ) * ( 2 ** 3 );
 
     // ステートマシンは state, digit を変数として動作する
 
     reg [2:0] state;
     reg [BCD_DIGITS_BITS-1:0] digit;
 
     localparam stIdle    = 0;
     localparam stDivide0 = 1;
     localparam stDivide1 = 2;
     localparam stDivide2 = 3;
     localparam stDivide3 = 4;
     localparam stDivide4 = 5;
     localparam stNext    = 6;
 
     // 計算結果を保持するレジスタ
     reg [3:0] bcd_internal[0:BCD_DIGITS-1];
 
     always @(posedge clk) 
         if (rst) begin
             state <= stIdle;
         end else
         case (state)
         stIdle: begin
                 numerator   <= bin;
                 digit       <= BCD_DIGITS - 1;
                 if (start)
                     state <= stDivide0;
             end
         stDivide0: begin
                 // 分母に 10^n << 3 を用意する
                 denominator <= denominators[digit];
                 state <= stDivide1;
             end
         stDivide1, stDivide2, stDivide3, stDivide4: begin
                 // 割り算して商を得る
                 if (numerator >= denominator) begin
                     quotient <= { quotient, 1'b1 };
                     numerator <= numerator - denominator;
                 end else begin
                     quotient <= { quotient, 1'b0 };
                 end
                 denominator <= denominator >> 1;
 
                 if (state != stDivide4) begin
                     state <= state + 1;
                 end else begin
                     state <= stNext;
                 end
             end
         stNext: begin
                 // 結果を格納して次へ
                 bcd_internal[digit] <= quotient;
                 if (digit==0) begin
                     state <= stIdle;
                 end else begin
                     digit <= digit - 1;
                     state <= stDivide0;
                 end
             end
         endcase
 
     // 出力に繋ぐ
     assign busy = state != stIdle;
     generate
         genvar j;
         for (j=0; j<BCD_DIGITS; j=j+1) begin: bcd_connection
             assign bcd[j*4 +: 4] = bcd_internal[j];
         end
     endgenerate
 
 endmodule

* テストベンチ [#tc58bda1]

 LANG:verilog(linenumber)
 module bin2bcd_test;
 
     // ここを変えれば異なるビット数についてもテスト可能
     parameter BITS = 10;
     localparam BCD_DIGITS  = ( BITS * 1205 / 1000 - 1 ) / 4 + 1; // log 16 = 1.20412
 
 	// Inputs
 	reg clk;
 	reg rst;
 	reg start;
 	reg [BITS-1:0] bin;
 
 	// Outputs
 	wire busy;
 	wire [BCD_DIGITS*4-1:0] bcd;
 
 	// Instantiate the Unit Under Test (UUT)
 	bin2bcd #(BITS) uut (
 		.clk(clk), 
 		.rst(rst), 
 		.start(start), 
 		.busy(busy), 
 		.bin(bin), 
 		.bcd(bcd)
 	);
 
     // value を入力して expect が出てくることを確かめる
     task test_with;
         input [BITS-1:0] value;
         input [BCD_DIGITS*4-1:0] expect;
         begin
             bin = value; 
             start = 1; 
             @(posedge clk); 
             start = 0;
 
             @(negedge busy); 
             if (bcd!==expect) 
                 $display("*** ERROR: expecting %x (%d) but found %x.",
                     expect, value, bcd);
         end
     endtask
 
     // クロック
     always #5 clk = !clk;
 
 	initial begin
 		// Initialize Inputs
 		clk = 0;
 		rst = 1;
 		start = 0;
 		bin = 0;
 
 		// Wait 100 ns for global reset to finish
 		#100;
         
 		// Add stimulus here
         rst = 0;
 
         repeat(10) @(posedge clk);
 
         // 境界値を重点的に
         test_with(0, 'h0);
         test_with(255, 'h255);
         test_with(123, 'h123);
         test_with(128, 'h128);
         test_with(127, 'h127);
         test_with(64, 'h64);
         test_with(63, 'h63);
         test_with(100, 'h100);
         test_with(99, 'h99);
         test_with(10, 'h10);
         test_with(9, 'h9);
 
 	end
       
 endmodule

* コメント [#h185d7db]

#article_kcaptcha

Counter: 19518 (from 2010/06/03), today: 9, yesterday: 0