x393  1.0
FPGAcodeforElphelNC393camera
cmd_frame_sequencer.v
Go to the documentation of this file.
1 
39 `timescale 1ns/1ps
40 // Comments from the x353 code:
41 // This command sequencer is designed (together with i2c sequencer) to provide
42 // pipelined operation of the sensor, FPGA pre-processor and compressor, to avoid
43 // requirement of resetting the circuitry and loosing several frames when the sensor
44 // acquisition parameters are changed (especially geometry - WOI, decimation).
45 // It also reduces real-time requirements to the software, as it is possible to
46 // program parameters related to the events several frames in the future.
47 //
48 //
49 // Controller is programmed through 32 locations. Each registers but the control require two writes:
50 // First write - register address (AXI_WR_ADDR_BITS bits), second - register data (32 bits)
51 // Writing to the contol register (0x1f) resets the first/second counter so the next write will be "first"
52 // 0x0..0xf write directly to the frame number [3:0] modulo 16, except if you write to the frame
53 // "just missed" - in that case data will go to the current frame.
54 // 0x10 - write seq commands to be sent ASAP
55 // 0x11 - write seq commands to be sent after the next frame starts
56 //
57 // 0x1e - write seq commands to be sent after the next 14 frame start pulses
58 // 0x1f - control register:
59 // [14] - reset all FIFO (takes 32 clock pulses), also - stops seq until run command
60 // [13:12] - 3 - run seq, 2 - stop seq , 1,0 - no change to run state
61 // New - [1:0] - 0: NOP, 1: clear IRQ, 2 - Clear IE, 3: set IE
62 
64  parameter CMDFRAMESEQ_ADDR= 'h780,
65  parameter CMDFRAMESEQ_MASK= 'h7e0,
66  parameter AXI_WR_ADDR_BITS = 14,
67  parameter CMDFRAMESEQ_DEPTH = 64, // 32/64/128
68  parameter CMDFRAMESEQ_ABS = 0,
69  parameter CMDFRAMESEQ_REL = 16,
70  parameter CMDFRAMESEQ_CTRL = 31,
71  parameter CMDFRAMESEQ_RST_BIT = 14,
72  parameter CMDFRAMESEQ_RUN_BIT = 13,
73  parameter CMDFRAMESEQ_IRQ_BIT = 0 // [1:0] used
74 )(
75  input mrst,
76  input mclk, // for command/status
77  // programming interface
78  input [7:0] cmd_ad, // byte-serial command address/data (up to 6 bytes: AL-AH-D0-D1-D2-D3
79  input cmd_stb, // strobe (with first byte) for the command a/d
80  // frame sync and frame number
81  input frame_sync, // @posedge mclk
82  output [ 3:0] frame_no, // @posedge mclk
83  // command mux interface
84  output [AXI_WR_ADDR_BITS-1:0] waddr, // write address, valid with wr_en_out
85  output valid, // output data valid
86  output [31:0] wdata, // write data, valid with waddr_out and wr_en_out
87  input ackn, // command sequencer address/data accepted
88  // Interrupt mask, status, request
89  output is, // interrupt status (not masked)
90  output im // interrupt mask
91 );
92  localparam PNTR_WIDH = (CMDFRAMESEQ_DEPTH > 32) ?((CMDFRAMESEQ_DEPTH > 64) ? 7 : 6) : 5;
93  wire [4:0] cmd_a; // 3 cycles before data
94  wire cmd_we; // 3 cycles befor data
95  reg [2:0] cmd_we_r; // cmd_we_r[2] - with cmd_data
96  wire [31:0] cmd_data;
97 
98  reg [3:0] wpage_asap; // FIFO page were ASAP writes go
99  reg [3:0] wpage_prev; // unused page, currently being cleared
100  reg [3:0] wpage_next; // next page to be used
101  reg [3:0] wpage_w; // FIFO page where current writes go
102  reg [1:0] wpage_inc; // increment wpage_asap (after frame sync or during reset), and [1] next clock cycle after [0]
103 
104  wire reset_cmd;
105  wire run_cmd;
106  reg reset_on; // reset FIFO in progress
107  reg seq_enrun=0; // enable seq
108  reg we_fifo_wp; // enable writing to fifo write pointer memory
109  reg next_frame_rq; // request to switch to the new frame page, clear pointer for the one just left
111  reg [PNTR_WIDH-1:0] fifo_wr_pointers_ram [0:15];
114 
117  reg d_na; // register counting address(0) or data(1) when writing sequences
118  reg [AXI_WR_ADDR_BITS-1:0] address_hold; // register to hold command address to write to the sequencer simultaneously with data
119  wire [63:0] cmdseq_di = {{32 - AXI_WR_ADDR_BITS{1'b0}},address_hold,cmd_data}; // data to write to the command sequencer
120  reg [2:0] por=0; //power on reset
121  reg initialized; // command fifo initialized
122 
123  wire cmd_we_ctl_w = cmd_we && (cmd_a == CMDFRAMESEQ_CTRL); // 3 cycles before data
124  reg [2:0] cmd_we_ctl_r; // cmd_we_ctl_r[2] - with data
125  wire cmd_we_abs_w = cmd_we && ((cmd_a & 'h10) == CMDFRAMESEQ_ABS); // 3 cycles before data
126  reg cmd_we_abs_r; // 2 cycles before data
127  wire cmd_we_rel_w = cmd_we && ((cmd_a & 'h10) == CMDFRAMESEQ_REL) && (cmd_a != CMDFRAMESEQ_CTRL); // 3 cycles before data
128  reg cmd_we_rel_r; // 2 cycles before data
129  reg [2:0] cmd_we_any_r; // any of the abs or rel (valid 2, 1 and 0 cycles before data)
131 
132  reg [PNTR_WIDH+3:0] seq_cmd_wa; // width of in-page pointer plus 4 (number of pages)
133  wire [PNTR_WIDH+3:0] seq_cmd_ra; // width of in-page pointer plus 4 (number of pages)
134 
135  reg [3:0] page_r; // FIFO page from where commands are generated
136  reg [1:0] page_r_inc; // increment page_r - signal and delayed version
137  reg [PNTR_WIDH-1:0] rpointer; // FIFO read pointer for current page
138  reg [1:0] read_busy; // reading and sending command
139  reg conf_send; // valid && ackn
140  wire commands_pending; // wants to send some commands
141  reg [1:0] ren; // 1-hot ren to BRAM, then regen to BRAM
142  wire pre_cmd_seq_w; // 1 cycle before starting command read/send sequence
143  reg valid_r;
144 
145  wire [63:0] cmdseq_do; // output data from the sequence
146 
148  reg is_r; // interrupt status (not masked)
149  reg im_r; // interrtupt mask
150  wire irq_ctrl;
151 
152  assign is = is_r; // interrupt status (not masked)
153  assign im = im_r; // interrtupt mask
154  assign irq_ctrl = cmd_we_ctl_r[2] && (|irq_bits);
155 
156  assign waddr = cmdseq_do[32 +:AXI_WR_ADDR_BITS];
157  assign wdata = cmdseq_do[31:0];
158  assign seq_cmd_ra = {page_r,rpointer};
159 
160 
161  assign frame_no = wpage_asap;
162 
163  assign reset_cmd = (!reset_on && cmd_we_ctl_r[2] && cmd_data[CMDFRAMESEQ_RST_BIT]) || (por[1] && !por[2]);
165 // assign reset_seq_done = reset_on && wpage_inc[0] && (wpage_asap == 4'hf);
166  assign reset_seq_done = reset_on && wpage_inc[0] && (&wpage_asap[3:1]); // ends after 'he
167 
168 // assign pre_wpage_inc = (!cmd_we && !(|cmd_we_r) ) && (!wpage_inc[0] && !wpage_inc[1]) && ((next_frame_rq && initialized) || reset_on) ;
169  // During reset_on write pointer every cycle:
170 // assign pre_wpage_inc = (!cmd_we && !(|cmd_we_r) ) && ((next_frame_rq && initialized) || reset_on) ;
171  assign pre_wpage_inc = (!cmd_we && !(|cmd_we_r) ) && ((next_frame_rq && !wpage_inc[0] && initialized) || reset_on) ;
172  assign commands_pending = rpointer != fifo_wr_pointers_outr_r; // only look at the current page different pages will trigger page increment first
174  assign valid = valid_r;
175 
176 // parameter CMDFRAMESEQ_IRQ_BIT = 0,
177 // parameter CMDFRAMESEQ_IRQ_BITS = 2
178  always @ (posedge mclk) begin
179  if (mrst) is_r <= 0;
180  else if (frame_sync) is_r <= 1;
181  else if (irq_ctrl && (irq_bits == 2'b01)) is_r <= 0;
182 
183  if (mrst) im_r <= 0;
184  else if (irq_ctrl && irq_bits[1]) im_r <= irq_bits[0];
185  end
186 
187  always @ (posedge mclk) begin
188  if (mrst) por <= 0;
189  else por <= {por[1:0], 1'b1};
190 
191  if (mrst) seq_enrun <= 0;
192  else if (reset_cmd) seq_enrun <= 0;
194 
195  if (mrst) initialized <= 0;
196  else if (reset_seq_done) initialized <= 1;
197 
198  if (mrst) d_na <= 0;
199  else if (cmd_we_ctl_w) d_na <= 0;
200  else if (cmd_we) d_na <= ~ d_na;
201 
202  if (mrst) valid_r <= 0;
203  else if (ren[1]) valid_r <= 1;
204  else if (ackn) valid_r <= 0;
205 
206  end
207 
208  always @ (posedge mclk) begin
210  cmd_we_r <= {cmd_we_r[1:0], cmd_we};
214 // signals related to writing to seq FIFO
215  if (cmd_we_r[1] && !d_na) address_hold <= cmd_data[AXI_WR_ADDR_BITS-1:0];
216 // decoded commands
217 // write pointer memory
218  wpage_inc <= (&por[1:0]) ? {wpage_inc[0],pre_wpage_inc} : 2'b0;
219 
220  if (reset_cmd || !por[1]) wpage_next <= 1;
221  else if (wpage_inc[0]) wpage_next <= wpage_next + 1; //
222 
223  if (reset_cmd || !por[1]) wpage_asap <= 0;
224  else if (wpage_inc[0]) wpage_asap <= wpage_next; // valid at cmd_we_*_r
225 
226  if (reset_cmd || !por[1]) wpage_prev <= 4'hf;
227  else if (wpage_inc[0]) wpage_prev <= wpage_asap; // valid at cmd_we_*_r
228 
229  if (!por[1]) reset_on <= 0;
230  else if (reset_cmd) reset_on <= 1;
231  else if (reset_seq_done) reset_on <= 0;
232 
233  if (!por[1]) next_frame_rq <= 0;
234  else if (frame_sync) next_frame_rq <= 1;
235  else if (wpage_inc[0]) next_frame_rq <= 0;
236 
237 
238 // now cmd_we_abs_r or cmd_we_rel_r can not happen with wpage_inc[0] - earliest at the next cycle
239  if (cmd_we_abs_r) wpage_w <= (cmd_a[3:0] == wpage_prev)? wpage_asap : cmd_a[3:0];
240  else if (cmd_we_rel_r) wpage_w <= wpage_asap + cmd_a[3:0];
241  else if (wpage_inc[0]) wpage_w <= wpage_asap; // will now be previous (switched at the same cycle)
242 
243  we_fifo_wp <= cmd_we_any_r[1] || wpage_inc[0];
244 
245  if (cmd_we_any_r[1]) fifo_wr_pointers_outw_r <= fifo_wr_pointers_outw; // register pointer RAM output (write port)
246  // write to pointer RAM (to the same address as just read from if read)
248 
250 
251  fifo_wr_pointers_outr_r <= fifo_wr_pointers_outr; // just register write pointer for the read page
252  page_r_inc <= {page_r_inc[0],
253  (~read_busy[0] | conf_send) & // not busy or will not be busy next cycle (when page_r_inc active)
254  ~(|page_r_inc) & // read_page was not just incremented, so updated read pointer had a chance to propagate
255  (rpointer == fifo_wr_pointers_outr_r) & // nothing left in the frame FIFO pointed page_r
256  (page_r != wpage_asap)}; // the page commands are taken from is not the ASAP (current) page
257 
258  if (!por[1] || reset_on) page_r <= 0;
259  else if (page_r_inc[0]) page_r <= page_r+1;
260 
261 // if (reset_on || reset_cmd || page_r_inc[0]) rpointer <= 0; // TODO: move to rst ?
262  if (!por[1] || reset_on || page_r_inc[0]) rpointer <= 0; // TODO: move to rst ?
263  else if (ren[0]) rpointer <= rpointer + 1;
264 
265  conf_send <= valid && ackn;
266 
267 // if (reset_on || reset_cmd) read_busy <= 0;
268  if (!por[1] || reset_on) read_busy <= 0;
269  else read_busy <= {read_busy[0],
271  ren <= {ren[0], pre_cmd_seq_w};
272 // TODO: check generation of the reset sequence
273 
274  end
275 
277  .ADDR (CMDFRAMESEQ_ADDR),
278  .ADDR_MASK (CMDFRAMESEQ_MASK),
279  .NUM_CYCLES (6),
280  .ADDR_WIDTH (5),
281  .DATA_WIDTH (32),
282  .WE_EARLY (3) // generate cmd_we and cmd_a three cycles before cmd_data is valid
283  ) cmd_deser_32bit_i (
284  .rst (1'b0), // rst), // input
285  .clk (mclk), // input
286  .srst (mrst), // input
287  .ad (cmd_ad), // input[7:0]
288  .stb (cmd_stb), // input
289  .addr (cmd_a), // output[3:0]
290  .data (cmd_data), // output[31:0]
291  .we (cmd_we) // output
292  );
293 
294 // Generate one x64 BRAM, 3 of x32 or 3 x64, depending on the sequnecer depth (CMDFRAMESEQ_DEPTH): 32/64/128 commands per frame
295  generate
296  if (CMDFRAMESEQ_DEPTH == 32) begin
298  .REGISTERS(1),
299  .LOG2WIDTH_WR(6),
300  .LOG2WIDTH_RD(6),
301  .DUMMY(0)
302  ) ram_var_w_var_r_i (
303  .rclk (mclk), // input
304 // .raddr (seq_cmd_ra), // input[8:0]
305  .raddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[4:0]}), // input[8:0]
306  .ren (ren[0]), // input
307  .regen (ren[1]), // input
308  .data_out (cmdseq_do), // output[63:0]
309  .wclk (mclk), // input
310  // VDT TODO: make conditions in generate skip parsing if condition does not match
311 // .waddr (seq_cmd_wa), // input[8:0]
312  .waddr ({seq_cmd_wa[PNTR_WIDH+3 -:4],seq_cmd_wa[4:0]}), // input[8:0] // just to make VDT happy
313  .we (cmd_we_any_r[2]), // input
314  .web (8'hff), // input[7:0]
315  .data_in (cmdseq_di) // input[63:0]
316  );
317 
318  end
319  else if (CMDFRAMESEQ_DEPTH == 64) begin
321  .REGISTERS(1),
322  .LOG2WIDTH_WR(4),
323  .LOG2WIDTH_RD(4),
324  .DUMMY(0)
325  ) ram18_var_w_var_r_dl_i (
326  .rclk (mclk), // input
327 // .raddr (seq_cmd_ra), // input[9:0]
328  .raddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[5:0]}), // input[9:0]
329  .ren (ren[0]), // input
330  .regen (ren[1]), // input
331  .data_out (cmdseq_do[15:0]), // output[15:0]
332  .wclk (mclk), // input
333 // .waddr (seq_cmd_wa), // input[9:0]
334  .waddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[5:0]}), // input[9:0]
335  .we (cmd_we_any_r[2]), // input
336  .web (4'hf), // input[3:0]
337  .data_in (cmdseq_di[15:0]) // input[15:0]
338  );
339 
341  .REGISTERS(1),
342  .LOG2WIDTH_WR(4),
343  .LOG2WIDTH_RD(4),
344  .DUMMY(0)
345  ) ram18_var_w_var_r_dh_i (
346  .rclk (mclk), // input
347 // .raddr (seq_cmd_ra), // input[9:0]
348  .raddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[5:0]}), // input[9:0]
349  .ren (ren[0]), // input
350  .regen (ren[1]), // input
351  .data_out (cmdseq_do[31:16]), // output[15:0]
352  .wclk (mclk), // input
353 // .waddr (seq_cmd_wa), // input[9:0]
354  .waddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[5:0]}), // input[9:0]
355  .we (cmd_we_any_r[2]), // input
356  .web (4'hf), // input[3:0]
357  .data_in (cmdseq_di[31:16]) // input[15:0]
358  );
359 
361  .REGISTERS(1),
362  .LOG2WIDTH_WR(4),
363  .LOG2WIDTH_RD(4),
364  .DUMMY(0)
365  ) ram18_var_w_var_r_ad_i (
366  .rclk (mclk), // input
367 // .raddr (seq_cmd_ra), // input[9:0]
368  .raddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[5:0]}), // input[9:0]
369  .ren (ren[0]), // input
370  .regen (ren[1]), // input
371  .data_out (cmdseq_do[47:32]), // output[15:0]
372  .wclk (mclk), // input
373 // .waddr (seq_cmd_wa), // input[9:0]
374  .waddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[5:0]}), // input[9:0]
375  .we (cmd_we_any_r[2]), // input
376  .web (4'hf), // input[3:0]
377  .data_in (cmdseq_di[47:32]) // input[15:0]
378  );
379 
380  end
381 
382  else if (CMDFRAMESEQ_DEPTH == 128) begin
384  .REGISTERS(1),
385  .LOG2WIDTH_WR(4),
386  .LOG2WIDTH_RD(4),
387  .DUMMY(0)
388  ) ram_var_w_var_r_dl_i (
389  .rclk (mclk), // input
390 // .raddr (seq_cmd_ra), // input[10:0]
391  .raddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[6:0]}), // input[10:0]
392  .ren (ren[0]), // input
393  .regen (ren[1]), // input
394  .data_out (cmdseq_do[15:0]), // output[15:0]
395  .wclk (mclk), // input
396 // .waddr (seq_cmd_wa), // input[9:0]
397  .waddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[6:0]}), // input[10:0]
398  .we (cmd_we_any_r[2]), // input
399  .web (8'hff), // input[7:0]
400  .data_in (cmdseq_di[15:0]) // input[15:0]
401  );
402 
404  .REGISTERS(1),
405  .LOG2WIDTH_WR(4),
406  .LOG2WIDTH_RD(4),
407  .DUMMY(0)
408  ) ram_var_w_var_r_dh_i (
409  .rclk (mclk), // input
410 // .raddr (seq_cmd_ra), // input[10:0]
411  .raddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[6:0]}), // input[10:0]
412  .ren (ren[0]), // input
413  .regen (ren[1]), // input
414  .data_out (cmdseq_do[31:16]), // output[15:0]
415  .wclk (mclk), // input
416 // .waddr (seq_cmd_wa), // input[9:0]
417  .waddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[6:0]}), // input[10:0]
418  .we (cmd_we_any_r[2]), // input
419  .web (8'hff), // input[7:0]
420  .data_in (cmdseq_di[31:16]) // input[15:0]
421  );
422 
424  .REGISTERS(1),
425  .LOG2WIDTH_WR(4),
426  .LOG2WIDTH_RD(4),
427  .DUMMY(0)
428  ) ram_var_w_var_r_ad_i (
429  .rclk (mclk), // input
430 // .raddr (seq_cmd_ra), // input[10:0]
431  .raddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[6:0]}), // input[10:0]
432  .ren (ren[0]), // input
433  .regen (ren[1]), // input
434  .data_out (cmdseq_do[47:32]), // output[15:0]
435  .wclk (mclk), // input
436 // .waddr (seq_cmd_wa), // input[9:0]
437  .waddr ({seq_cmd_ra[PNTR_WIDH+3 -:4],seq_cmd_ra[6:0]}), // input[10:0]
438  .we (cmd_we_any_r[2]), // input
439  .web (8'hff), // input[7:0]
440  .data_in (cmdseq_di[47:32]) // input[15:0]
441  );
442 
443  end
444  else begin
445  // cause some error - invalid CMDFRAMESEQ_DEPTH
446  end
447  endgenerate
448 
449 endmodule
450 
10096seq_cmd_wareg[PNTR_WIDH+3:0]
cmd_deser_32bit_i cmd_deser
10081fifo_wr_pointers_outw_rreg[PNTR_WIDH-1:0]
[1 << LOG2WIDTH_WR-1:0] 11872data_in
[14-LOG2WIDTH_WR:0] 11869waddr
10097seq_cmd_rawire[PNTR_WIDH+3:0]
[1 << LOG2WIDTH_WR-1:0] 11597data_in
10061PNTR_WIDH(CMDFRAMESEQ_DEPTH > 32) ?((CMDFRAMESEQ_DEPTH > 64) ? 7 : 6) : 5
[1 << LOG2WIDTH_RD-1:0] 11592data_out
[13-LOG2WIDTH_RD:0] 11589raddr
10079fifo_wr_pointers_outwwire[PNTR_WIDH-1:0]
[ADDR_MASK2!=0?2:ADDR_MASK1!=0?1:0:0] 9935we
Definition: cmd_deser.v:60
[AXI_WR_ADDR_BITS-1:0] 10055waddr
10084address_holdreg[AXI_WR_ADDR_BITS-1:0]
ram_var_w_var_r_ad_i ram_var_w_var_r[generate]
[1 << LOG2WIDTH_RD-1:0] 11867data_out
[DATA_WIDTH-1:0] 9934data
Definition: cmd_deser.v:59
ram18_var_w_var_r_ad_i ram18_var_w_var_r[generate]
[14-LOG2WIDTH_RD:0] 11864raddr
[7:0] 9931ad
Definition: cmd_deser.v:56
[ADDR_WIDTH-1:0] 9933addr
Definition: cmd_deser.v:58
[13-LOG2WIDTH_WR:0] 11594waddr
[0:15] 10078fifo_wr_pointers_ramreg[PNTR_WIDH-1:0]
10100rpointerreg[PNTR_WIDH-1:0]
10082fifo_wr_pointers_outr_rreg[PNTR_WIDH-1:0]
10080fifo_wr_pointers_outrwire[PNTR_WIDH-1:0]