FPGA活用回路&サンプル記述集(3) ―― ビデオ信号処理回路
tag: 半導体 電子回路 ディジタル・デザイン
技術解説 2009年3月25日
module LineBuffer_4lines
(
RESET,
WA,
WEN,
WCK,
WD,
RA,
REN,
RCK,
RD0,
RD1,
RD2
);
parameter DataWidth = 24;
//データ幅はRGB各8ビットに対応できるように24ビットを設定しています.
parameter XADRSWidth = 10; //水平アドレス幅に10ビットを設定,最大1024ピクセル長のラインをサポートします.
parameter YADRSWidth = 10; //垂直アドレス幅に10ビットを設定.しかしライン・バッファが4本であれば,下位2ビットしか使われません.
//ここまでのパラメータは必要に応じて変更可能です.
parameter ADRSWidth = XADRSWidth + YADRSWidth;
input RESET; //リセット入力
input [ADRSWidth-1:0] WA; //書き込みアドレス入力
input WEN; //書き込みイネーブル入力
input WCK; //書き込みクロック入力
input [DataWidth-1:0] WD; //書き込みデータ入力
input [ADRSWidth-1:0] RA; //読み出しアドレス入力
input REN; //読み出し(データ更新)イネーブル入力
input RCK; //読み出しクロック入力
output [DataWidth-1:0] RD0; //下位ライン読み出しデータ出力
output [DataWidth-1:0] RD1; //中間ライン読み出しデータ出力
output [DataWidth-1:0] RD2; //上位ライン読み出しデータ出力
wire [DataWidth-1:0] RAM_q0;
wire [DataWidth-1:0] RAM_q1;
wire [DataWidth-1:0] RAM_q2;
wire [DataWidth-1:0] RAM_q3;
//メモリ・ブロック選択用のアドレスです.
//
wire [1:0] LineAddress = WA[ADRSWidth-1:XADRSWidth];
//書き込み側メモリ・ブロックの選択信号です.
reg RAMsel0;
reg RAMsel1;
reg RAMsel2;
reg RAMsel3;
//ブロック図における「デコーダ」です.
//書き込み側メモリ・ブロックの選択信号をWENとメモリ・ブロック選択用アドレスを元に生成します.
always @ ( WEN or RESET ) begin
if( ~ RESET | ~ WEN ) begin
RAMsel0 <= 0;
RAMsel1 <= 0;
RAMsel2 <= 0;
RAMsel3 <= 0;
end
else begin
case ( LineAddress[1:0] )
0: RAMsel0 <= WEN;
1: RAMsel1 <= WEN;
2: RAMsel2 <= WEN;
3: RAMsel3 <= WEN;
endcase
end
end
//4本のライン・バッファメモリです.四つのメモリ・ブロックを使用します.
RAMDP2 LineBuffer0 (.clka( WCK ), .dina( WD ), .addra( WA[XADRSWidth-1:0] ), .wea( RAMsel0 ), .clkb( RCK ), .addrb( RA[XADRSWidth-1:0] ), .doutb( RAM_q0 ) );
defparam LineBuffer0.DataWidth = DataWidth;
defparam LineBuffer0.ADRSWidth = XADRSWidth;
RAMDP2 LineBuffer1 (.clka( WCK ), .dina( WD ), .addra( WA[XADRSWidth-1:0] ), .wea( RAMsel1 ), .clkb( RCK ), .addrb( RA[XADRSWidth-1:0] ), .doutb( RAM_q1 ) );
defparam LineBuffer1.DataWidth = DataWidth;
defparam LineBuffer1.ADRSWidth = XADRSWidth;
RAMDP2 LineBuffer2 (.clka( WCK ), .dina( WD ), .addra( WA[XADRSWidth-1:0] ), .wea( RAMsel2 ), .clkb( RCK ), .addrb( RA[XADRSWidth-1:0] ), .doutb( RAM_q2 ) );
defparam LineBuffer2.DataWidth = DataWidth;
defparam LineBuffer2.ADRSWidth = XADRSWidth;
RAMDP2 LineBuffer3 (.clka( WCK ), .dina( WD ), .addra( WA[XADRSWidth-1:0] ), .wea( RAMsel3 ), .clkb( RCK ), .addrb( RA[XADRSWidth-1:0] ), .doutb( RAM_q3 ) );
defparam LineBuffer3.DataWidth = DataWidth;
defparam LineBuffer3.ADRSWidth = XADRSWidth;
//データ・レジスタです.メモリと,セレクタを通るので一段レジスタをおきます.
reg [DataWidth-1:0] RD0d;
reg [DataWidth-1:0] RD1d;
reg [DataWidth-1:0] RD2d;
reg RENd;
//読み出しメモリ・セレクタ用アドレスです.
reg [1:0] R_LineAddress0;
reg [1:0] R_LineAddress1;
reg [1:0] R_LineAddress2;
//読み出しメモリ・セレクタ
always @ (posedge RCK) begin
if (~ RESET ) begin
RD0d <= 0;
RD1d <= 0;
RD2d <= 0;
RENd <= 0;
R_LineAddress0 <= 0;
R_LineAddress1 <= 0;
R_LineAddress2 <= 0;
end
else begin
RENd <= REN; //読み出しメモリ・セレクタは前段にメモリ・ブロックによるレイテンシがあるため,RENを調整します.
//セレクタ用アドレスを生成します.書き込み側垂直アドレスの相対位置を指すようにします.
R_LineAddress0 <= WA[ADRSWidth-1:XADRSWidth] - 1; //3×3フィルタの下位ライン用のセレクタです.
R_LineAddress1 <= WA[ADRSWidth-1:XADRSWidth] - 2; //3×3フィルタの中間ライン用のセレクタです.
R_LineAddress2 <= WA[ADRSWidth-1:XADRSWidth] - 3; //3×3フィルタの上位ライン用のセレクタです.
//読み出しメモリ・セレクタ部です.
if ( RENd ) begin
case ( R_LineAddress0[1:0] )
0: RD0d <= RAM_q0;
1: RD0d <= RAM_q1;
2: RD0d <= RAM_q2;
3: RD0d <= RAM_q3;
endcase
case ( R_LineAddress1[1:0] )
0: RD1d <= RAM_q0;
1: RD1d <= RAM_q1;
2: RD1d <= RAM_q2;
3: RD1d <= RAM_q3;
endcase
case ( R_LineAddress2[1:0] )
0: RD2d <= RAM_q0;
1: RD2d <= RAM_q1;
2: RD2d <= RAM_q2;
3: RD2d <= RAM_q3;
endcase
end
end
end
//読み出しデータをポートに出力します.
assign RD0 = RD0d;
assign RD1 = RD1d;
assign RD2 = RD2d;
endmodule
(
RESET,
WA,
WEN,
WCK,
WD,
RA,
REN,
RCK,
RD0,
RD1,
RD2
);
parameter DataWidth = 24;
//データ幅はRGB各8ビットに対応できるように24ビットを設定しています.
parameter XADRSWidth = 10; //水平アドレス幅に10ビットを設定,最大1024ピクセル長のラインをサポートします.
parameter YADRSWidth = 10; //垂直アドレス幅に10ビットを設定.しかしライン・バッファが4本であれば,下位2ビットしか使われません.
//ここまでのパラメータは必要に応じて変更可能です.
parameter ADRSWidth = XADRSWidth + YADRSWidth;
input RESET; //リセット入力
input [ADRSWidth-1:0] WA; //書き込みアドレス入力
input WEN; //書き込みイネーブル入力
input WCK; //書き込みクロック入力
input [DataWidth-1:0] WD; //書き込みデータ入力
input [ADRSWidth-1:0] RA; //読み出しアドレス入力
input REN; //読み出し(データ更新)イネーブル入力
input RCK; //読み出しクロック入力
output [DataWidth-1:0] RD0; //下位ライン読み出しデータ出力
output [DataWidth-1:0] RD1; //中間ライン読み出しデータ出力
output [DataWidth-1:0] RD2; //上位ライン読み出しデータ出力
wire [DataWidth-1:0] RAM_q0;
wire [DataWidth-1:0] RAM_q1;
wire [DataWidth-1:0] RAM_q2;
wire [DataWidth-1:0] RAM_q3;
//メモリ・ブロック選択用のアドレスです.
//
wire [1:0] LineAddress = WA[ADRSWidth-1:XADRSWidth];
//書き込み側メモリ・ブロックの選択信号です.
reg RAMsel0;
reg RAMsel1;
reg RAMsel2;
reg RAMsel3;
//ブロック図における「デコーダ」です.
//書き込み側メモリ・ブロックの選択信号をWENとメモリ・ブロック選択用アドレスを元に生成します.
always @ ( WEN or RESET ) begin
if( ~ RESET | ~ WEN ) begin
RAMsel0 <= 0;
RAMsel1 <= 0;
RAMsel2 <= 0;
RAMsel3 <= 0;
end
else begin
case ( LineAddress[1:0] )
0: RAMsel0 <= WEN;
1: RAMsel1 <= WEN;
2: RAMsel2 <= WEN;
3: RAMsel3 <= WEN;
endcase
end
end
//4本のライン・バッファメモリです.四つのメモリ・ブロックを使用します.
RAMDP2 LineBuffer0 (.clka( WCK ), .dina( WD ), .addra( WA[XADRSWidth-1:0] ), .wea( RAMsel0 ), .clkb( RCK ), .addrb( RA[XADRSWidth-1:0] ), .doutb( RAM_q0 ) );
defparam LineBuffer0.DataWidth = DataWidth;
defparam LineBuffer0.ADRSWidth = XADRSWidth;
RAMDP2 LineBuffer1 (.clka( WCK ), .dina( WD ), .addra( WA[XADRSWidth-1:0] ), .wea( RAMsel1 ), .clkb( RCK ), .addrb( RA[XADRSWidth-1:0] ), .doutb( RAM_q1 ) );
defparam LineBuffer1.DataWidth = DataWidth;
defparam LineBuffer1.ADRSWidth = XADRSWidth;
RAMDP2 LineBuffer2 (.clka( WCK ), .dina( WD ), .addra( WA[XADRSWidth-1:0] ), .wea( RAMsel2 ), .clkb( RCK ), .addrb( RA[XADRSWidth-1:0] ), .doutb( RAM_q2 ) );
defparam LineBuffer2.DataWidth = DataWidth;
defparam LineBuffer2.ADRSWidth = XADRSWidth;
RAMDP2 LineBuffer3 (.clka( WCK ), .dina( WD ), .addra( WA[XADRSWidth-1:0] ), .wea( RAMsel3 ), .clkb( RCK ), .addrb( RA[XADRSWidth-1:0] ), .doutb( RAM_q3 ) );
defparam LineBuffer3.DataWidth = DataWidth;
defparam LineBuffer3.ADRSWidth = XADRSWidth;
//データ・レジスタです.メモリと,セレクタを通るので一段レジスタをおきます.
reg [DataWidth-1:0] RD0d;
reg [DataWidth-1:0] RD1d;
reg [DataWidth-1:0] RD2d;
reg RENd;
//読み出しメモリ・セレクタ用アドレスです.
reg [1:0] R_LineAddress0;
reg [1:0] R_LineAddress1;
reg [1:0] R_LineAddress2;
//読み出しメモリ・セレクタ
always @ (posedge RCK) begin
if (~ RESET ) begin
RD0d <= 0;
RD1d <= 0;
RD2d <= 0;
RENd <= 0;
R_LineAddress0 <= 0;
R_LineAddress1 <= 0;
R_LineAddress2 <= 0;
end
else begin
RENd <= REN; //読み出しメモリ・セレクタは前段にメモリ・ブロックによるレイテンシがあるため,RENを調整します.
//セレクタ用アドレスを生成します.書き込み側垂直アドレスの相対位置を指すようにします.
R_LineAddress0 <= WA[ADRSWidth-1:XADRSWidth] - 1; //3×3フィルタの下位ライン用のセレクタです.
R_LineAddress1 <= WA[ADRSWidth-1:XADRSWidth] - 2; //3×3フィルタの中間ライン用のセレクタです.
R_LineAddress2 <= WA[ADRSWidth-1:XADRSWidth] - 3; //3×3フィルタの上位ライン用のセレクタです.
//読み出しメモリ・セレクタ部です.
if ( RENd ) begin
case ( R_LineAddress0[1:0] )
0: RD0d <= RAM_q0;
1: RD0d <= RAM_q1;
2: RD0d <= RAM_q2;
3: RD0d <= RAM_q3;
endcase
case ( R_LineAddress1[1:0] )
0: RD1d <= RAM_q0;
1: RD1d <= RAM_q1;
2: RD1d <= RAM_q2;
3: RD1d <= RAM_q3;
endcase
case ( R_LineAddress2[1:0] )
0: RD2d <= RAM_q0;
1: RD2d <= RAM_q1;
2: RD2d <= RAM_q2;
3: RD2d <= RAM_q3;
endcase
end
end
end
//読み出しデータをポートに出力します.
assign RD0 = RD0d;
assign RD1 = RD1d;
assign RD2 = RD2d;
endmodule
リスト2-1 4ライン構成のライン・バッファのVerilog HDL記述