@marsee101 たぶんこんなかんじで大丈夫じゃないかな~。3面のフレームバッファ(FB)は、各々表示中、表示待ち、書込中、書込待ちの状態を持ちます。(続く)
— KAWAZOME Ichiroさん (@ikwzm) 2013年5月1日
@marsee101 (続き) 表示(Read)側は、表示待ちのFBを見つけたら表示中だったFBを書込待ちにして表示待ちのFBを表示中にして、このFBから読み出す。表示待ちのFBが無ければ、引き続き表示中のFBから読み出す。(続く)
— KAWAZOME Ichiroさん (@ikwzm) 2013年5月1日
@marsee101 (続き) 書込側は全画面書き込んだ後、 書込待ちのFBがあるならば、今まで書込中だったFBを表示待ちにして、書込待ちのFBを書込中にしてこのFBに書き込む。書込待ちのFBが無ければ引き続き、書込中のFBに上書きする。(続く)
— KAWAZOME Ichiroさん (@ikwzm) 2013年5月1日
@marsee101 (続き)このように、書込中のFBと表示中のFBの間に、表示待ちのFBを用意することによって、表示側と書込側の速度やタイミングが異なっても表示が乱れないようにするのかな~なんて想像します(想像かよ!ひとりノリツッコミ)
— KAWAZOME Ichiroさん (@ikwzm) 2013年5月1日
// frame buffer life cycle
//
`default_nettype none
module fb_life_cycle (
input wire clk,
input wire reset,
input wire write_req,
input wire display_req,
input wire wtime_is_zero,
input wire dtime_is_zero,
output reg [1:0] state
);
localparam wait_write = 2'b00,
writing = 2'b01,
displaying = 2'b10,
wait_display = 2'b11;
always @(posedge clk) begin
if (reset)
state <= wait_write;
else begin
case (state)
wait_write :
if (write_req)
state <= writing;
writing :
if (write_req)
state <= writing;
else if (wtime_is_zero)
state <= wait_display;
wait_display :
if (display_req)
state <= displaying;
displaying :
if (display_req)
state <= displaying;
else if (dtime_is_zero)
state <=wait_write;
endcase
end
end
// synthesis translate_off
reg [12*8:1] FB_STATE;
always @(state) begin
case (state)
wait_write: FB_STATE <= "WAIT_WRITE";
writing: FB_STATE <= "WRITING";
displaying : FB_STATE <= "DISPLAYING";
wait_display : FB_STATE <= "WAIT_DISPLAY";
endcase
end
// synthesis translate_on
endmodule
`default_nettype wire
// Frame Buffer Life Cycle Testbench
//
`default_nettype none
`timescale 1us / 100ps
module fb_life_cycle_tb;
parameter integer write_life_cycle = 100000/60; // 60fps
parameter integer display_life_cycle = 100000/60; // 60fps
localparam wait_write = 2'b00,
writing = 2'b01,
displaying = 2'b10,
wait_display = 2'b11;
wire clk;
wire reset;
wire [1:0] state_1;
wire [1:0] state_2;
wire [1:0] state_3;
reg write_req_1, write_req_2, write_req_3;
reg display_req_1, display_req_2, display_req_3;
reg [23:0] wtime;
reg [23:0] dtime;
wire wtime_is_zero, dtime_is_zero;
reg reset_1b;
// clk のインスタンス
clk_gen #(
.CLK_PERIOD(10), // 10usec, 100kHz
.CLK_DUTY_CYCLE(0.5),
.CLK_OFFSET(0),
.START_STATE(1'b0)
) clki (
.clk_out(clk)
);
// reset_gen のインスタンス
reset_gen #(
.RESET_STATE(1'b1),
.RESET_TIME(10) // 10usec
) RESETi (
.reset_out(reset)
);
// Frame Buffer のインスタンス
fb_life_cycle fb_life_cycle_1 (
.clk(clk),
.reset(reset),
.write_req(write_req_1),
.display_req(display_req_1),
.wtime_is_zero(wtime_is_zero),
.dtime_is_zero(dtime_is_zero),
.state(state_1)
);
fb_life_cycle fb_life_cycle_2 (
.clk(clk),
.reset(reset),
.write_req(write_req_2),
.display_req(display_req_2),
.wtime_is_zero(wtime_is_zero),
.dtime_is_zero(dtime_is_zero),
.state(state_2)
);
fb_life_cycle fb_life_cycle_3 (
.clk(clk),
.reset(reset),
.write_req(write_req_3),
.display_req(display_req_3),
.wtime_is_zero(wtime_is_zero),
.dtime_is_zero(dtime_is_zero),
.state(state_3)
);
always @(posedge clk) begin
if (reset)
wtime <= write_life_cycle - 1;
else begin
if (wtime == 24'd0)
wtime <= write_life_cycle - 1;
else
wtime <= wtime - 24'd1;
end
end
assign wtime_is_zero = (wtime == 24'd0) ? 1'b1 : 1'b0;
always @(posedge clk) begin
if (reset)
dtime <= display_life_cycle - 1;
else begin
if (dtime == 24'd0)
dtime <= display_life_cycle - 1;
else
dtime <= dtime - 24'd1;
end
end
assign dtime_is_zero = (dtime == 24'd0) ? 1'b1 : 1'b0;
always @(posedge clk) begin
reset_1b <= reset;
end
always @* begin
if (~reset & reset_1b) begin
write_req_1 <= 1'b1; write_req_2 <= 1'b0; write_req_3 <= 1'b0;
end else if (wtime_is_zero) begin
if (state_1 == wait_write) begin
write_req_1 <= 1'b1; write_req_2 <= 1'b0; write_req_3 <= 1'b0;
end else if (state_2 == wait_write) begin
write_req_1 <= 1'b0; write_req_2 <= 1'b1; write_req_3 <= 1'b0;
end else if (state_3 == wait_write) begin
write_req_1 <= 1'b0; write_req_2 <= 1'b0; write_req_3 <= 1'b1;
end else if (state_1==writing && state_2!=wait_write && state_3!=wait_write) begin
write_req_1 <= 1'b1; write_req_2 <= 1'b0; write_req_3 <= 1'b0;
end else if (state_2==writing && state_1!=wait_write && state_3!=wait_write) begin
write_req_1 <= 1'b0; write_req_2 <= 1'b1; write_req_3 <= 1'b0;
end else if (state_3==writing && state_2!=wait_write && state_3!=wait_write) begin
write_req_1 <= 1'b0; write_req_2 <= 1'b0; write_req_3 <= 1'b1;
end else begin
write_req_1 <= 1'b0; write_req_2 <= 1'b0; write_req_3 <= 1'b0;
end
end else begin
write_req_1 <= 1'b0; write_req_2 <= 1'b0; write_req_3 <= 1'b0;
end
end
always @* begin
if (dtime_is_zero) begin
if (state_1 == wait_display) begin
display_req_1 <= 1'b1; display_req_2 <= 1'b0; display_req_3 <= 1'b0;
end else if (state_2 == wait_display) begin
display_req_1 <= 1'b0; display_req_2 <= 1'b1; display_req_3 <= 1'b0;
end else if (state_3 == wait_display) begin
display_req_1 <= 1'b0; display_req_2 <= 1'b0; display_req_3 <= 1'b1;
end else if (state_1==displaying && state_2!=wait_display && state_3!=wait_display) begin
display_req_1 <= 1'b1; display_req_2 <= 1'b0; display_req_3 <= 1'b0;
end else if (state_2==displaying && state_1!=wait_display && state_3!=wait_display) begin
display_req_1 <= 1'b0; display_req_2 <= 1'b1; display_req_3 <= 1'b0;
end else if (state_3==displaying && state_1!=wait_display && state_2!=wait_display) begin
display_req_1 <= 1'b0; display_req_2 <= 1'b0; display_req_3 <= 1'b1;
end else begin
display_req_1 <= 1'b0; display_req_2 <= 1'b0; display_req_3 <= 1'b0;
end
end else begin
display_req_1 <= 1'b0; display_req_2 <= 1'b0; display_req_3 <= 1'b0;
end
end
// synthesis translate_off
localparam integer CHAR_NUM = 12;
reg [CHAR_NUM*8:1] FB_STATE_1;
reg [CHAR_NUM*8:1] FB_STATE_2;
reg [CHAR_NUM*8:1] FB_STATE_3;
always @(state_1) begin
case (state_1)
wait_write: FB_STATE_1 <= "WAIT_WRITE";
writing: FB_STATE_1 <= "WRITING";
displaying : FB_STATE_1 <= "DISPLAYING";
wait_display : FB_STATE_1 <= "WAIT_DISPLAY";
endcase
end
always @(state_2) begin
case (state_2)
wait_write: FB_STATE_2 <= "WAIT_WRITE";
writing: FB_STATE_2 <= "WRITING";
displaying : FB_STATE_2 <= "DISPLAYING";
wait_display : FB_STATE_2 <= "WAIT_DISPLAY";
endcase
end
always @(state_3) begin
case (state_3)
wait_write: FB_STATE_3 <= "WAIT_WRITE";
writing: FB_STATE_3 <= "WRITING";
displaying : FB_STATE_3 <= "DISPLAYING";
wait_display : FB_STATE_3 <= "WAIT_DISPLAY";
endcase
end
// synthesis translate_on
endmodule
module clk_gen #(
parameter CLK_PERIOD = 100,
parameter real CLK_DUTY_CYCLE = 0.5,
parameter CLK_OFFSET = 0,
parameter START_STATE = 1'b0 )
(
output reg clk_out
);
begin
initial begin
#CLK_OFFSET;
forever
begin
clk_out = START_STATE;
#(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
#(CLK_PERIOD*CLK_DUTY_CYCLE);
end
end
end
endmodule
module reset_gen #(
parameter RESET_STATE = 1'b1,
parameter RESET_TIME = 100 )
(
output reg reset_out
);
begin
initial begin
reset_out = RESET_STATE;
#RESET_TIME;
reset_out = ~RESET_STATE;
end
end
endmodule
`default_nettype wire
// RGB - YCbCr変換
// Y = 0.257R + 0.504G + 0.098B + 16
// Cb = -0.148R - 0.291G + 0.439B + 128
// Cr = 0.439R - 0.368G - 0.071B + 128
// 但し、Yは255以上だったら飽和演算をして255に丸める。Cb, Crは16以下だったら16に、240以上だったら240に飽和演算を行う。
// 0捨1入バージョン
`default_nettype none
module conv_rgb2ycbcr (
input wire [7:0] red,
input wire [7:0] green,
input wire [7:0] blue,
output reg [7:0] y,
output reg [7:0] cb,
output reg [7:0] cr
);
wire [18:0] y_lshift8;
wire [18:0] cb_lshift8;
wire [18:0] cr_lshift8;
assign y_lshift8 = ({5'd0, red, 6'd0} + {10'd0, red, 1'd0}) + ({4'd0, green, 7'd0} + {11'd0, green}) + ({7'd0, blue, 4'd0} + {8'd0, blue, 3'd0} + {11'd0, blue}) + 19'd4096;
assign cb_lshift8 = 19'd0 - ({6'd0, red, 5'd0} + {9'd0, red, 2'd0} + {10'd0, red, 1'd0}) - ({5'd0, green, 6'd0} + {8'd0, green, 3'd0} + {10'd0, green, 1'd0}) + ({5'd0, blue, 6'd0} + {6'd0, blue, 5'd0} + {7'd0, blue, 4'd0}) + 19'd32768;
assign cr_lshift8 = ({5'd0, red, 6'd0} + {6'd0, red, 5'd0} + {7'd0, red, 4'd0}) - ({5'd0, green, 6'd0} + {7'd0, green, 4'd0} + {8'd0, green, 3'd0} + {9'd0, green, 2'd0} + {10'd0, green, 1'd0}) - ({7'd0, blue, 4'd0} + {10'd0, blue , 1'd0}) + 19'd32768;
always @* begin
if (y_lshift8[18]==1'b1 || y_lshift8[17:8]<16) // マイナスまたは16以下なので16に丸める
y <= 8'd16;
else if (y_lshift8[17:8] > 235) // 235より大きければ235に丸める
y <= 8'd235;
else begin
if (y_lshift8[7] == 1'b1) begin
if (y_lshift8[15:8] == 8'd235)
y <= 8'd235;
else
y <= y_lshift8[15:8] + 8'd1;
end else
y <= y_lshift8[15:8];
end
end
always @* begin
if (cb_lshift8[18]==1'b1 || cb_lshift8[17:8]<16) // マイナスまたは16以下なので16に丸める
cb <= 8'd16;
else if (cb_lshift8[17:8] > 240) // 240より大きければ240に丸める
cb <= 8'd240;
else begin
if (cb_lshift8[7] == 1'b1) begin
if (cb_lshift8[15:8] == 8'd240)
cb <= 8'd240;
else
cb <= cb_lshift8[15:8] + 8'd1;
end else
cb <= cb_lshift8[15:8];
end
end
always @* begin
if (cr_lshift8[18]==1'b1 || cr_lshift8[17:8]<16) // マイナスまたは16以下なので16に丸める
cr <= 8'd16;
else if (cr_lshift8[17:8] > 240) // 240より大きければ240に丸める
cr <= 8'd240;
else begin
if (cr_lshift8[7] == 1'b1) begin
if (cr_lshift8[15:8] == 8'd240)
cr <= 8'd240;
else
cr <= cr_lshift8[15:8] + 8'd1;
end else
cr <= cr_lshift8[15:8];
end
end
endmodule
`default_nettype wire
// conv_rgb2ycbcr_top.v
`default_nettype none
module conv_rgb2ycbcr_rd_top (
input wire clk,
input wire reset,
input wire [7:0] red,
input wire [7:0] green,
input wire [7:0] blue,
output reg [7:0] y,
output reg [7:0] cb,
output reg [7:0] cr
);
reg [7:0] red_ff, green_ff, blue_ff;
wire [7:0] y_node, cb_node, cr_node;
always @(posedge clk) begin
if (reset) begin
red_ff <= 0;
green_ff <= 0;
blue_ff <= 0;
end else begin
red_ff <= red;
green_ff <= green;
blue_ff <= blue;
end
end
conv_rgb2ycbcr_round_down conv_rgb2ycbcr_rd_inst (
.red(red_ff),
.green(green_ff),
.blue(blue_ff),
.y(y_node),
.cb(cb_node),
.cr(cr_node)
);
always @(posedge clk) begin
if (reset) begin
y <= 0;
cb <= 0;
cr <= 0;
end else begin
y <= y_node;
cb <= cb_node;
cr <= cr_node;
end
end
endmodule
`default_nettype wire
// RGB - YCbCr変換
// Y = 0.257R + 0.504G + 0.098B + 16
// Cb = -0.148R - 0.291G + 0.439B + 128
// Cr = 0.439R - 0.368G - 0.071B + 128
// 但し、Yは255以上だったら飽和演算をして255に丸める。Cb, Crは16以下だったら16に、240以上だったら240に飽和演算を行う。
// 切り捨てバージョン
`default_nettype none
module conv_rgb2ycbcr_round_down (
input wire [7:0] red,
input wire [7:0] green,
input wire [7:0] blue,
output reg [7:0] y,
output reg [7:0] cb,
output reg [7:0] cr
);
wire [18:0] y_lshift8;
wire [18:0] cb_lshift8;
wire [18:0] cr_lshift8;
assign y_lshift8 = ({5'd0, red, 6'd0} + {10'd0, red, 1'd0}) + ({4'd0, green, 7'd0} + {11'd0, green}) + ({7'd0, blue, 4'd0} + {8'd0, blue, 3'd0} + {11'd0, blue}) + 19'd4096;
assign cb_lshift8 = 19'd0 - ({6'd0, red, 5'd0} + {9'd0, red, 2'd0} + {10'd0, red, 1'd0}) - ({5'd0, green, 6'd0} + {8'd0, green, 3'd0} + {10'd0, green, 1'd0}) + ({5'd0, blue, 6'd0} + {6'd0, blue, 5'd0} + {7'd0, blue, 4'd0}) + 19'd32768;
assign cr_lshift8 = ({5'd0, red, 6'd0} + {6'd0, red, 5'd0} + {7'd0, red, 4'd0}) - ({5'd0, green, 6'd0} + {7'd0, green, 4'd0} + {8'd0, green, 3'd0} + {9'd0, green, 2'd0} + {10'd0, green, 1'd0}) - ({7'd0, blue, 4'd0} + {10'd0, blue , 1'd0}) + 19'd32768;
always @* begin
if (y_lshift8[18] == 1'b1 || y_lshift8[17:8]<16) // マイナスまたは16より小さいので16に丸める
y <= 8'd16;
else if (y_lshift8[17:8] > 235) // 235より大きければ235に丸める
y <= 8'd235;
else
y <= y_lshift8[15:8];
end
always @* begin
if (cb_lshift8[18] == 1'b1 || cb_lshift8[17:8]<16) // マイナスまたは16より小さいので16に丸める
cb <= 8'd16;
else if (cb_lshift8[17:8] > 240) // 240より大きければ240に丸める
cb <= 8'd240;
else
cb <= cb_lshift8[15:8];
end
always @* begin
if (cr_lshift8[18] == 1'b1 || cr_lshift8[17:8]<16) // マイナスまたは16より小さいので16に丸める
cr <= 8'd16;
else if (cr_lshift8[17:8] > 240) // 240より大きければ240に丸める
cr <= 8'd240;
else
cr <= cr_lshift8[15:8];
end
endmodule
`default_nettype wire
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 04:57:17 11/18/2012
// Design Name: conv_rgb2ycbcr
// Module Name: K:/HDL/FndtnISEWork/Zynq-7000/ZedBoard/test/conv_rgb2ycbcr/conv_rgb2ycbcr_tb.v
// Project Name: conv_rgb2ycbcr
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: conv_rgb2ycbcr
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////
module conv_rgb2ycbcr_tb;
// Inputs
reg [7:0] red;
reg [7:0] green;
reg [7:0] blue;
// Outputs
wire [7:0] y;
wire [7:0] cb;
wire [7:0] cr;
integer i = 0;
integer j = 0;
integer k = 0;
// Instantiate the Unit Under Test (UUT)
conv_rgb2ycbcr uut (
.red(red),
.green(green),
.blue(blue),
.y(y),
.cb(cb),
.cr(cr)
);
initial begin
// Initialize Inputs
red = 0;
green = 0;
blue = 0;
// Wait 100 ns for global reset to finish
#100;
// Add stimulus here
for (i=0; i < 100; i = i + 10) begin
red = i;
green = i;
blue = i; // 色は白
#10;
end
for (i=0; i<256; i=i+1) begin
for (j=0; j<256; j=j+1) begin
for (k=0; k<256; k=k+1) begin
red = i;
green = j;
blue = k;
#10;
end
end
end
$finish;
end
endmodule
Release 14.3 Map P.40xd (nt)
Xilinx Mapping Report File for Design 'conv_rgb2ycbcr'
Design Information
------------------
Command Line : map -intstyle ise -p xc7z020-clg484-1 -w -logic_opt off -ol
high -t 1 -xt 0 -register_duplication off -r 4 -mt off -ir off -pr off -lc off
-power off -o conv_rgb2ycbcr_map.ncd conv_rgb2ycbcr.ngd conv_rgb2ycbcr.pcf
Target Device : xc7z020
Target Package : clg484
Target Speed : -1
Mapper Version : zynq -- $Revision: 1.55 $
Mapped Date : SUN 18 NOV 6:1:11 2012
Design Summary
--------------
Number of errors: 0
Number of warnings: 50
Slice Logic Utilization:
Number of Slice Registers: 41 out of 106,400 1%
Number used as Flip Flops: 0
Number used as Latches: 0
Number used as Latch-thrus: 0
Number used as AND/OR logics: 41
Number of Slice LUTs: 240 out of 53,200 1%
Number used as logic: 238 out of 53,200 1%
Number using O6 output only: 117
Number using O5 output only: 8
Number using O5 and O6: 113
Number used as ROM: 0
Number used as Memory: 0 out of 17,400 0%
Number used exclusively as route-thrus: 2
Number with same-slice register load: 0
Number with same-slice carry load: 2
Number with other load: 0
Slice Logic Distribution:
Number of occupied Slices: 93 out of 13,300 1%
Number of LUT Flip Flop pairs used: 240
Number with an unused Flip Flop: 199 out of 240 82%
Number with an unused LUT: 0 out of 240 0%
Number of fully used LUT-FF pairs: 41 out of 240 17%
Number of slice register sites lost
to control set restrictions: 0 out of 106,400 0%
Y = 0.257R + 0.504G + 0.098B + 16
Cb = -0.148R - 0.291G + 0.439B + 128
Cr = 0.439R - 0.368G - 0.071B + 128
但し、Yは255以上だったら飽和演算をして255に丸める。Cb, Crは16以下だったら16に、240以上だったら240に飽和演算を行う。
Y = (66R + 129G + 25B + 4096) >> 8
Cb = (-38R - 74G + 112B + 32768) >> 8
Cr = (112R - 94G - 18B + 32768) >> 8
Y = (0100_0010R + 1000_0001G + 0001_1001B + 19'd4096) >> 8
Cb = (-0010_0110R - 0100_1010G + 0111_0000B + 19'd32768) >> 8
Cr = (0111_0000R - 0101_1110G - 0001_0010B + 19'd32768) >> 8
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | - | - | - | - | - | - |