情報画像学実験II

実験II-1. 論理回路

回路作成例・解説


第4週目-課題1

図1 に記述例を示す。

module COUNTER5(
    input CLK,
    input RST,
    output reg [2:0] OUT
    );
    
    always@(posedge CLK) begin
        if(RST) begin    // リセット
            OUT <= 0;
        end else begin
            if(OUT==4) begin    // 4の次は 0
                OUT <= 0;
            end else begin    // それ以外の場合は1増加
                OUT <= OUT+1;
            end
        end
    end
endmodule
図1. 5進カウンタの Verilog 記述例

第4週目-課題3

サンプルプログラムがそうであったように、Verilog には 同じような記述を何度も繰り返し行う必要がしばしば発生する。一応、繰り返しを避けるための記法もいくらか用意されており、創意工夫で繰り返しを減らすこともできる。しかし、繰り返し書いてしまった方が、分かり易く、手っ取り早いことも多い。エクセルの連番機能とコピー&ペーストを活用することにより、繰り返し記述する苦痛とミスもある程度は軽減できる。頑張って書いて欲しい。

1. 図9 に左右反転フィルタの記述例を示す。なお、繰り返しになる箇所は中略している。コピー&ペーストするときは適宜補うこと。

module FILTER(
        input [7:0] S00,
        input [7:0] S01,
        input [7:0] S02,
           /* 中略 */
        input [7:0] S30,
        input [7:0] S31,
        
        output reg [7:0] D00,
        output reg [7:0] D01,
        output reg [7:0] D02,
           /* 中略 */
        output reg [7:0] D30,
        output reg [7:0] D31,
        
        input CLK,
        input RESET,
        input [4:0] ROW,
        input IN,
        output reg OUT
        );
        
        always@(posedge CLK) begin
                D00 <= S31;
                D01 <= S30;
                D02 <= S29;
                D03 <= S28;
                D04 <= S27;
                D05 <= S26;
                D06 <= S25;
                D07 <= S24;
                D08 <= S23;
                D09 <= S22;
                D10 <= S21;
                D11 <= S20;
                D12 <= S19;
                D13 <= S18;
                D14 <= S17;
                D15 <= S16;
                D16 <= S15;
                D17 <= S14;
                D18 <= S13;
                D19 <= S12;
                D20 <= S11;
                D21 <= S10;
                D22 <= S09;
                D23 <= S08;
                D24 <= S07;
                D25 <= S06;
                D26 <= S05;
                D27 <= S04;
                D28 <= S03;
                D29 <= S02;
                D30 <= S01;
                D31 <= S00;
                
                OUT <= IN;
        end
endmodule
図9. 左右反転フィルタの Verilog 記述例

2. 図10 に一次空間微分フィルタ(横方向) の Verilog 記述例を示す。このフィルタの出力値は隣接する2ビットの差である。各画素の定義域は 0〜255 であることから、出力値の値域は -255 〜 255 となる。しかし、出力画像もまた256調画像とする必要があることから、出力値を (本来の出力値)÷2+127 としている。

この計算はモジュール TWO_COLUMN_DIFFERENTIAL 内で行っている。算術演算を行うため画素信号 S, SA を signed 付きの信号線 SIGNED_S, SIGNED_SA に変換している。また、画素値が 128〜255 のとき正数として計算させるため、SIGNED_S, SIGNED_SA は 9ビットバスとし、最上位ビット、すなわち符号ビットは 0 としている。なお除算演算子 / は ISE では使用できないと第3週目に説明したが、定数値 2 で割るなど、シフト演算子で容易に置き換えられるような演算の場合には使用できる。

module FILTER(
        input [7:0] S00,
        input [7:0] S01,
        input [7:0] S02,
           /* 中略 */
        input [7:0] S30,
        input [7:0] S31,
        
        output [7:0] D00,
        output [7:0] D01,
        output [7:0] D02,
           /* 中略 */
        output [7:0] D30,
        output [7:0] D31,
        
        input CLK,
        input RESET,
        input [4:0] ROW,
        input IN,
        output reg OUT
        );
        
        TWO_COLUMN_DIFFERENTIAL U00 (.S(S00), .SA(S01), .D(D00), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U01 (.S(S01), .SA(S02), .D(D01), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U02 (.S(S02), .SA(S03), .D(D02), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U03 (.S(S03), .SA(S04), .D(D03), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U04 (.S(S04), .SA(S05), .D(D04), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U05 (.S(S05), .SA(S06), .D(D05), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U06 (.S(S06), .SA(S07), .D(D06), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U07 (.S(S07), .SA(S08), .D(D07), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U08 (.S(S08), .SA(S09), .D(D08), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U09 (.S(S09), .SA(S10), .D(D09), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U10 (.S(S10), .SA(S11), .D(D10), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U11 (.S(S11), .SA(S12), .D(D11), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U12 (.S(S12), .SA(S13), .D(D12), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U13 (.S(S13), .SA(S14), .D(D13), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U14 (.S(S14), .SA(S15), .D(D14), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U15 (.S(S15), .SA(S16), .D(D15), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U16 (.S(S16), .SA(S17), .D(D16), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U17 (.S(S17), .SA(S18), .D(D17), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U18 (.S(S18), .SA(S19), .D(D18), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U19 (.S(S19), .SA(S20), .D(D19), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U20 (.S(S20), .SA(S21), .D(D20), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U21 (.S(S21), .SA(S22), .D(D21), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U22 (.S(S22), .SA(S23), .D(D22), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U23 (.S(S23), .SA(S24), .D(D23), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U24 (.S(S24), .SA(S25), .D(D24), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U25 (.S(S25), .SA(S26), .D(D25), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U26 (.S(S26), .SA(S27), .D(D26), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U27 (.S(S27), .SA(S28), .D(D27), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U28 (.S(S28), .SA(S29), .D(D28), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U29 (.S(S29), .SA(S30), .D(D29), .CLK(CLK));
        TWO_COLUMN_DIFFERENTIAL U30 (.S(S30), .SA(S31), .D(D30), .CLK(CLK));
        assign D31 = 127;
            /* S32 なる画素はないので、右端 D31 の出力値は
                とりあえず 127 にする。大した意味はない。 */
        
        always @(posedge CLK) begin
                OUT <= IN;
        end
endmodule

module TWO_COLUMN_DIFFERENTIAL(
        input [7:0] S,
        input [7:0] SA,
        output reg [7:0] D,
        input CLK
        );
        
        wire signed [8:0] SIGNED_S;    // signed 付き信号へ変換
        wire signed [8:0] SIGNED_SA;
        
        assign SIGNED_S = {1'b0, S};    // 最上位に符号ビットを付加
        assign SIGNED_SA = {1'b0, SA};
        
        always@(posedge CLK) begin
                D <= (SIGNED_SA - SIGNED_S) / 2 + 127;
        end
endmodule
図10. 一次空間微分フィルタ(横方向) の Verilog 記述例

3. 今までのフィルタでは各行のデータをそれぞれ独立に処理していた。そのため、各行毎、入力されたデータについて、処理結果を即時出力することができた。しかし、縦方向の一次空間微分フィルタにおいては、ある行の画素と、隣接する行の画素との差をとる必要があり、行毎の演算が独立していない。そのため、過去に入力された演算に必要な行データをフィルタ内に記憶しておく必要がある。

図11 に一次空間微分フィルタ(縦方向) の Verilog 記述例を示す。このフィルタは制御用レジスタ IR を用いながら、以下の通り動作する。

  1. 最初、IN = 0, IR = 00 である。
  2. IN = 1 となり、1行目が入力されたとき、IR = 01 となり、1行目の画像データはモジュール ONE_COLUMN_DIFFERENTIAL 内のレジスタ R に記憶される。ここで OUT=0 となり、フィルタはデータ出力しない。
  3. 2行目が入力されたとき、IR = 11 となる。2行目と1行目の差を計算し、1行目の出力データとして出力する。
  4. 以降、同様の処理を32行目のデータが入力され、31行目のデータが出力されるまで繰り返す。
  5. 32行全てのデータが入力し終わったことから、以後 IN = 0 となる。フィルタは 32行目のデータとして 127 を出力する。このとき、IR = 10 とし、OUT = 1 とする。
  6. 32行全てのデータを出力し終えたことで、シミュレーションは終了する。
module FILTER(
        input [7:0] S00,
        input [7:0] S01,
        input [7:0] S02,
           /* 中略 */
        input [7:0] S30,
        input [7:0] S31,
        
        output [7:0] D00,
        output [7:0] D01,
        output [7:0] D02,
           /* 中略 */
        output [7:0] D30,
        output [7:0] D31,
        
        input CLK,
        input RESET,
        input [4:0] ROW,
        input IN,
        output OUT
        );
        
        reg [1:0] IR;
        
        ONE_COLUMN_DIFFERENTIAL U00 (.S(S00), .D(D00), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U01 (.S(S01), .D(D01), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U02 (.S(S02), .D(D02), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U03 (.S(S03), .D(D03), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U04 (.S(S04), .D(D04), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U05 (.S(S05), .D(D05), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U06 (.S(S06), .D(D06), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U07 (.S(S07), .D(D07), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U08 (.S(S08), .D(D08), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U09 (.S(S09), .D(D09), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U10 (.S(S10), .D(D10), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U11 (.S(S11), .D(D11), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U12 (.S(S12), .D(D12), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U13 (.S(S13), .D(D13), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U14 (.S(S14), .D(D14), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U15 (.S(S15), .D(D15), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U16 (.S(S16), .D(D16), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U17 (.S(S17), .D(D17), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U18 (.S(S18), .D(D18), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U19 (.S(S19), .D(D19), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U20 (.S(S20), .D(D20), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U21 (.S(S21), .D(D21), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U22 (.S(S22), .D(D22), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U23 (.S(S23), .D(D23), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U24 (.S(S24), .D(D24), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U25 (.S(S25), .D(D25), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U26 (.S(S26), .D(D26), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U27 (.S(S27), .D(D27), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U28 (.S(S28), .D(D28), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U29 (.S(S29), .D(D29), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U30 (.S(S30), .D(D30), .IN(IN), .CLK(CLK));
        ONE_COLUMN_DIFFERENTIAL U31 (.S(S31), .D(D31), .IN(IN), .CLK(CLK));

        always@(posedge CLK) begin
                    // 状態レジスタ IR による状態遷移器
                if(RESET) begin
                        IR <= 2'b00;
                end else begin
                        if(IN) begin
                                IR <= (IR == 2'b00) ? 2'b01 : 2'b11;
                        end else begin
                                IR <= (IR == 2'b11) ? 2'b10 : 2'b00;
                        end
                end
        end
        
        assign OUT = IR[1];    // IR = 10 または 11 のとき、データ出力
endmodule

module ONE_COLUMN_DIFFERENTIAL(
        input [7:0] S,
        input IN,
        output reg [7:0] D,
        input CLK
        );
        
        reg [7:0] R;
        
        wire signed [8:0] SIGNED_R;
        wire signed [8:0] SIGNED_S;
        
        assign SIGNED_R = {1'b0, R};
        assign SIGNED_S = {1'b0, S};
        
        always@(posedge CLK) begin
                D <= IN ? (SIGNED_R - SIGNED_S) / 2 + 127 : 127;
                R <= S;
                    // 入力された画素データを次行処理時に用いるため、 R に記憶
        end
endmodule
図11. 一次空間微分フィルタ(縦方向) の Verilog 記述例

第3週目の回路作成例・解説に戻る
実験II-1トップページに戻る
難波担当実験・演習のページに戻る

難波 一輝 (助教・伊藤・北神・難波研究室)
工学部1号棟4階409号室、内線3255、043-290-3255、namba@ieee.org