Integrated video in. Working but cleanup-needing I2C functions.
[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 wire [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                 int_r0 <= y0;
68                 int_g0 <= y0;
69                 int_b0 <= y0;
70                 int_r1 <= y1;
71                 int_g1 <= y1;
72                 int_b1 <= y1;
73         end
74         if(add_r) begin
75                 int_r0 <= int_r0 + mult_result_t;
76                 int_r1 <= int_r1 + mult_result_t;
77         end
78         if(sub_g) begin
79                 int_g0 <= int_g0 - mult_result_t;
80                 int_g1 <= int_g1 - mult_result_t;
81         end
82         if(add_b) begin
83                 int_b0 <= int_b0 + mult_result_t;
84                 int_b1 <= int_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 initial state = S1;
137 always @(posedge vid_clk) begin
138         state <= next_state;
139         //$display("state: %d->%d (%d)", state, next_state, stb_i);
140 end
141
142 always @(*) begin
143         mult_sela = 1'bx;
144         mult_selb = 2'bx;
145         
146         load_y = 1'b0;
147         add_r = 1'b0;
148         sub_g = 1'b0;
149         add_b = 1'b0;
150
151         fsm_stb = 1'b0;
152
153         next_state = state;
154
155         case(state)
156                 S1: begin
157                         load_y = 1'b1;
158                         mult_sela = 1'b1; // 1.402*Cr
159                         mult_selb = 2'd0;
160                         if(stb_i)
161                                 next_state = S2;
162                 end
163                 S2: begin
164                         add_r = 1'b1;
165                         mult_sela = 1'b0; // 1.772*Cb
166                         mult_selb = 2'd1;
167                         next_state = S3;
168                 end
169                 S3: begin
170                         add_b = 1'b1;
171                         mult_sela = 1'b0; // 0.344*Cb
172                         mult_selb = 2'd2;
173                         next_state = S4;
174                 end
175                 S4: begin
176                         sub_g = 1'b1;
177                         mult_sela = 1'b1; // 0.714*Cr
178                         mult_selb = 2'd3;
179                         next_state = S5;
180                 end
181                 S5: begin
182                         fsm_stb = 1'b1;
183                         load_y = 1'b1;
184                         mult_sela = 1'b1; // 1.402*Cr
185                         mult_selb = 2'd0;
186                         if(stb_i)
187                                 next_state = S2;
188                         else
189                                 next_state = S1;
190                 end
191         endcase
192 end
193
194 endmodule