x393  1.0
FPGAcodeforElphelNC393camera
cmd_encod_tiled_wr.v
Go to the documentation of this file.
1 
50 `timescale 1ns/1ps
51 /*
52 TODO Comments from cmd_encod_tiled_rd, update
53 Minimal ACTIVATE period =4 Tcm or 10ns, so maximal no-miss rate is Tck=1.25 ns (800 MHz)
54 Minimal window of 4 ACTIVATE pulses - 16 Tck or 40 (40 ns), so one ACTIVATE per 8 Tck is still OK down to 1.25 ns
55 Reads are in 16-byte colums: 1 8-burst (16 bytes) in a row, then next row, bank inc first. Then (if needed) - next column
56 Number of rows should be >=5 (4 now for tCK=2.5ns to meet tRP (precharge to activate) of the same bank (tRP=13ns)
57 Can read less if just one column
58 TODO: Maybe allow less rows with different sequence (no autoprecharge/no activate?) Will not work if row crosses page boundary
59 number fo rows>1!
60 
61 Known issues:
62 1: Most tile heights cause timing violation. Valid height mod 8 can be 0,6,7 (1,2,3,4,5 - invalid)
63 2: With option "keep_open" there should be no page boundary crossings, caller only checks the first line, and if window full width
64  is not multiple of CAS page, page crossings can appear on other than first line (fix caller to use largest common divider of page and
65  frame full width? Seems easy to fix
66 */
67 
69  parameter ADDRESS_NUMBER= 15,
70  parameter COLADDR_NUMBER= 10,
71  parameter CMD_PAUSE_BITS= 10,
72  parameter CMD_DONE_BIT= 10, // VDT BUG: CMD_DONE_BIT is used in a function call parameter!
73  parameter FRAME_WIDTH_BITS= 13, // Maximal frame width - 8-word (16 bytes) bursts
74  parameter WSEL= 1'b0
75 ) (
76  input mrst,
77  input clk,
78 // programming interface
79  input [2:0] start_bank, // bank address
80  input [ADDRESS_NUMBER-1:0] start_row, // memory row
81  input [COLADDR_NUMBER-4:0] start_col, // start memory column in 8-bit bursts
82  input [FRAME_WIDTH_BITS:0] rowcol_inc_in, // increment {row.col} when bank rolls over, removed 3 LSBs (in 8-bursts)
83  input [5:0] num_rows_in_m1, // number of rows to read minus 1
84  input [5:0] num_cols_in_m1, // number of 16-pixel columns to read (rows first, then columns) - 1
85  input keep_open_in, // keep banks open (for <=8 banks only
86  input skip_next_page_in, // do not reset external buffer (continue)
87  input start, // start generating commands
88  output reg [31:0] enc_cmd, // encoded command SuppressThisWarning VivadoSynthesis: [Synth 8-3332] Sequential element cmd_encod_tiled_wr.enc_cmd_reg[11,9,6,4:3,1] is unused and will be removed from module cmd_encod_tiled_wr.
89  output reg enc_wr, // write encoded command
90  output reg enc_done // encoding finished
91 );
92  localparam FULL_ADDR_NUMBER=ADDRESS_NUMBER+COLADDR_NUMBER; // excluding 3 CA lsb, but adding 3 bank
93  localparam ROM_WIDTH=12;
94  localparam ROM_DEPTH=4;
95  localparam ENC_NOP= 0;
96  localparam ENC_BUF_RD= 1;
97  localparam ENC_DQS_TOGGLE= 2;
98  localparam ENC_DQ_DQS_EN= 3;
99  localparam ENC_SEL= 4;
100  localparam ENC_ODT= 5;
101  localparam ENC_CMD_SHIFT= 6; // [7:6] - command: 0 -= NOP, 1 - WRITE, 2 - PRECHARGE, 3 - ACTIVATE
102  localparam ENC_PAUSE_SHIFT= 8; // [9:8] - 2- bit pause (for NOP commandes)
103  localparam ENC_PRE_DONE= 10;
104  localparam ENC_BUF_PGNEXT= 11;
105 
106  localparam ENC_CMD_NOP= 0; // 2-bit locally encoded commands
107  localparam ENC_CMD_WRITE= 1;
108  localparam ENC_CMD_ACTIVATE= 2;
109 
110  localparam LOOP_FIRST= 6; // address of the first word in a loop
111  localparam LOOP_LAST= 7; // address of the last word in a loop
112 
113  localparam CMD_NOP= 0; // 3-bit normal memory RCW commands (positive logic)
114  localparam CMD_WRITE= 3;
115  localparam CMD_ACTIVATE= 4;
116 
117 
118  reg [ADDRESS_NUMBER-1:0] row; // memory row
119  reg [COLADDR_NUMBER-4:0] col; // start memory column in 8-bursts
120  reg [2:0] bank; // memory bank;
121  reg [5:0] num_rows_m1; // number of rows in a tile minus 1
122  reg [5:0] num_cols128_m1; // number of r16-byte columns in a tile -1
123  reg [FRAME_WIDTH_BITS:0] rowcol_inc; // increment {row.col} when bank rolls over, remove 3 LSBs (in 8-bursts)
124 
125  reg keep_open;
127  reg gen_run;
128 // reg gen_run_d; // to output "done"?
129  reg [ROM_DEPTH-1:0] gen_addr; // will overrun as stop comes from ROM
130 
131  reg [ROM_WIDTH-1:0] rom_r; // SuppressThisWarning VivadoSynthesis: [Synth 8-3332] Sequential element cmd_encod_tiled_wr.rom_r_reg[8,0] is unused and will be removed from module cmd_encod_tiled_wr.
132  wire pre_done;
133  wire [1:0] rom_cmd;
134  wire [1:0] rom_skip;
135  wire [2:0] full_cmd;
136 // reg done;
137 
138  reg [FULL_ADDR_NUMBER-4:0] top_rc; // top combined row,column,bank burst address (excludes 3 CA LSBs), valid/modified @pre_act
140  reg last_col;
141  wire pre_act; //1 cycle before optional ACTIVATE
142  wire pre_write; //1 cycle before READ command
143  reg [5:0] scan_row; // current row in a tile (valid @pre_act)
144  reg [5:0] scan_col; // current 16-byte column in a tile (valid @pre_act)
145  reg start_d; // start, delayed by 1 clocks
146  wire last_row;
147  reg [FULL_ADDR_NUMBER-1:0] row_col_bank; // RA,CA, BA - valid @pre_act;
148  wire [COLADDR_NUMBER-1:0] col_bank;// CA, BA - valid @ pre_write;
149 
152 
153  wire [2:0] next_bank_w;
154  wire [ADDRESS_NUMBER+COLADDR_NUMBER-4:0] next_rowcol_w; // next row/col when bank rolls over (in 8-bursts)
155 
157 
158  wire [FULL_ADDR_NUMBER-1:0] row_col_bank_next_w; // RA,CA, BA - valid @pre_act;
159 
160 // reg cut_buf_rd;
161 
162 // always @ (posedge clk) begin
163 // if (!gen_run) cut_buf_rd <= 0;
164 // else if ((gen_addr==(LOOP_LAST-1)) && loop_continue) cut_buf_rd <= 1; //*******
165 // end
166 
168  {top_rc,bank}: // can not work if ACTIVATE is next after ACTIVATE in the last row (single-row tile)
169  (&row_col_bank[2:0]? // bank==7
170  {next_rowcol_w,3'b0}:
172 
173 
174  assign pre_done=rom_r[ENC_PRE_DONE] && gen_run;
175  assign rom_cmd= rom_r[ENC_CMD_SHIFT+:2]; // & {enable_act,1'b1}; // disable bit 1 if activate is disabled (not the first column)
176  assign rom_skip= rom_r[ENC_PAUSE_SHIFT+:2];
177  assign full_cmd= (enable_act && rom_cmd[1]) ? CMD_ACTIVATE : (rom_cmd[0] ? CMD_WRITE : CMD_NOP);
178 
179  assign last_row= (scan_row==num_rows_m1);
180  assign enable_act= first_col || !keep_open; // TODO: do not forget to zero addresses too (or they will become pause/done)
181  assign next_bank_w= row_col_bank[2:0]+1; //bank+1;
183 
184  assign pre_act= gen_run && rom_cmd[1]; //1 cycle before optional ACTIVATE
185  assign pre_write= rom_r[ENC_CMD_SHIFT]; //1 cycle before READ command
186 
187 
188  always @ (posedge clk) begin
189  if (mrst) gen_run <= 0;
190  else if (start_d) gen_run<= 1; // delaying
191  else if (pre_done) gen_run<= 0;
192 
193  if (mrst) num_rows_m1 <= 0;
194  else if (start) num_rows_m1 <= num_rows_in_m1; // number of rows
195 
196  if (mrst) num_cols128_m1 <= 0;
197  else if (start) num_cols128_m1 <= num_cols_in_m1; // number of r16-byte columns
198 
199  if (mrst) start_d <=0;
200  else start_d <= start;
201 
202  if (mrst) top_rc <= 0;
203  else if (start_d) top_rc <= {row,col}+1;
204  else if (pre_act && last_row) top_rc <= top_rc+1; // may increment RA
205 
206  if (mrst) row_col_bank <= 0;
207  else if (start_d) row_col_bank <= {row,col,bank}; // TODO: Use start_col,... and start, not start_d?
208 
210 
211 
212  if (mrst) scan_row <= 0;
213  else if (start_d) scan_row <= 0;
214  else if (pre_act) scan_row <= last_row?0:scan_row+1;
215 
216  if (mrst) scan_col <= 0;
217  else if (start_d) scan_col <= 0;
218  else if (pre_act && last_row) scan_col <= scan_col+1; // for ACTIVATE, not for READ
219 
220  if (mrst) first_col <= 0;
221  else if (start_d) first_col <= 1;
222  else if (pre_act && last_row) first_col <= 0;
223 
224  if (mrst) last_col <= 0;
225  else if (start_d) last_col <= num_cols128_m1==0; // if single column - will start with 1'b1;
226  else if (pre_act) last_col <= (scan_col==num_cols128_m1); // too early for READ ?
227 
228  if (mrst) enable_autopre <= 0;
229  else if (start_d) enable_autopre <= 0;
230  else if (pre_act) enable_autopre <= last_col || !keep_open; // delayed by 2 pre_act tacts form last_col, OK with a single column
231 
232  if (mrst) loop_continue<=0;
234 
235  if (mrst) gen_addr <= 0;
236  else if (!start_d && !gen_run) gen_addr <= 0;
237  else if ((gen_addr==LOOP_LAST) && !loop_continue) gen_addr <= LOOP_FIRST; // skip loop alltogeter
238  else gen_addr <= gen_addr+1; // not in a loop
239  end
240 
241  always @ (posedge clk) if (start) begin
242  row<=start_row;
243  col <= start_col;
244  bank <= start_bank;
246  keep_open <= keep_open_in && (|num_cols_in_m1[5:3] == 0);
248  end
249 
250  // ROM-based (registered output) encoded sequence
251  always @ (posedge clk) begin
252  if (mrst) rom_r <= 0;
253  else case (gen_addr)
254  4'h0: rom_r <= (ENC_CMD_ACTIVATE << ENC_CMD_SHIFT) | (1 << ENC_BUF_RD) ; // here does not matter, just to work with masked ACTIVATE
255  4'h1: rom_r <= (ENC_CMD_NOP << ENC_CMD_SHIFT) | (1 << ENC_BUF_RD) ;
256  4'h2: rom_r <= (ENC_CMD_ACTIVATE << ENC_CMD_SHIFT) | (1 << ENC_BUF_RD) | (WSEL << ENC_SEL);
257  4'h3: rom_r <= (ENC_CMD_WRITE << ENC_CMD_SHIFT) | (1 << ENC_BUF_RD) | (WSEL << ENC_SEL) | (1 << ENC_ODT);
258  4'h4: rom_r <= (ENC_CMD_ACTIVATE << ENC_CMD_SHIFT) | (1 << ENC_BUF_RD) | (WSEL << ENC_SEL) | (1 << ENC_ODT);
259  4'h5: rom_r <= (ENC_CMD_WRITE << ENC_CMD_SHIFT) | (1 << ENC_BUF_RD) | (WSEL << ENC_SEL) | (1 << ENC_ODT) | (1 << ENC_DQ_DQS_EN) | (1 << ENC_DQS_TOGGLE);
260  // start loop
261  4'h6: rom_r <= (ENC_CMD_ACTIVATE << ENC_CMD_SHIFT) | (1 << ENC_BUF_RD) | (WSEL << ENC_SEL) | (1 << ENC_ODT) | (1 << ENC_DQ_DQS_EN) | (1 << ENC_DQS_TOGGLE);
262  4'h7: rom_r <= (ENC_CMD_WRITE << ENC_CMD_SHIFT) | (1 << ENC_BUF_RD) | (WSEL << ENC_SEL) | (1 << ENC_ODT) | (1 << ENC_DQ_DQS_EN) | (1 << ENC_DQS_TOGGLE);
263  // end loop
264  4'h8: rom_r <= (ENC_CMD_NOP << ENC_CMD_SHIFT) | (WSEL << ENC_SEL) | (1 << ENC_ODT) | (1 << ENC_DQ_DQS_EN) | (1 << ENC_DQS_TOGGLE);
265  4'h9: rom_r <= (ENC_CMD_WRITE << ENC_CMD_SHIFT) | (1 << ENC_BUF_PGNEXT) | (WSEL << ENC_SEL) | (1 << ENC_ODT) | (1 << ENC_DQ_DQS_EN) | (1 << ENC_DQS_TOGGLE);
266  4'ha: rom_r <= (ENC_CMD_NOP << ENC_CMD_SHIFT) | (3 << ENC_PAUSE_SHIFT) | (WSEL << ENC_SEL) | (1 << ENC_ODT) | (1 << ENC_DQ_DQS_EN) | (1 << ENC_DQS_TOGGLE);
267  4'hb: rom_r <= (ENC_CMD_NOP << ENC_CMD_SHIFT) | (3 << ENC_PAUSE_SHIFT);
268  4'hc: rom_r <= (ENC_CMD_NOP << ENC_CMD_SHIFT) | (1 << ENC_PRE_DONE);
269  default:rom_r <= 0;
270  endcase
271  end
272  always @ (posedge clk) begin
273  if (mrst) enc_wr <= 0;
274  else enc_wr <= gen_run || gen_run; // gen_run_d; *****
275 
276  if (mrst) enc_done <= 0;
277  else enc_done <= enc_wr && !gen_run; // !gen_run_d; *****
278 
279  if (mrst) enc_cmd <= 0;
280  else if (gen_run) begin
281  if (rom_cmd[0] || (rom_cmd[1] && enable_act)) enc_cmd <= func_encode_cmd ( // encode non-NOP command
282  rom_cmd[1]? // activate
283  row_col_bank[FULL_ADDR_NUMBER-1:COLADDR_NUMBER]: // top combined row,column,bank burst address (excludes 3 CA LSBs), valid/modified @pre_act
284  {{ADDRESS_NUMBER-COLADDR_NUMBER-1{1'b0}},
287  3'b0}, // [14:0] addr; // 15-bit row/column address
288  rom_cmd[1]?
289  row_col_bank[2:0]:
290  col_bank[2:0], //
291  full_cmd[2:0], // rcw; // RAS/CAS/WE, positive logic
292  rom_r[ENC_ODT], // odt_en; // enable ODT
293  1'b0, // cke; // disable CKE
294  rom_r[ENC_SEL], // sel; // first/second half-cycle, other will be nop (cke+odt applicable to both)
295  rom_r[ENC_DQ_DQS_EN], // dq_en; // enable (not tristate) DQ lines (internal timing sequencer for 0->1 and 1->0)
296  rom_r[ENC_DQ_DQS_EN], // dqs_en; // enable (not tristate) DQS lines (internal timing sequencer for 0->1 and 1->0)
297  rom_r[ENC_DQS_TOGGLE], // dqs_toggle; // enable toggle DQS according to the pattern
298  1'b0, // dci; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
299  1'b0, // buf_wr; // connect to external buffer (but only if not paused)
300  rom_r[ENC_BUF_RD], // buf_rd; // connect to external buffer (but only if not paused)
301  rom_r[ENC_NOP], // nop; // add NOP after the current command, keep other data
302  rom_r[ENC_BUF_PGNEXT] && !skip_next_page);// buf_rst; // connect to external buffer (but only if not paused)
303  else enc_cmd <= func_encode_skip ( // encode pause
304  {{CMD_PAUSE_BITS-2{1'b0}},rom_skip[1:0]}, // skip; // number of extra cycles to skip (and keep all the other outputs)
305  pre_done, // done, // end of sequence
306  3'b0, // bank (here OK to be any)
307  rom_r[ENC_ODT], // odt_en; // enable ODT
308  1'b0, // cke; // disable CKE
309  rom_r[ENC_SEL], // sel; // first/second half-cycle, other will be nop (cke+odt applicable to both)
310  rom_r[ENC_DQ_DQS_EN], // dq_en; // enable (not tristate) DQ lines (internal timing sequencer for 0->1 and 1->0)
311  rom_r[ENC_DQ_DQS_EN], // dqs_en; // enable (not tristate) DQS lines (internal timing sequencer for 0->1 and 1->0)
312  rom_r[ENC_DQS_TOGGLE], // dqs_toggle; // enable toggle DQS according to the pattern
313  1'b0, // dci; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
314  1'b0, // buf_wr; // connect to external buffer (but only if not paused)
315  rom_r[ENC_BUF_RD], // buf_rd; // connect to external buffer (but only if not paused)
316  rom_r[ENC_BUF_PGNEXT] && !skip_next_page);// buf_rst; // connect to external buffer (but only if not paused)
317  end
318  end
320  .WIDTH(COLADDR_NUMBER)
321  ) fifo_2regs_i (
322  .mrst (mrst), // input
323  .clk (clk), // input
324  .din (row_col_bank[COLADDR_NUMBER-1:0]), // input[15:0]
325  .wr(pre_act), // input
326  .rd(pre_write), // input
327  .srst(start_d), // input
328  .dout(col_bank) // output[15:0]
329  );
366 
367  function [31:0] func_encode_cmd;
368  input [14:0] addr; // 15-bit row/column address
369  input [2:0] bank; // bank (here OK to be any)
370  input [2:0] rcw; // RAS/CAS/WE, positive logic
371  input odt_en; // enable ODT
372  input cke; // disable CKE
373  input sel; // first/second half-cycle, other will be nop (cke+odt applicable to both)
374  input dq_en; // enable (not tristate) DQ lines (internal timing sequencer for 0->1 and 1->0)
375  input dqs_en; // enable (not tristate) DQS lines (internal timing sequencer for 0->1 and 1->0)
376  input dqs_toggle; // enable toggle DQS according to the pattern
377  input dci; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
378  input buf_wr; // connect to external buffer (but only if not paused)
379  input buf_rd; // connect to external buffer (but only if not paused)
380  input nop; // add NOP after the current command, keep other data
381  input buf_rst; // connect to external buffer (but only if not paused)
382  begin
383  func_encode_cmd={
384  addr[14:0], // 15-bit row/column address
385  bank [2:0], // bank
386  rcw[2:0], // RAS/CAS/WE
387  odt_en, // enable ODT
388  cke, // may be optimized (removed from here)?
389  sel, // first/second half-cycle, other will be nop (cke+odt applicable to both)
390  dq_en, // enable (not tristate) DQ lines (internal timing sequencer for 0->1 and 1->0)
391  dqs_en, // enable (not tristate) DQS lines (internal timing sequencer for 0->1 and 1->0)
392  dqs_toggle, // enable toggle DQS according to the pattern
393  dci, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
394  buf_wr, // phy_buf_wr, // connect to external buffer (but only if not paused)
395  buf_rd, // phy_buf_rd, // connect to external buffer (but only if not paused)
396  nop, // add NOP after the current command, keep other data
397  buf_rst // Reserved for future use
398  };
399  end
400  endfunction
401 
402  function [31:0] func_encode_skip;
403  input [CMD_PAUSE_BITS-1:0] skip; // number of extra cycles to skip (and keep all the other outputs)
404  input done; // end of sequence
405  input [2:0] bank; // bank (here OK to be any)
406  input odt_en; // enable ODT
407  input cke; // disable CKE
408  input sel; // first/second half-cycle, other will be nop (cke+odt applicable to both)
409  input dq_en; // enable (not tristate) DQ lines (internal timing sequencer for 0->1 and 1->0)
410  input dqs_en; // enable (not tristate) DQS lines (internal timing sequencer for 0->1 and 1->0)
411  input dqs_toggle; // enable toggle DQS according to the pattern
412  input dci; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
413  input buf_wr; // connect to external buffer (but only if not paused)
414  input buf_rd; // connect to external buffer (but only if not paused)
415  input buf_rst; // connect to external buffer (but only if not paused)
416  begin
417  func_encode_skip= func_encode_cmd (
418  {{14-CMD_DONE_BIT{1'b0}}, done, skip[CMD_PAUSE_BITS-1:0]}, // 15-bit row/column address
419  bank[2:0], // bank (here OK to be any)
420  3'b0, // RAS/CAS/WE, positive logic
421  odt_en, // enable ODT
422  cke, // disable CKE
423  sel, // first/second half-cycle, other will be nop (cke+odt applicable to both)
424  dq_en, // enable (not tristate) DQ lines (internal timing sequencer for 0->1 and 1->0)
425  dqs_en, // enable (not tristate) DQS lines (internal timing sequencer for 0->1 and 1->0)
426  dqs_toggle, // enable toggle DQS according to the pattern
427  dci, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
428  buf_wr, // connect to external buffer (but only if not paused)
429  buf_rd, // connect to external buffer (but only if not paused)
430  1'b0, // nop
431  buf_rst);
432  end
433  endfunction
434 
435 
436 endmodule
437 
4533row_col_bankreg[FULL_ADDR_NUMBER-1:0]
[WIDTH-1:0] 10385din
Definition: fifo_2regs.v:47
4510colreg[COLADDR_NUMBER-4:0]
[ADDRESS_NUMBER-1:0] 4477start_row
4488FULL_ADDR_NUMBERADDRESS_NUMBER+COLADDR_NUMBER
4518gen_addrreg[ROM_DEPTH-1:0]
[WIDTH-1:0] 10389dout
Definition: fifo_2regs.v:51
4538next_rowcol_wwire[ADDRESS_NUMBER+COLADDR_NUMBER-4:0]
4519rom_rreg[ROM_WIDTH-1:0]
4524top_rcreg[FULL_ADDR_NUMBER-4:0]
4509rowreg[ADDRESS_NUMBER-1:0]
4534col_bankwire[COLADDR_NUMBER-1:0]
4514rowcol_increg[FRAME_WIDTH_BITS:0]
[FRAME_WIDTH_BITS:0] 4479rowcol_inc_in
4540row_col_bank_next_wwire[FULL_ADDR_NUMBER-1:0]
[COLADDR_NUMBER-4:0] 4478start_col