Skip to content

Commit e564ed9

Browse files
authored
Merge pull request #237 from felloryz/main
Fix Quartus synth error after previous PR
2 parents 904045c + a3b579a commit e564ed9

File tree

7 files changed

+369
-383
lines changed

7 files changed

+369
-383
lines changed

peripherals/dvi.sv

Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
`include "dvi_config.svh"
2+
3+
module dvi_top (
4+
input logic serial_clk_i,
5+
input logic pixel_clk_i,
6+
input logic rst_i,
7+
8+
input logic [COLOR_W-1:0] red_i,
9+
input logic [COLOR_W-1:0] green_i,
10+
input logic [COLOR_W-1:0] blue_i,
11+
12+
output logic [X_POS_W-1:0] x_o,
13+
output logic [Y_POS_W-1:0] y_o,
14+
15+
output logic red_serial_o,
16+
output logic green_serial_o,
17+
output logic blue_serial_o
18+
);
19+
20+
logic hsync;
21+
logic vsync;
22+
logic visible_range;
23+
logic hsync_r;
24+
logic vsync_r;
25+
logic visible_range_r;
26+
27+
logic [ 9:0] red_tmds;
28+
logic [ 9:0] green_tmds;
29+
logic [ 9:0] blue_tmds;
30+
31+
// ------------------------------------------------------------------------
32+
// Sync
33+
// ------------------------------------------------------------------------
34+
35+
dvi_sync i_dvi_sync (
36+
.clk_i ( pixel_clk_i ),
37+
.rst_i ( rst_i ),
38+
.hsync_o ( hsync ),
39+
.vsync_o ( vsync ),
40+
.pixel_x_o ( x_o ),
41+
.pixel_y_o ( y_o ),
42+
.visible_range_o ( visible_range )
43+
);
44+
45+
// ------------------------------------------------------------------------
46+
// Encode
47+
// ------------------------------------------------------------------------
48+
49+
// Delay hsync/vsync and visible_range by 1 clock cycle to account for color
50+
// delay in image_gen
51+
always_ff @(posedge pixel_clk_i) begin
52+
if (rst_i) begin
53+
hsync_r <= '0;
54+
vsync_r <= '0;
55+
visible_range_r <= '0;
56+
end else begin
57+
hsync_r <= hsync;
58+
vsync_r <= vsync;
59+
visible_range_r <= visible_range;
60+
end
61+
end
62+
63+
tmds_encoder blue_encoder (
64+
.clk_i ( pixel_clk_i ),
65+
.rst_i ( rst_i ),
66+
.C0 ( hsync_r ),
67+
.C1 ( vsync_r ),
68+
.DE ( visible_range_r ),
69+
.D ( blue_i ),
70+
.q_out ( blue_tmds )
71+
);
72+
73+
tmds_encoder green_encoder (
74+
.clk_i ( pixel_clk_i ),
75+
.rst_i ( rst_i ),
76+
.C0 ( 1'b0 ),
77+
.C1 ( 1'b0 ),
78+
.DE ( visible_range_r ),
79+
.D ( green_i ),
80+
.q_out ( green_tmds )
81+
);
82+
83+
tmds_encoder red_encoder (
84+
.clk_i ( pixel_clk_i ),
85+
.rst_i ( rst_i ),
86+
.C0 ( 1'b0 ),
87+
.C1 ( 1'b0 ),
88+
.DE ( visible_range_r ),
89+
.D ( red_i ),
90+
.q_out ( red_tmds )
91+
);
92+
93+
// ------------------------------------------------------------------------
94+
// Serialize
95+
// ------------------------------------------------------------------------
96+
97+
serializer #(
98+
.DATA_W ( 10 )
99+
) blue_serializer (
100+
.clk_i ( serial_clk_i ),
101+
.rst_i ( rst_i ),
102+
.data_i ( blue_tmds ),
103+
.data_o ( blue_serial_o )
104+
);
105+
106+
serializer #(
107+
.DATA_W ( 10 )
108+
) green_serializer (
109+
.clk_i ( serial_clk_i ),
110+
.rst_i ( rst_i ),
111+
.data_i ( green_tmds ),
112+
.data_o ( green_serial_o )
113+
);
114+
115+
serializer #(
116+
.DATA_W ( 10 )
117+
) red_serializer (
118+
.clk_i ( serial_clk_i ),
119+
.rst_i ( rst_i ),
120+
.data_i ( red_tmds ),
121+
.data_o ( red_serial_o )
122+
);
123+
124+
endmodule
125+
126+
127+
module dvi_sync (
128+
input logic clk_i,
129+
input logic rst_i,
130+
output logic hsync_o,
131+
output logic vsync_o,
132+
output logic [X_POS_W-1:0] pixel_x_o,
133+
output logic [Y_POS_W-1:0] pixel_y_o,
134+
output logic visible_range_o
135+
);
136+
137+
logic h_cnt_max;
138+
logic [HS_W-1:0] h_cnt_next;
139+
logic [HS_W-1:0] h_cnt;
140+
logic [VS_W-1:0] v_cnt_next;
141+
logic [VS_W-1:0] v_cnt;
142+
143+
always_comb begin
144+
h_cnt_max = h_cnt == (H_TOTAL - 1);
145+
h_cnt_next = h_cnt_max ? '0 : h_cnt + 1'b1;
146+
v_cnt_next = v_cnt;
147+
148+
if (h_cnt_max) begin
149+
v_cnt_next = v_cnt + 1'b1;
150+
151+
if (v_cnt == (V_TOTAL - 1))
152+
v_cnt_next = '0;
153+
end
154+
end
155+
156+
always_ff @(posedge clk_i) begin
157+
if (rst_i) begin
158+
h_cnt <= '0;
159+
v_cnt <= '0;
160+
end else begin
161+
h_cnt <= h_cnt_next;
162+
v_cnt <= v_cnt_next;
163+
end
164+
end
165+
166+
// Register outputs
167+
always_ff @(posedge clk_i)
168+
if (rst_i) begin
169+
hsync_o <= '0;
170+
vsync_o <= '0;
171+
pixel_x_o <= '0;
172+
pixel_y_o <= '0;
173+
visible_range_o <= '0;
174+
end else begin
175+
hsync_o <= !(h_cnt_next >= HSYNC_START && h_cnt_next < HSYNC_END);
176+
vsync_o <= !(v_cnt_next >= VSYNC_START && v_cnt_next < VSYNC_END);
177+
178+
pixel_x_o <= (h_cnt_next > SCREEN_H_RES - 1) ? '0 : X_POS_W'(h_cnt_next);
179+
pixel_y_o <= (v_cnt_next > SCREEN_V_RES - 1) ? '0 : Y_POS_W'(v_cnt_next);
180+
181+
visible_range_o <= ((h_cnt_next < SCREEN_H_RES) && (v_cnt_next < SCREEN_V_RES));
182+
end
183+
184+
endmodule
185+
186+
187+
module serializer #(
188+
parameter DATA_W = 10
189+
) (
190+
input logic clk_i,
191+
input logic rst_i,
192+
input logic [DATA_W-1:0] data_i,
193+
output logic data_o
194+
);
195+
196+
localparam CNT_MAX = DATA_W - 1;
197+
198+
logic [DATA_W-1:0] shift_reg;
199+
logic [ 3:0] cnt;
200+
logic load;
201+
202+
assign load = cnt == CNT_MAX;
203+
204+
always_ff @(posedge clk_i) begin
205+
if (rst_i) begin
206+
cnt <= '0;
207+
end else if (load) begin
208+
cnt <= '0;
209+
end else begin
210+
cnt <= cnt + 1'b1;
211+
end
212+
end
213+
214+
always_ff @(posedge clk_i) begin
215+
if (rst_i) begin
216+
shift_reg <= '0;
217+
end else if (load) begin
218+
shift_reg <= data_i;
219+
end else begin
220+
shift_reg <= { 1'b0, shift_reg[DATA_W-1:1] };
221+
end
222+
end
223+
224+
assign data_o = shift_reg[0];
225+
226+
endmodule
227+
228+
229+
module tmds_encoder (
230+
input logic clk_i,
231+
input logic rst_i,
232+
input logic C0,
233+
input logic C1,
234+
input logic DE,
235+
input logic [7:0] D,
236+
output logic [9:0] q_out
237+
);
238+
239+
localparam W_CNT = 8;
240+
241+
logic signed [W_CNT-1:0] cnt;
242+
logic signed [W_CNT-1:0] cnt_next;
243+
logic [8:0] q_m;
244+
logic [9:0] q_next;
245+
logic [3:0] N1D;
246+
logic [3:0] N1_qm;
247+
logic [3:0] N0_qm;
248+
249+
250+
always_comb begin
251+
N1D = 4'(D[0]) + 4'(D[1]) + 4'(D[2]) + 4'(D[3])
252+
+ 4'(D[4]) + 4'(D[5]) + 4'(D[6]) + 4'(D[7]);
253+
254+
q_m[0] = D[0];
255+
256+
if ((N1D > 4) || (N1D == 4 && ~D[0])) begin
257+
// verilator lint_off ALWCOMBORDER
258+
q_m[8] = 1'b0;
259+
260+
for (int i = 0; i < 7; i++) begin
261+
q_m[i + 1] = q_m[i] ~^ D[i + 1];
262+
end
263+
// verilator lint_on ALWCOMBORDER
264+
265+
end else begin
266+
q_m[8] = 1'b1;
267+
268+
for (int i = 0; i < 7; i++) begin
269+
q_m[i + 1] = q_m[i] ^ D[i + 1];
270+
end
271+
end
272+
273+
N1_qm = 4'(q_m[0]) + 4'(q_m[1]) + 4'(q_m[2]) + 4'(q_m[3])
274+
+ 4'(q_m[4]) + 4'(q_m[5]) + 4'(q_m[6]) + 4'(q_m[7]);
275+
276+
N0_qm = 4'(!q_m[0]) + 4'(!q_m[1]) + 4'(!q_m[2]) + 4'(!q_m[3])
277+
+ 4'(!q_m[4]) + 4'(!q_m[5]) + 4'(!q_m[6]) + 4'(!q_m[7]);
278+
279+
if (DE) begin
280+
if ((cnt == 0) || (N1_qm == N0_qm)) begin
281+
q_next[9] = ~q_m[8];
282+
q_next[8] = q_m[8];
283+
q_next[7:0] = q_m[8] ? q_m[7:0] : ~q_m[7:0];
284+
285+
if (~q_m[8]) begin
286+
cnt_next = cnt + W_CNT'(N0_qm) - W_CNT'(N1_qm);
287+
end else begin
288+
cnt_next = cnt + W_CNT'(N1_qm) - W_CNT'(N0_qm);
289+
end
290+
291+
end else begin
292+
if (((cnt > 0) && (N1_qm > N0_qm)) ||
293+
((cnt < 0) && (N0_qm > N1_qm))) begin
294+
295+
q_next[9] = 1'b1;
296+
q_next[8] = q_m[8];
297+
q_next[7:0] = ~q_m[7:0];
298+
cnt_next = cnt + (W_CNT'(q_m[8]) << 1) +
299+
W_CNT'(N0_qm) - W_CNT'(N1_qm);
300+
301+
end else begin
302+
q_next[9] = 1'b0;
303+
q_next[8] = q_m[8];
304+
q_next[7:0] = q_m[7:0];
305+
cnt_next = cnt - (W_CNT'({~q_m[8]}) << 1) +
306+
W_CNT'(N1_qm) - W_CNT'(N0_qm);
307+
end
308+
end
309+
310+
end else begin
311+
cnt_next = '0;
312+
313+
case ({C1, C0})
314+
2'b00: q_next = 10'b1101010100;
315+
2'b01: q_next = 10'b0010101011;
316+
2'b10: q_next = 10'b0101010100;
317+
2'b11: q_next = 10'b1010101011;
318+
endcase
319+
end
320+
end
321+
322+
always_ff @(posedge clk_i) begin
323+
if (rst_i) begin
324+
cnt <= '0;
325+
end else begin
326+
cnt <= cnt_next;
327+
end
328+
end
329+
330+
always_ff @(posedge clk_i) begin
331+
q_out <= q_next;
332+
end
333+
334+
endmodule

peripherals/dvi_config.svh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
`ifndef DVI_CONFIG_SVH
2+
`define DVI_CONFIG_SVH
3+
4+
parameter SCREEN_H_RES = 640;
5+
parameter SCREEN_V_RES = 480;
6+
7+
parameter HSYNC_PULSE = 96;
8+
parameter H_FRONT_PORCH = 16;
9+
parameter H_BACK_PORCH = 48;
10+
parameter H_BORDER = 0;
11+
12+
parameter VSYNC_PULSE = 2;
13+
parameter V_FRONT_PORCH = 10;
14+
parameter V_BACK_PORCH = 33;
15+
parameter V_BORDER = 0;
16+
17+
// HSYNC
18+
parameter HSYNC_START = SCREEN_H_RES + H_BORDER + H_FRONT_PORCH;
19+
parameter HSYNC_END = HSYNC_START + HSYNC_PULSE;
20+
parameter H_TOTAL = HSYNC_END + H_BACK_PORCH + H_BORDER;
21+
22+
// VSYNC
23+
parameter VSYNC_START = SCREEN_V_RES + V_BORDER + V_FRONT_PORCH;
24+
parameter VSYNC_END = VSYNC_START + VSYNC_PULSE;
25+
parameter V_TOTAL = VSYNC_END + V_BACK_PORCH + V_BORDER;
26+
27+
parameter X_POS_W = $clog2(SCREEN_H_RES + 1);
28+
parameter Y_POS_W = $clog2(SCREEN_V_RES + 1);
29+
30+
parameter HS_W = $clog2(H_TOTAL + 1);
31+
parameter VS_W = $clog2(V_TOTAL + 1);
32+
33+
parameter COLOR_W = 8;
34+
35+
`endif

0 commit comments

Comments
 (0)