x393  1.0
FPGAcodeforElphelNC393camera
All Classes Namespaces Files Functions Variables
cmprs_macroblock_buf_iface.v
Go to the documentation of this file.
1 
41 `timescale 1ns/1ps
42 
44 `ifdef USE_OLD_DCT
45  parameter DCT_PIPELINE_PAUSE = 0 // No need to delay
46 `else
47  parameter DCT_PIPELINE_PAUSE = 48 // TODO: find really required value (minimal), adjust counter bits (now 6)
48  // 48 seems to be OK (may be less)
49 `endif
50 )(
51 // input rst,
52  input xclk, // global clock input, compressor single clock rate
53 
54  input mclk, // global clock for commands (posedge) and write side of the memory buffer (negedge)
55  input mrst, // @posedge mclk, sync reset
56  input xrst, // @posedge xclk, sync reset
57 
58  // buffer interface, DDR3 memory read
59  input xfer_reset_page_rd, // @ negedge mclk - reset ddr3 memory buffer. Use it to reset the read buffer too
60  input page_ready_chn, // single mclk (posedge)
61  output next_page_chn, // single mclk (posedge): Done with the page in the buffer, memory controller may read more data
62 
63  input frame_en, // if 0 - will reset logic immediately (but not page number)
64  input frame_start_xclk, // frame parameters are valid after this pulse
65  input frame_go, // start frame: if idle, will start reading data (if available),
66  // if running - will not restart a new frame if 0.
67  input [ 4:0] left_marg, // left margin (for not-yet-implemented) mono JPEG (8 lines tile row) can need 7 bits (mod 32 - tile)
68  input [12:0] n_blocks_in_row_m1, // number of macroblocks in a macroblock row minus 1
69  input [12:0] n_block_rows_m1, // number of macroblock rows in a frame minus 1
70  input [ 5:0] mb_w_m1, // macroblock width minus 1 // 3 LSB not used
71  input [ 4:0] mb_hper, // macroblock horizontal period (8/16) // 3 LSB not used
72  input [ 1:0] tile_width, // memory tile width (can be 128 for monochrome JPEG) Can be 32/64/128: 0 - 16, 1 - 32, 2 - 64, 3 - 128
73 
74  input mb_pre_end_in, // from cmprs_pixel_buf_iface - just in time to start a new macroblock w/o gaps
75  input mb_release_buf, // send required "next_page" pulses to buffer. Having rather long minimal latency in the memory
76  // controller this can just be the same as mb_pre_end_in
77  output mb_pre_start_out, // 1 clock cycle before stream of addresses to the buffer
78  output [ 1:0] start_page, // page to read next tile from (or first of several pages)
79  output [ 6:0] macroblock_x, // macroblock left pixel x relative to a tile (page) Maximal page - 128 bytes wide
80  output reg first_mb, // during first macroblock (valid @mb_pre_start_out)
81  output last_mb // during last macroblock (valid @mb_pre_start_out)
82 `ifdef DEBUG_RING
83  ,output [ 1:0] dbg_add_invalid,
84  output dbg_mb_release_buf
85 `endif
86 );
87 
88  wire reset_page_rd;
89  wire page_ready;
90 
91  wire frame_en_w;
93 
94  reg [12:0] mb_cols_left; // number of a macroblocks left in a row (after this)
95  reg [12:0] mb_rows_left; // number of a rows left in a row (after this)
96  wire [ 6:0] mbl_x; // macroblock left pixel x relative to a tile (page) Maximal page - 128 bytes wide
97  reg [ 6:3] mbl_x_r; // macroblock left pixel x relative to a tile (page) (3 low don't change)
98  reg [ 6:3] mbl_x_next_r; // macroblock left pixel x relative to a tile (page), not valid for first column (3 low don't change)
99  reg [ 7:3] mbl_x_inc_r; // intermediate register for calculating mbl_x_next_r and add_invalid
100  reg [ 7:3] mbl_x_last_r; // intermediate register for calculating needed_page
101 
102  reg [1:0] pre_advance_tiles; // advance tiles by this for same row of macroblocks
104  wire mb_pre_start_w; // start sequence for a macroblock
105  wire frame_pre_start_w; // start sequence for a new frame
107  reg [ 8:0] mb_pre_start; // 1-hot macroblock pre start calcualtions - TODO: adjust width
108  reg mb_pre_start4_first; // first cycle after mb_pre_start[3]
109  wire [ 2:0] buf_diff; // difference between page needed and next valid - should be negative to have it ready
110  wire buf_ready_w; // External memory buffer has all the pages needed
111 
113  reg mb_last_in_row;
115 // wire last_mb;
116  reg [ 2:0] next_valid; // number of next valid page (only 2 LSB are actual page number)
117  reg [ 2:0] next_invalid; // oldest valid page
118  reg [ 1:0] add_invalid; // advance next_invalid pointer by this value, send next_page pulses
119 // reg [ 2:0] used_pages; // number of pages simultaneously used for the last macroblock
120  reg [ 1:0] used_pages; // number of pages simultaneously used for the last macroblock - [2] was never used
121  reg [ 2:0] needed_page; // calculate at MB start
122  reg pre_first_mb; // from frame start to mb_pre_start[2]
123 // reg first_mb; // from mb_pre_start[2] to mb_pre_start[1]
124  wire starting;
125  reg frame_pre_run;
126  reg [1:0] frame_may_start;
127 
128  reg [5:0] dct_pipeline_delay_cntr;
129 
130 `ifdef DEBUG_RING
131  assign dbg_add_invalid = add_invalid;
133 `endif
134  assign frame_en_w = frame_en && frame_go;
135 
136  assign mbl_x={mbl_x_r[6:3], left_marg[2:0]};
137 
138  assign buf_diff = needed_page - next_valid;
139  assign buf_ready_w = buf_diff[2];
140  assign mb_pre_start_out=mb_pre_start[5]; // first after wait?
141  assign macroblock_x = mbl_x;
142 
143  assign last_mb = mb_last_row && mb_last_in_row;
144  assign starting = |mb_pre_start;
145 
146 // assign mb_pre_start_w = (mb_pre_end_in && (!last_mb || frame_en_w)) || (!frame_pre_run && frame_en_w && !frame_en_r && !starting);
147 // assign frame_pre_start_w = frame_en_w && ((mb_pre_end_in && last_mb) || (!frame_pre_run && !frame_en_r && !starting));
150 
151  assign start_page = next_invalid[1:0]; // oldest page needed for this macroblock
152  always @ (posedge xclk) begin
153  if (!frame_en) frame_en_r <= 0;
154  else frame_en_r <= frame_en_w;
155 
156  if (!frame_en_w || starting) frame_may_start[0] <= 0;
157  else if (frame_start_xclk) frame_may_start[0] <= 1;
159 
160  frame_pre_start_r <= frame_pre_start_w; // same time as mb_pre_start
161 
162  if (!frame_en) mb_first_in_row <= 0;
163  else if (frame_pre_start_r) mb_first_in_row <= 1;
165 
166 
167  if (!frame_en) frame_pre_run <= 0;
168  else if (mb_pre_start_w) frame_pre_run <= 1;
169  else if (mb_pre_end_in && last_mb) frame_pre_run <= 0;
170 
172  else if (mb_pre_start[0] && mb_last_in_row) mb_rows_left <= mb_rows_left - 1;
173 
175  else if (mb_pre_start[0]) mb_cols_left <= mb_cols_left - 1;
176 
177  if (mb_pre_start[1]) mb_last_row <= (mb_rows_left == 0);
178 
179  if (mb_pre_start[1]) mb_last_in_row <= (mb_cols_left == 0);
180 
181  if (!frame_en || mb_pre_start[1]) pre_first_mb <= 0;
182  else if (frame_pre_start_r) pre_first_mb <= 1;
183 
185 
186  // pages read from the external memory, previous one is the last in the buffer
187  if (reset_page_rd) next_valid <= 0;
188  else if (page_ready) next_valid <= next_valid + 1;
189 
190 
191  // calculate before starting each macroblock (will wait if buffer is not ready) (TODO: align mb_pre_start[0] to mb_pre_end[2] - same)
192  //mb_pre_start_w
193  // TODO: Here enforce minimal pause (if not zero for the DCT pipeline to recover
194  // will wait for buf_ready_w, but not less than DCT_PIPELINE_PAUSE (or no wait at all)
196  if (xrst) dct_pipeline_delay_cntr <= 0;
197  else if (mb_pre_start4_first && !buf_ready_w) dct_pipeline_delay_cntr <= DCT_PIPELINE_PAUSE -1;
199 
200 
201  if (!frame_en_r) mb_pre_start <= 0;
202  if (mb_pre_start_w) mb_pre_start <= 1;
204 
205  if (mb_pre_start[1]) mbl_x_r[6:3] <= mb_first_in_row? {2'b0,left_marg[4:3]} : mbl_x_next_r[6:3];
206  if (mb_pre_start[2]) mbl_x_last_r[7:3] <= {1'b0,mbl_x_r[6:3]} + {2'b0,mb_w_m1[5:3]};
207  if (mb_pre_start[3]) begin
208  case (tile_width)
209  2'b00: needed_page[2:0] <= next_invalid[2:0]+{1'b0, mbl_x_last_r[5:4]};
210  2'b01: needed_page[2:0] <= next_invalid[2:0]+{1'b0, mbl_x_last_r[6:5]};
211  2'b10: needed_page[2:0] <= next_invalid[2:0]+{1'b0, mbl_x_last_r[7:6]};
212  2'b11: needed_page[2:0] <= next_invalid[2:0]+{2'b0, mbl_x_last_r[7]};
213  endcase
214  end
215 
216  // at the end of each macroblock - calculate start page increment (and after delay - advance invalidate_next)
217  // changed to after started:
218 
219  // calculate next start X in page (regardless of end of macroblock row - selection will be at macroblock start)
220 
221  if (mb_pre_start[5]) mbl_x_inc_r[7:3] <= {1'b0,mbl_x_r[6:3]} + {3'b0,mb_hper[4:3]};
222  if (mb_pre_start[6]) begin
223  case (tile_width)
224  2'b00: begin
225  mbl_x_next_r[6:3] <= {3'b0,mbl_x_inc_r[3]};
226  pre_advance_tiles[1:0] <= mbl_x_inc_r[5:4];
227  end
228  2'b01: begin
229  mbl_x_next_r[6:3] <= {2'b0,mbl_x_inc_r[4:3]};
230  pre_advance_tiles[1:0] <= mbl_x_inc_r[6:5];
231  end
232  2'b10: begin
233  mbl_x_next_r[6:3] <= {1'b0,mbl_x_inc_r[5:3]};
234  pre_advance_tiles[1:0] <= mbl_x_inc_r[7:6];
235  end
236  2'b11: begin
237  mbl_x_next_r[6:3] <= { mbl_x_inc_r[6:3]};
238  pre_advance_tiles[1:0] <= {1'b0, mbl_x_inc_r[7]};
239  end
240  endcase
241 // used_pages <= needed_page - next_invalid +1;
242  used_pages <= needed_page[1:0] - next_invalid[1:0] +1; // nit [2] not used
243  end
244  if (mb_pre_start[7]) begin // TODO: apply after delay, regardless last or not
247  end
248  // pages already processed by compressor - they can be reused for reading new tiles
249  if (reset_page_rd) next_invalid <= 0;
250  else if (mb_pre_start[8]) next_invalid <= next_invalid + {1'b0, add_invalid}; // TODO: Send next_page after delay
251  // "next_page_ pulses will be sent near the end of the macroblock
252 
253 
254 
255 
256  end
257  reg nmrst;
258  always @(negedge mclk) nmrst <= mrst;
259  // synchronization between mclk and xclk clock domains
260  // negedge mclk -> xclk (verify clock inversion is absorbed)
262  // mclk -> xclk
264 
266  .WIDTH(3),
267  .EXTRA_DLY(0)
268  ) multipulse_cross_clock_i (
269  .rst (xrst), // input
270  .src_clk (xclk), // input
271  .dst_clk (mclk), // input
272  .num_pulses ({1'b0,add_invalid}), // input[0:0]
273  .we (mb_release_buf), // input
274  .out_pulse (next_page_chn), // output
275  .busy () // output
276  );
277 
278 endmodule
279 
280 
multipulse_cross_clock_i multipulse_cross_clock