x393  1.0
FPGAcodeforElphelNC393camera
gtx_elastic.v
Go to the documentation of this file.
1 
39 module gtx_elastic #(
40  parameter DEPTH_LOG2 = 4, // 3, // => 8 total rows
41  parameter OFFSET = 8 // 4 // distance between read and write pointers, = wr_ptr - rd_ptr
42 )
43 (
44  input wire rst,
45  input wire wclk,
46  input wire rclk,
47 
48  input wire isaligned_in,
49  input wire [1:0] charisk_in,
50  input wire [1:0] notintable_in,
51  input wire [1:0] disperror_in,
52  input wire [15:0] data_in,
53 
54  output wire isaligned_out,
55  output wire [1:0] charisk_out,
56  output wire [1:0] notintable_out,
57  output wire [1:0] disperror_out,
58  output wire [15:0] data_out,
59 
60 // strobes LAST word in a dword primitive
61  output wire lword_strobe,
62 
63 // status outputs, just in case
64  output wire full,
65  output wire empty
66 );
67 // gather inputs and outputs
68 wire [22:0] indata;
69 wire [22:0] outdata;
71 assign isaligned_out = outdata[22];
72 assign notintable_out = outdata[21:20];
73 assign disperror_out = outdata[19:18];
74 assign charisk_out = outdata[17:16];
75 assign data_out = outdata[15:0];
76 
77 localparam HI = DEPTH_LOG2 - 1; // hi bus index
78 /*
79  buffer itself
80  */
81 // data storage
82 reg [22:0] ram [(1 << DEPTH_LOG2) - 1:0];
83 // data to/from fifo
84 wire [22:0] inram;
85 reg [22:0] outram;
86 // adresses in their natural clock domains
87 reg [HI:0] rd_addr;
88 reg [HI:0] wr_addr;
89 // incremened addresses
90 wire [HI:0] wr_next_addr;
91 wire [HI:0] rd_next_addr;
92 // gray coded addresses
93 reg [HI:0] rd_addr_gr;
94 reg [HI:0] wr_addr_gr;
95 // anti-metastability shift registers for gray-coded addresses
96 reg [HI:0] rd_addr_gr_r;
97 reg [HI:0] wr_addr_gr_r;
98 reg [HI:0] rd_addr_gr_rr;
99 reg [HI:0] wr_addr_gr_rr;
100 // resynced to opposite clks addresses
101 wire [HI:0] rd_addr_r;
102 wire [HI:0] wr_addr_r;
103 // fifo states
104 //wire full; // MAY BE full. ~full -> MUST NOT be full
105 //wire empty; // MAY BE empty. ~empty -> MUST NOT be empty
106 wire re;
107 wire we;
108 
109 assign wr_next_addr = wr_addr + 1'b1;
110 assign rd_next_addr = rd_addr + 1'b1;
111 // wclk domain counters
112 always @ (posedge wclk)
113 begin
114  wr_addr <= rst ? {DEPTH_LOG2{1'b0}} : we ? wr_next_addr : wr_addr;
115  wr_addr_gr <= rst ? {DEPTH_LOG2{1'b0}} : we ? wr_next_addr ^ {1'b0, wr_next_addr[HI:1]} : wr_addr_gr;
116 end
117 // rclk domain counters
118 always @ (posedge rclk)
119 begin
120  rd_addr <= rst ? {DEPTH_LOG2{1'b0}} : re ? rd_next_addr : rd_addr;
121  rd_addr_gr <= rst ? {DEPTH_LOG2{1'b0}} : re ? rd_next_addr ^ {1'b0, rd_next_addr[HI:1]} : rd_addr_gr;
122 end
123 // write address -> rclk (rd) domain to compare
124 always @ (posedge rclk)
125 begin
126  wr_addr_gr_r <= rst ? {DEPTH_LOG2{1'b0}} : wr_addr_gr;
127  wr_addr_gr_rr <= rst ? {DEPTH_LOG2{1'b0}} : wr_addr_gr_r;
128 end
129 // read address -> wclk (wr) domain to compare
130 always @ (posedge wclk)
131 begin
132  rd_addr_gr_r <= rst ? {DEPTH_LOG2{1'b0}} : rd_addr_gr;
133  rd_addr_gr_rr <= rst ? {DEPTH_LOG2{1'b0}} : rd_addr_gr_r;
134 end
135 // translate resynced write address into ordinary (non-gray) address
136 genvar ii;
137 generate
138 for (ii = 0; ii <= HI; ii = ii + 1)
139 begin: wr_antigray
140  assign wr_addr_r[ii] = ^wr_addr_gr_rr[HI:ii];
141 end
142 endgenerate
143 // translate resynced read address into ordinary (non-gray) address
144 generate
145 for (ii = 0; ii <= HI; ii = ii + 1)
146 begin: rd_antigray
147  assign rd_addr_r[ii] = ^rd_addr_gr_rr[HI:ii];
148 end
149 endgenerate
150 // so we've got the following:
151 // wclk domain: wr_addr - current write address
152 // rd_addr_r - read address some wclk ticks ago
153 // => we can say if the fifo have the possibility to be full
154 // since actual rd_addr could only be incremented
155 //
156 // rclk domain: rd_addr - current read address
157 // wr_addr_r - write address some rclk ticks ago
158 // => we can say if the fifo have the possibility to be empty
159 // since actual wr_addr could only be incremented
160 assign full = wr_addr == rd_addr_r + 1'b1;
161 assign empty = wr_addr_r == rd_addr;
162 
163 always @ (posedge rclk)
164  outram <= ram[rd_addr];
165 
166 always @ (posedge wclk)
167  if (we)
168  ram[wr_addr] <= inram;
169 
170 // elactic part
171 // control fifo state @ rclk domain
172 // sends a pulse to wclk domain for every necessary ALIGNP removal
173 // waits for response from wclk domain of a successful removal
174 // pauses fifo read and inserts ALIGNP
175 
176 // @ rclk
177 // calculating an offset - a distance between write and read pointers
178 wire [HI:0] current_offset;
179 assign current_offset = wr_addr_r - rd_addr;
180 
181 // more records in fifo than expected on 1 primitive = 2 words = 2 records
183 // more records in fifo than expected on 2 primitives or more = 4 words + = 4 records +
185 // less records than expected - can insert a lot of alignes instantly, so exact count is not important
187 
188 // doesnt bother if offset is more on 1 word.
189 assign offset_more_on_1 = current_offset == (OFFSET + 2) | current_offset == (OFFSET + 3);
192 
193 `ifdef ENABLE_CHECKERS
194  always @ (posedge clk)
195  if (offset_less & (offset_more_on_1 | offset_more_on_1)) begin
196  $display("Error in %m. Wrong offset calculations");
197  $finish;
198  end
199 `endif
201 /*
202  Case when we need to get rid of extra elements in fifo
203  */
205 // control part @ rclk
212 wire set_rmv1_req;
213 wire set_rmv2_req;
214 wire set_wait_ack;
215 wire clr_rmv1_req;
216 wire clr_rmv2_req;
217 wire clr_wait_ack;
218 
220 
224 assign clr_rmv1_req = set_wait_ack;
225 assign clr_rmv2_req = set_wait_ack;
226 assign clr_wait_ack = rmv_ack_rclk;
227 
228 always @ (posedge rclk)
229 begin
233 end
234 
235 `ifdef ENABLE_CHECKERS
236  always @ (posedge rclk)
237  if (~rst)
238  if ((4'h0
239  + state_rmv1_req
240  + state_rmv2_req
241  + state_wait_ack
242  + state_idle_rmv
243  ) == 4'h1) begin
244  // all good
245  end
246  else
247  begin
248  $display("Error in %m: wrong fsm states: %b", {state_rmv1_req, state_rmv2_req, state_wait_ack, state_idle_rmv});
249  $finish;
250  end
251 `endif
252 
253 // align removal logic @ wclk
254 // we MUST compare current and next data pack even if the current one is a comma because
255 // the next data word could be either valid ALIGNP's or any other 2 bytes, which shall tell
256 // link layer that incorrect primitive has been received, so it can't be skipped
257 // also NO DISPARITY ERROR would be dropped
258 reg [22:0] indata_r;
259 always @ (posedge wclk)
262 // align is stored in a buffer right now
263 // ALIGNP = 7B4A4ABC
264 // charisk : 0 0 0 1
265 // notintbl: 0 0 0 0
266 // disperr: 0 0 0 0
268 assign align_det = {indata[15:0], indata_r[15:0]} == 32'h7B4A4ABC
269  & {indata[17:16], indata_r[17:16]} == 4'b0001
270  & {indata[19:18], indata_r[19:18]} == 4'b0000
271  & {indata[21:20], indata_r[21:20]} == 4'b0000;
273 // fsm
274 /*
275  bypass --req1--> wait for align --------------------------------------------------------> skip 1 primitive -> send ack -> bypass
276  \ | /\
277  req2--> wait for align -> skip 1 primitive -> wait until next ------align in buf--+ |
278  prim is in buffer --not align in buf------------------------------+
279  */
284 
291 reg state_send_ack;
292 wire set_wait1_align;
293 wire set_skip1_align;
294 wire set_wait2_align;
295 wire set_skip2_align;
296 wire set_wait_next_p;
297 wire set_send_ack;
298 wire clr_wait1_align;
299 wire clr_skip1_align;
300 wire clr_wait2_align;
301 wire clr_skip2_align;
302 wire clr_wait_next_p;
304 
305 always @ (posedge wclk)
307 
309 
315 assign set_send_ack = state_skip1_align | state_wait_next_p & next_prim_loaded & ~align_det; // 1 cycle skip - while set_skip1, 2nd cycle - while state_skip1
322 
323 always @ (posedge wclk)
324 begin
331 end
332 
334 assign inram = indata_r;
335 assign we = ~skip_write;
336 
337 // cross-domain messaging
339 // just to simplify an algorithm, we don't serialize a request to remove 2 ALIGNP,
340 // instead make 2 independent request lines
341 pulse_cross_clock remove1_req(
342  .rst (rst),
343  .src_clk (rclk),
344  .dst_clk (wclk),
347  .busy ()
348 );
349 pulse_cross_clock remove2_req(
350  .rst (rst),
351  .src_clk (rclk),
352  .dst_clk (wclk),
355  .busy ()
356 );
357 // removal request ack
358 pulse_cross_clock remove_ack(
359  .rst (rst),
360  .src_clk (wclk),
364  .busy ()
365 );
366 
367 // insert additional ALINGPs to head @ rclk
368 // 1 way to implement - search for align primitive at the head of fifo, and insert enough alignes right after detected one
369 // 2nd way - continiously send a pulse, indicating 1st word of each primitive.
370 // Choosing the 1st way
371 
372 // start algorithm after fifo gets in a stable state - let it fill to predefined offset count
373 reg fifo_stable;
374 always @ (posedge rclk)
377 // once again check if the current half-primitive is a part of an align
378 // no need to latch the whole outram
379 
380 // indicator, that @ previous clock cycle there was a first word of ALIGNP
382 always @ (posedge rclk)
383  align_1st <= outram[15:0] == 16'h4ABC
384  & outram[17:16] == 2'b01
385  & outram[19:18] == 2'b00
386  & outram[21:20] == 2'b00;
387 // indicates that current word is a second word of ALIGNP
388 wire align_2nd;
389 assign align_2nd = outram[15:0] == 16'h7B4A
390  & outram[17:16] == 2'b00
391  & outram[19:18] == 2'b00
392  & outram[21:20] == 2'b00;
393 // whole align primitive is the last thing we read from fifo
395 wire pause_read;
396 always @ (posedge rclk)
397  read_align <= rst ? 1'b0 : pause_read | align_1st & align_2nd;
398 
399 
400 // just to alternate alignp's words, = 0 => 1st word, = 1 => 2nd word
402 
403 // also pause when offset gets ok, but only 1st word of alignp is sent - need to send 2nd word
405 always @ (posedge rclk)
406  align_altern <= rst | ~pause_read ? 1'b0 : ~align_altern;
407 
408 // choose 1 of 2 words of ALIGNP
409 wire [22:0] align_word;
410 assign align_word = {outram[22], 22'h007B4A} & {23{align_altern}} | {outram[22], 22'h014ABC} & {23{~align_altern}};
411 
412 // output data would be valid the next clock they are issued
413 reg pause_read_r;
414 always @ (posedge rclk)
416 // read when compensation is not issued and when fifo gets required fullfillment
417 assign re = ~pause_read & fifo_stable;
418 assign outdata = {23{~pause_read_r}} & outram | {23{pause_read_r}} & align_word;
419 // indicates last cycle before the next primitive
421 reg fword_strobe;
422 `ifdef SIMULATION
423 assign fword_strobe_correction = (align_1st === 1'bx || align_2nd === 1'bx) ? 1'b0 : align_1st & align_2nd ;
424 `else
426 `endif
427 always @ (posedge rclk)
429 
430 assign lword_strobe = ~fword_strobe;
431 
432 endmodule
433 
14853clr_skip1_alignwire
Definition: gtx_elastic.v:279
14864align_wordwire[22:0]
Definition: gtx_elastic.v:389
14820offset_more_on_2wire
Definition: gtx_elastic.v:184
14819offset_more_on_1wire
Definition: gtx_elastic.v:182
remove_ack pulse_cross_clock
Definition: gtx_elastic.v:338
wire [15:0] 14794data_out
Definition: gtx_elastic.v:58
14806wr_next_addrwire[HI:0]
Definition: gtx_elastic.v:90
14809wr_addr_grreg[HI:0]
Definition: gtx_elastic.v:94
wire 14784rclk
Definition: gtx_elastic.v:46
14865pause_read_rreg
Definition: gtx_elastic.v:393
wire [1:0] 14793disperror_out
Definition: gtx_elastic.v:57
wire [1:0] 14786charisk_in
Definition: gtx_elastic.v:49
14828set_rmv2_reqwire
Definition: gtx_elastic.v:207
14837rmv2_req_wclkwire
Definition: gtx_elastic.v:262
wire 14785isaligned_in
Definition: gtx_elastic.v:48
wire 14782rst
Definition: gtx_elastic.v:44
14843state_skip2_alignreg
Definition: gtx_elastic.v:269
14849set_skip2_alignwire
Definition: gtx_elastic.v:275
14832clr_wait_ackwire
Definition: gtx_elastic.v:211
14854clr_wait2_alignwire
Definition: gtx_elastic.v:280
14827set_rmv1_reqwire
Definition: gtx_elastic.v:206
14860align_2ndwire
Definition: gtx_elastic.v:368
14829set_wait_ackwire
Definition: gtx_elastic.v:208
14857clr_send_ackwire
Definition: gtx_elastic.v:283
14839state_bypass_rmvwire
Definition: gtx_elastic.v:265
14862pause_readwire
Definition: gtx_elastic.v:375
14804rd_addrreg[HI:0]
Definition: gtx_elastic.v:87
wire [1:0] 14792notintable_out
Definition: gtx_elastic.v:56
wire 14797empty
Definition: gtx_elastic.v:65
14821offset_lesswire
Definition: gtx_elastic.v:186
14850set_wait_next_pwire
Definition: gtx_elastic.v:276
14800HIDEPTH_LOG2 - 1
Definition: gtx_elastic.v:77
14831clr_rmv2_reqwire
Definition: gtx_elastic.v:210
14803outramreg[22:0]
Definition: gtx_elastic.v:85
14822rmv_ack_rclkwire
Definition: gtx_elastic.v:200
14856clr_wait_next_pwire
Definition: gtx_elastic.v:282
14844state_wait_next_preg
Definition: gtx_elastic.v:270
14799outdatawire[22:0]
Definition: gtx_elastic.v:69
wire 14795lword_strobe
Definition: gtx_elastic.v:61
14830clr_rmv1_reqwire
Definition: gtx_elastic.v:209
wire [1:0] 14788disperror_in
Definition: gtx_elastic.v:51
14802inramwire[22:0]
Definition: gtx_elastic.v:84
14798indatawire[22:0]
Definition: gtx_elastic.v:68
14841state_skip1_alignreg
Definition: gtx_elastic.v:267
14814rd_addr_rwire[HI:0]
Definition: gtx_elastic.v:101
14838next_prim_loadedreg
Definition: gtx_elastic.v:263
14823state_idle_rmvwire
Definition: gtx_elastic.v:202
14847set_skip1_alignwire
Definition: gtx_elastic.v:273
14833indata_rreg[22:0]
Definition: gtx_elastic.v:238
wire [15:0] 14789data_in
Definition: gtx_elastic.v:52
14836rmv1_req_wclkwire
Definition: gtx_elastic.v:261
wire 14796full
Definition: gtx_elastic.v:64
14813wr_addr_gr_rrreg[HI:0]
Definition: gtx_elastic.v:99
14826state_wait_ackreg
Definition: gtx_elastic.v:205
14815wr_addr_rwire[HI:0]
Definition: gtx_elastic.v:102
14855clr_skip2_alignwire
Definition: gtx_elastic.v:281
14842state_wait2_alignreg
Definition: gtx_elastic.v:268
14834align_detwire
Definition: gtx_elastic.v:247
wire [1:0] 14791charisk_out
Definition: gtx_elastic.v:55
14851set_send_ackwire
Definition: gtx_elastic.v:277
14861read_alignreg
Definition: gtx_elastic.v:374
14858fifo_stablereg
Definition: gtx_elastic.v:353
14825state_rmv2_reqreg
Definition: gtx_elastic.v:204
wire 14790isaligned_out
Definition: gtx_elastic.v:54
14859align_1streg
Definition: gtx_elastic.v:361
wire [1:0] 14787notintable_in
Definition: gtx_elastic.v:50
14840state_wait1_alignreg
Definition: gtx_elastic.v:266
14863align_alternreg
Definition: gtx_elastic.v:381
14818current_offset[HI:0]
Definition: gtx_elastic.v:178
14824state_rmv1_reqreg
Definition: gtx_elastic.v:203
14845state_send_ackreg
Definition: gtx_elastic.v:271
14867fword_strobereg
Definition: gtx_elastic.v:401
wire 14783wclk
Definition: gtx_elastic.v:45
[1<<DEPTH_LOG2-1:0] 14801ramreg[22:0]
Definition: gtx_elastic.v:82
14812rd_addr_gr_rrreg[HI:0]
Definition: gtx_elastic.v:98
14805wr_addrreg[HI:0]
Definition: gtx_elastic.v:88
14852clr_wait1_alignwire
Definition: gtx_elastic.v:278
14808rd_addr_grreg[HI:0]
Definition: gtx_elastic.v:93
14835skip_writewire
Definition: gtx_elastic.v:260
14848set_wait2_alignwire
Definition: gtx_elastic.v:274
14811wr_addr_gr_rreg[HI:0]
Definition: gtx_elastic.v:97
14807rd_next_addrwire[HI:0]
Definition: gtx_elastic.v:91
14810rd_addr_gr_rreg[HI:0]
Definition: gtx_elastic.v:96
14846set_wait1_alignwire
Definition: gtx_elastic.v:272
14866fword_strobe_correctionwire
Definition: gtx_elastic.v:400