図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 |
サンプルプログラムがそうであったように、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 |
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 |
3. 今までのフィルタでは各行のデータをそれぞれ独立に処理していた。そのため、各行毎、入力されたデータについて、処理結果を即時出力することができた。しかし、縦方向の一次空間微分フィルタにおいては、ある行の画素と、隣接する行の画素との差をとる必要があり、行毎の演算が独立していない。そのため、過去に入力された演算に必要な行データをフィルタ内に記憶しておく必要がある。
図11 に一次空間微分フィルタ(縦方向) の Verilog 記述例を示す。このフィルタは制御用レジスタ IR を用いながら、以下の通り動作する。
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 |
難波 一輝 (助教・伊藤・北神・難波研究室)
工学部1号棟4階409号室、内線3255、043-290-3255、namba@ieee.org