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