x393  1.0
FPGAcodeforElphelNC393camera
par12_hispi_psp4l.v
Go to the documentation of this file.
1 
39 `timescale 1ns/1ps
40 
42  parameter FULL_HEIGHT = 0, // number of lines in a frame. If 0 - wait to the VACT end, if > 0 - output immediately
43  parameter CLOCK_MPY = 10,
44  parameter CLOCK_DIV = 3,
45  parameter LANE0_DLY = 1.3,
46  parameter LANE1_DLY = 2.7,
47  parameter LANE2_DLY = 0.2,
48  parameter LANE3_DLY = 1.8,
49  parameter CLK_DLY = 2.3,
50  parameter EMBED_LINES = 2, // number of first lines containing embedded (non-image) data
51  parameter MSB_FIRST = 0,
52  parameter FIFO_LOGDEPTH = 12 // line FIFO address bits (includes sync+latency overhead)
53 )(
54  input pclk,
55  input rst,
56  input [11:0] pxd,
57  input vact,
58  input hact_in, // should be multiple of 4 pixels
59  output [3:0] lane_p,
60  output [3:0] lane_n,
61  output clk_p,
62  output clk_n
63 );
64  localparam FIFO_DEPTH = 1 << FIFO_LOGDEPTH;
65  localparam [3:0] SYNC_SOF = 3;
66  localparam [3:0] SYNC_SOL = 1;
67  localparam [3:0] SYNC_EOF = 7;
68  localparam [3:0] SYNC_EOL = 6;
69 // localparam SYNC_EMBED = 4;
70 
71  integer lines_left; // number of lines left in a frame
72  integer pre_lines; // Number of lines left with "embedded" (not image) data
73  reg [ 1:0] lane_pcntr; // count input pixels to extend hact to 4*n if needed
74  wire hact = hact_in || (|lane_pcntr);
76  reg vact_d;
77  reg [47:0] pxd_d;
78  reg [48:0] fifo_di; // msb: 0 - data,1 sync
79  reg fifo_we;
80  reg hact_d;
81  reg next_sof;
82  reg next_line_pclk; // triggers serial output of a line (generated at SOL and EOF, wait full line)
83  reg next_frame_pclk; // start of a new frame on input
84  wire pre_fifo_we_eof_w = (FULL_HEIGHT > 0) ? (next_line_pclk && (lines_left == 0)) : (vact_d && !vact);
85 // wire pre_fifo_we_sof_sol_w = vact_d && ((FULL_HEIGHT > 0) ? ((next_sof && hact && !hact_d) || (hact_d && ! hact && (lines_left > 1)))
87  : (hact && !hact_d));
90 
91  always @(posedge pclk) begin
92  if (!vact) lines_left <= FULL_HEIGHT;
93  else if (hact_d && ! hact) lines_left <= lines_left - 1;
94  end
95 
96  always @(posedge pclk) begin
97 
98  vact_d <= vact;
99  hact_d <= hact;
100 // pxd_d <= {pxd_d[35:0],pxd};
101  pxd_d <= {pxd, pxd_d[47:12]};
102 
103 
104  if (!vact) lane_pcntr <= 0;
105  else if (hact) lane_pcntr <= lane_pcntr + 1;
106 
107  if (!vact) pre_lines <= EMBED_LINES;
108  else if (!image_lines && hact_d && !hact) pre_lines <= pre_lines - 1;
109 
110  if (!vact) image_lines <= (EMBED_LINES != 0);
111  else if (!image_lines && hact_d && !hact && (pre_lines == 1)) image_lines <= 1;
112 
113  if (!vact) next_sof <= 1;
114  else if (hact_d) next_sof <= 0;
115 
116  if (!vact_d) next_line_pclk <= 0;
117  else next_line_pclk <= (FULL_HEIGHT >0)? (hact_d && !hact): (!vact || (hact && !hact_d && !next_sof));
118 
120 
122 
123  if (!pre_fifo_we_w) fifo_di <= 'bx;
124  else if (pre_fifo_we_data_w) fifo_di <= {1'b0,pxd_d};
125  else if (pre_fifo_we_sof_sol_w) fifo_di <= {1'b1,{4 {{ 7'b0, ~image_lines, next_sof?SYNC_SOF:SYNC_SOL}}}};
126  else if (pre_fifo_we_eof_w) fifo_di <= {1'b1,{4 {{7'b0, 1'b0, SYNC_EOF}}}};
127  end
128  reg [48:0] fifo_ram [0 : FIFO_DEPTH - 1];
129  reg [FIFO_LOGDEPTH - 1:0] fifo_wa;
130 
131  always @ (posedge pclk) begin
132  if (rst) fifo_wa <= 0;
133  else if (fifo_we) fifo_wa <= fifo_wa + 1;
134 
135  if (fifo_we) fifo_ram[fifo_wa] <= fifo_di;
136  end
137 
138  // generate output clock (normally multiplier first, but in simulation there will be less calculations if division is first)
139  wire oclk;
140 // wire int_clk;
143  reg orst_r = 1;
144  wire orst = rst || orst_r;
146  .MULTIPLIER(CLOCK_MPY),
147  .DIVISOR(CLOCK_DIV),
148  .SKIP_FIRST(5)
149  ) simul_clk_div_mult_i (
150  .clk_in(pclk), // input
151  .en(1'b1), // input
152  .clk_out(oclk) // output
153  );
154 
156  .EXTRA_DLY(0)
157  ) pulse_cross_clock_sof_sol_i (
158  .rst (rst), // input
159  .src_clk (pclk), // input
160  .dst_clk (oclk), // input
161  .in_pulse (next_line_pclk), // input
162  .out_pulse (next_line_oclk), // output
163  .busy() // output
164  );
165 
167  .EXTRA_DLY(0)
168  ) pulse_cross_clock_sof_i (
169  .rst (rst), // input
170  .src_clk (pclk), // input
171  .dst_clk (oclk), // input
172  .in_pulse (next_frame_pclk), // input
173  .out_pulse (next_frame_oclk), // output
174  .busy() // output
175  );
176 
177  always @ (oclk) begin
178  orst_r <= rst;
179  end
180 
181  wire [3:0] rdy ; // all lanes operate at the same time, only one rdy bit is used
182  wire [3:0] sdata;
183  wire [3:0] sdata_dly;
184  reg [FIFO_LOGDEPTH - 1:0] fifo_ra;
185  wire [48:0] fifo_out = fifo_ram[fifo_ra];
186  wire fifo_dav;
187 // wire next_line;
189  reg [1:0] lines_available; // number of lines ready in FIFO
191  generate
192  genvar i;
193  for (i=0; i < 4; i=i+1) begin: cmprs_channel_block
195  .SYNC_SOF (SYNC_SOF),
196  .SYNC_SOL (SYNC_SOL),
197  .SYNC_EOF (SYNC_EOF),
198  .SYNC_EOL (SYNC_EOL),
199  .IDL (12'h800),
201  ) par12_hispi_psp4l_lane_i (
202  .clk (oclk), // input
203  .rst (orst), // input
204  .din ({fifo_out[48], fifo_out[i * 12 +: 12]}), // input[12:0]
205  .dav (fifo_dav), // input
206  .next_line (line_available), // input
207  .sof_sol_sent (sof_sol_sent), // output reg
208  .rdy (rdy[i]), // output
209  .sout (sdata[i]) // output reg
210  );
211  // TODO: Add delays and diff out here?
212  end
213  endgenerate
214  reg [1:0] frames_open; // number of frames that are already started on input, but not yet finished on output //next_frame_oclk
215  wire eof_sent = rdy[0] && fifo_dav && fifo_out[48] && (fifo_out[2:0] == SYNC_EOF[2:0]);
216  assign fifo_dav = (|frames_open) && !(fifo_out[48] && (fifo_out[2:0] == SYNC_SOF[2:0]) && !line_available);
217  always @(posedge oclk) begin
218  if (orst) lines_available <= 0;
221 
222  if (orst) frames_open <= 0;
223  else if ( next_frame_oclk && !eof_sent) frames_open <= frames_open + 1;
224  else if (!next_frame_oclk && eof_sent) frames_open <= frames_open - 1;
225 
226  if (orst) fifo_ra <= fifo_wa;
227  else if (fifo_dav && rdy[0]) fifo_ra <= fifo_ra + 1;
228 
229  end
230 
232  .FRAC_DELAY (LANE0_DLY),
233  .SKIP_FIRST (5)
234  ) sim_frac_clk_delay0_i (
235  .clk (oclk), // input
236  .din (sdata[0]), // input
237  .dout (sdata_dly[0]) // output
238  );
239 
241  .FRAC_DELAY (LANE1_DLY),
242  .SKIP_FIRST (5)
243  ) sim_frac_clk_delay1_i (
244  .clk (oclk), // input
245  .din (sdata[1]), // input
246  .dout (sdata_dly[1]) // output
247  );
249  .FRAC_DELAY (LANE2_DLY),
250  .SKIP_FIRST (5)
251  ) sim_frac_clk_delay2_i (
252  .clk (oclk), // input
253  .din (sdata[2]), // input
254  .dout (sdata_dly[2]) // output
255  );
257  .FRAC_DELAY (LANE3_DLY),
258  .SKIP_FIRST (5)
259  ) sim_frac_clk_delay3_i (
260  .clk (oclk), // input
261  .din (sdata[3]), // input
262  .dout (sdata_dly[3]) // output
263  );
264  reg clk_pn;
266  always @ (posedge oclk) begin
267  if (orst) clk_pn <= 0;
268  else clk_pn <= ~clk_pn;
269  end
270 
272  .FRAC_DELAY (CLK_DLY),
273  .SKIP_FIRST (5)
274  ) sim_frac_clk_delay_clk_i (
275  .clk (oclk), // input
276  .din (clk_pn), // input
277  .dout (clk_pn_dly) // output
278  );
279 
280  assign lane_p = sdata_dly;
281  assign lane_n = ~sdata_dly;
282 
283  assign clk_p = clk_pn_dly;
284  assign clk_n = ~clk_pn_dly;
285 
286 endmodule
287 
289  parameter [3:0] SYNC_SOF = 3,
290  parameter [3:0] SYNC_SOL = 1,
291  parameter [3:0] SYNC_EOF = 7,
292  parameter [3:0] SYNC_EOL = 6,
293  parameter [11:0] IDL = 12'h800,
294  parameter MSB_FIRST = 0
295 )(
296  input clk,
297  input rst,
298  input [12:0] din,
299  input dav,
300  input next_line, // enable to continue seq_eol_sol
301  output reg sof_sol_sent, // SOL sent
302  output rdy,
303  output reg sout
304 );
305  reg [11:0] sr;
306  reg [11:0] sr_in;
307  reg sr_in_av; //
308  reg [ 3:0] bcntr;
309  reg [ 3:0] seq_sof;
310  reg [ 3:0] seq_eof;
311  reg [ 7:0] seq_eol_sol;
312  reg embed;
313  wire dav_rdy = dav && rdy;
314  wire is_sync = din[12];
315  wire [11:0] din_filt = (din[11:1] == 11'h0)? 12'h001 : din[11:0];
316 // wire pause = seq_eol_sol[4] && !next_line;
317  wire pause = seq_eol_sol[3] && !next_line;
318  assign rdy = !sr_in_av;
319 
320  always @ (posedge clk) begin
321  if (rst || (bcntr == 11)) bcntr <= 0;
322  else bcntr <= bcntr + 1;
323 
324  if (rst) sr <= 'bx;
325  else if (bcntr == 0) sr <= (sr_in_av && !pause) ? sr_in : IDL;
326  else sr <= MSB_FIRST ? {sr[10:0],1'b0} : {1'b0,sr[11:1]};
327 
328  sout <= MSB_FIRST ? sr[11] : sr[0];
329 
330  if (rst) embed <= 0;
331  else if (dav_rdy && is_sync) embed <= din[4];
332 
333  if (rst) seq_sof <= 0;
334  else if (dav_rdy && is_sync && (din[3:0] == SYNC_SOF )) seq_sof <= 8;
335  else if (bcntr == 0) seq_sof <= seq_sof >> 1;
336 
337  if (rst) seq_eof <= 0;
338  else if (dav_rdy && is_sync && (din[2:0] == SYNC_EOF[2:0] )) seq_eof <= 8;
339  else if (bcntr == 0) seq_eof <= seq_eof >> 1;
340 
341  if (rst) seq_eol_sol <= 0;
342  else if (dav_rdy && is_sync && (din[3:0] == SYNC_SOL )) seq_eol_sol <= 'h80;
343  else if ((bcntr == 0) && !pause) seq_eol_sol <= seq_eol_sol >> 1;
344 
345  if (dav_rdy) sr_in <= is_sync ? 12'hfff : din_filt;
346  else if ((bcntr == 0) && !pause) begin
347  if (seq_sof[3] || seq_eof[3] || seq_eol_sol[7] || seq_eol_sol[3]) sr_in <= 12'h0;
348  else if (seq_eol_sol[4]) sr_in <= 12'hfff;
349  else if (seq_sof[1]) sr_in <= {7'b0, embed, SYNC_SOF};
350  else if (seq_eof[1]) sr_in <= {7'b0, 1'b0, SYNC_EOF};
351  else if (seq_eol_sol[5]) sr_in <= {7'b0, 1'b0, SYNC_EOL};
352  else if (seq_eol_sol[1]) sr_in <= {7'b0, embed, SYNC_SOL};
353  end
354 
355  if (rst) sr_in_av <= 0;
356  else if (dav_rdy) sr_in_av <= 1;
357 // else if (bcntr == 0) sr_in_av <= (|seq_sof[3:1]) || (|seq_eof[3:1]) || ((|seq_eol_sol[7:1]) && !pause);
358  else if (bcntr == 0) sr_in_av <= (|seq_sof[3:1]) || (|seq_eof[3:1]) || (|seq_eol_sol[7:1]);
359 
360  sof_sol_sent <= (bcntr == 0) && (seq_sof[1] || seq_eol_sol[1]);
361  end
362 endmodule
363 
[0:FIFO_DEPTH-1] 8762fifo_ramreg[48:0]
8763fifo_wareg[FIFO_LOGDEPTH-1:0]
8740FIFO_DEPTH1 << FIFO_LOGDEPTH
simul_clk_div_mult_i simul_clk_mult_div
sim_frac_clk_delay_clk_i sim_frac_clk_delay
par12_hispi_psp4l_lane_i par12_hispi_psp4l_lane[generate]
8772fifo_rareg[FIFO_LOGDEPTH-1:0]
pulse_cross_clock_sof_i pulse_cross_clock