fc5fd590b82cbbd842d2c96feab0d90cfc651598
[mw/milkymist.git] / cores / bt656cap / rtl / bt656cap_colorspace.v
1 /*
2  * Milkymist VJ SoC
3  * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 module bt656cap_colorspace(
19         input vid_clk,
20
21         input stb_i,
22         input field_i,
23         input [31:0] ycc422,
24
25         output reg stb_o,
26         output reg field_o,
27         output [31:0] rgb565
28 );
29
30 /* Datapath */
31 wire [7:0] cb = ycc422[31:24];
32 wire [7:0] y0 = ycc422[23:16];
33 wire [7:0] cr = ycc422[15: 8];
34 wire [7:0] y1 = ycc422[ 7: 0];
35
36 reg mult_sela;
37 reg [1:0] mult_selb;
38
39 wire [7:0] mult_opa = mult_sela ? cr : cb;
40 reg [8:0] mult_opb;
41 always @(*) begin
42         case(mult_selb)
43                 2'd0: mult_opb = 9'd359; // 1.402
44                 2'd1: mult_opb = 9'd454; // 1.772
45                 2'd2: mult_opb = 9'd88;  // 0.344
46                 2'd3: mult_opb = 9'd183; // 0.714
47         endcase
48 end
49
50 reg [16:0] mult_result;
51 reg [8:0] mult_result_t = mult_result[16:8];
52 always @(posedge vid_clk) mult_result <= mult_opa*mult_opb;
53
54 reg [8:0] int_r0;
55 reg [8:0] int_g0;
56 reg [8:0] int_b0;
57 reg [8:0] int_r1;
58 reg [8:0] int_g1;
59 reg [8:0] int_b1;
60
61 reg load_y;
62 reg add_r;
63 reg sub_g;
64 reg add_b;
65 always @(posedge vid_clk) begin
66         if(load_y) begin
67                 r0 <= y0;
68                 g0 <= y0;
69                 b0 <= y0;
70                 r1 <= y1;
71                 g1 <= y1;
72                 b1 <= y1;
73         end
74         if(add_r) begin
75                 r0 <= r0 + mult_result_t;
76                 r1 <= r1 + mult_result_t;
77         end
78         if(sub_g) begin
79                 g0 <= g0 - mult_result_t;
80                 g1 <= g1 - mult_result_t;
81         end
82         if(add_b) begin
83                 b0 <= b0 + mult_result_t;
84                 b1 <= b1 + mult_result_t;
85         end
86 end
87
88 /* Output generator */
89 reg fsm_stb;
90 reg fsm_field;
91 wire [8:0] fsm_r0 = int_r0;
92 wire [8:0] fsm_g0 = int_g0 - mult_result_t;
93 wire [8:0] fsm_b0 = int_b0;
94 wire [8:0] fsm_r1 = int_r1;
95 wire [8:0] fsm_g1 = int_g1 - mult_result_t;
96 wire [8:0] fsm_b1 = int_b1;
97 reg [7:0] out_r0;
98 reg [7:0] out_g0;
99 reg [7:0] out_b0;
100 reg [7:0] out_r1;
101 reg [7:0] out_g1;
102 reg [7:0] out_b1;
103 always @(posedge vid_clk) begin
104         stb_o <= 1'b0;
105         if(fsm_stb) begin
106                 stb_o <= 1'b1;
107                 field_o <= fsm_field;
108                 out_r0 <= fsm_r0[7:0] | {8{fsm_r0[8]}};
109                 out_g0 <= fsm_g0[7:0] | {8{fsm_g0[8]}};
110                 out_b0 <= fsm_b0[7:0] | {8{fsm_b0[8]}};
111                 out_r1 <= fsm_r1[7:0] | {8{fsm_r1[8]}};
112                 out_g1 <= fsm_g1[7:0] | {8{fsm_g1[8]}};
113                 out_b1 <= fsm_b1[7:0] | {8{fsm_b1[8]}};
114         end
115 end
116
117 assign rgb565 = {out_r0[7:3], out_g0[7:2], out_b0[7:3],
118         out_r1[7:3], out_g1[7:2], out_b1[7:3]};
119
120 /* Forward field */
121 always @(posedge vid_clk) begin
122         if(stb_i)
123                 fsm_field <= field_i;
124 end
125
126 /* Controller */
127 reg [2:0] state;
128 reg [2:0] next_state;
129
130 parameter S1 = 3'd0;
131 parameter S2 = 3'd1;
132 parameter S3 = 3'd2;
133 parameter S4 = 3'd3;
134 parameter S5 = 3'd4;
135
136 always @(posedge vid_clk)
137         state <= next_state;
138
139 always @(*) begin
140         mult_sela = 1'bx;
141         mult_selb = 2'bx;
142         
143         load_y = 1'b0;
144         add_r = 1'b0;
145         sub_g = 1'b0;
146         add_b = 1'b0;
147
148         fsm_stb = 1'b0;
149
150         next_state = state;
151
152         case(state)
153                 S1: begin
154                         load_y = 1'b1;
155                         mult_sela = 1'b1; // 1.402*Cr
156                         mult_selb = 2'd0;
157                         if(stb_i)
158                                 next_state = S2;
159                 end
160                 S2: begin
161                         add_r = 1'b1;
162                         mult_sela = 1'b0; // 1.772*Cb
163                         mult_selb = 2'd1;
164                         next_state = S3;
165                 end
166                 S3: begin
167                         add_b = 1'b1;
168                         mult_sela = 1'b0; // 0.344*Cb
169                         mult_selb = 2'd2;
170                         next_state = S4;
171                 end
172                 S4: begin
173                         sub_g = 1'b1;
174                         mult_sela = 1'b1; // 0.714*Cr
175                         mult_selb = 2'd3;
176                         next_state = S5;
177                 end
178                 S5: begin
179                         fml_stb = 1'b1;
180                         load_y = 1'b1;
181                         mult_sela = 1'b1; // 1.402*Cr
182                         mult_selb = 2'd0;
183                         if(stb_i)
184                                 next_state = S2;
185                         else
186                                 next_state = S0;
187                 end
188         endcase
189 end
190
191 endmodule