altera_avalon_sc_fifo.v 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. // -----------------------------------------------------------
  2. // Legal Notice: (C)2007 Altera Corporation. All rights reserved. Your
  3. // use of Altera Corporation's design tools, logic functions and other
  4. // software and tools, and its AMPP partner logic functions, and any
  5. // output files any of the foregoing (including device programming or
  6. // simulation files), and any associated documentation or information are
  7. // expressly subject to the terms and conditions of the Altera Program
  8. // License Subscription Agreement or other applicable license agreement,
  9. // including, without limitation, that your use is for the sole purpose
  10. // of programming logic devices manufactured by Altera and sold by Altera
  11. // or its authorized distributors. Please refer to the applicable
  12. // agreement for further details.
  13. //
  14. // Description: Single clock Avalon-ST FIFO.
  15. // -----------------------------------------------------------
  16. `timescale 1 ns / 1 ns
  17. //altera message_off 10036
  18. module altera_avalon_sc_fifo
  19. #(
  20. // --------------------------------------------------
  21. // Parameters
  22. // --------------------------------------------------
  23. parameter SYMBOLS_PER_BEAT = 1,
  24. parameter BITS_PER_SYMBOL = 8,
  25. parameter FIFO_DEPTH = 16,
  26. parameter CHANNEL_WIDTH = 0,
  27. parameter ERROR_WIDTH = 0,
  28. parameter USE_PACKETS = 0,
  29. parameter USE_FILL_LEVEL = 0,
  30. parameter USE_STORE_FORWARD = 0,
  31. parameter USE_ALMOST_FULL_IF = 0,
  32. parameter USE_ALMOST_EMPTY_IF = 0,
  33. // --------------------------------------------------
  34. // Empty latency is defined as the number of cycles
  35. // required for a write to deassert the empty flag.
  36. // For example, a latency of 1 means that the empty
  37. // flag is deasserted on the cycle after a write.
  38. //
  39. // Another way to think of it is the latency for a
  40. // write to propagate to the output.
  41. //
  42. // An empty latency of 0 implies lookahead, which is
  43. // only implemented for the register-based FIFO.
  44. // --------------------------------------------------
  45. parameter EMPTY_LATENCY = 3,
  46. parameter USE_MEMORY_BLOCKS = 1,
  47. // --------------------------------------------------
  48. // Internal Parameters
  49. // --------------------------------------------------
  50. parameter DATA_WIDTH = SYMBOLS_PER_BEAT * BITS_PER_SYMBOL,
  51. parameter EMPTY_WIDTH = log2ceil(SYMBOLS_PER_BEAT)
  52. )
  53. (
  54. // --------------------------------------------------
  55. // Ports
  56. // --------------------------------------------------
  57. input clk,
  58. input reset,
  59. input [DATA_WIDTH-1: 0] in_data,
  60. input in_valid,
  61. input in_startofpacket,
  62. input in_endofpacket,
  63. input [((EMPTY_WIDTH>0) ? (EMPTY_WIDTH-1):0) : 0] in_empty,
  64. input [((ERROR_WIDTH>0) ? (ERROR_WIDTH-1):0) : 0] in_error,
  65. input [((CHANNEL_WIDTH>0) ? (CHANNEL_WIDTH-1):0): 0] in_channel,
  66. output in_ready,
  67. output [DATA_WIDTH-1 : 0] out_data,
  68. output reg out_valid,
  69. output out_startofpacket,
  70. output out_endofpacket,
  71. output [((EMPTY_WIDTH>0) ? (EMPTY_WIDTH-1):0) : 0] out_empty,
  72. output [((ERROR_WIDTH>0) ? (ERROR_WIDTH-1):0) : 0] out_error,
  73. output [((CHANNEL_WIDTH>0) ? (CHANNEL_WIDTH-1):0): 0] out_channel,
  74. input out_ready,
  75. input [(USE_STORE_FORWARD ? 2 : 1) : 0] csr_address,
  76. input csr_write,
  77. input csr_read,
  78. input [31 : 0] csr_writedata,
  79. output reg [31 : 0] csr_readdata,
  80. output wire almost_full_data,
  81. output wire almost_empty_data
  82. );
  83. // --------------------------------------------------
  84. // Local Parameters
  85. // --------------------------------------------------
  86. localparam ADDR_WIDTH = log2ceil(FIFO_DEPTH);
  87. localparam DEPTH = FIFO_DEPTH;
  88. localparam PKT_SIGNALS_WIDTH = 2 + EMPTY_WIDTH;
  89. localparam PAYLOAD_WIDTH = (USE_PACKETS == 1) ?
  90. 2 + EMPTY_WIDTH + DATA_WIDTH + ERROR_WIDTH + CHANNEL_WIDTH:
  91. DATA_WIDTH + ERROR_WIDTH + CHANNEL_WIDTH;
  92. // --------------------------------------------------
  93. // Internal Signals
  94. // --------------------------------------------------
  95. genvar i;
  96. reg [PAYLOAD_WIDTH-1 : 0] mem [DEPTH-1 : 0];
  97. reg [ADDR_WIDTH-1 : 0] wr_ptr;
  98. reg [ADDR_WIDTH-1 : 0] rd_ptr;
  99. reg [DEPTH-1 : 0] mem_used;
  100. wire [ADDR_WIDTH-1 : 0] next_wr_ptr;
  101. wire [ADDR_WIDTH-1 : 0] next_rd_ptr;
  102. wire [ADDR_WIDTH-1 : 0] incremented_wr_ptr;
  103. wire [ADDR_WIDTH-1 : 0] incremented_rd_ptr;
  104. wire [ADDR_WIDTH-1 : 0] mem_rd_ptr;
  105. wire read;
  106. wire write;
  107. reg empty;
  108. reg next_empty;
  109. reg full;
  110. reg next_full;
  111. wire [PKT_SIGNALS_WIDTH-1 : 0] in_packet_signals;
  112. wire [PKT_SIGNALS_WIDTH-1 : 0] out_packet_signals;
  113. wire [PAYLOAD_WIDTH-1 : 0] in_payload;
  114. reg [PAYLOAD_WIDTH-1 : 0] internal_out_payload;
  115. reg [PAYLOAD_WIDTH-1 : 0] out_payload;
  116. reg internal_out_valid;
  117. wire internal_out_ready;
  118. reg [ADDR_WIDTH : 0] fifo_fill_level;
  119. reg [ADDR_WIDTH : 0] fill_level;
  120. reg [ADDR_WIDTH-1 : 0] sop_ptr = 0;
  121. wire [ADDR_WIDTH-1 : 0] curr_sop_ptr;
  122. reg [23:0] almost_full_threshold;
  123. reg [23:0] almost_empty_threshold;
  124. reg [23:0] cut_through_threshold;
  125. reg [15:0] pkt_cnt;
  126. reg drop_on_error_en;
  127. reg error_in_pkt;
  128. reg pkt_has_started;
  129. reg sop_has_left_fifo;
  130. reg fifo_too_small_r;
  131. reg pkt_cnt_eq_zero;
  132. reg pkt_cnt_eq_one;
  133. wire wait_for_threshold;
  134. reg pkt_mode;
  135. wire wait_for_pkt;
  136. wire ok_to_forward;
  137. wire in_pkt_eop_arrive;
  138. wire out_pkt_leave;
  139. wire in_pkt_start;
  140. wire in_pkt_error;
  141. wire drop_on_error;
  142. wire fifo_too_small;
  143. wire out_pkt_sop_leave;
  144. wire [31:0] max_fifo_size;
  145. reg fifo_fill_level_lt_cut_through_threshold;
  146. // --------------------------------------------------
  147. // Define Payload
  148. //
  149. // Icky part where we decide which signals form the
  150. // payload to the FIFO with generate blocks.
  151. // --------------------------------------------------
  152. generate
  153. if (EMPTY_WIDTH > 0) begin : gen_blk1
  154. assign in_packet_signals = {in_startofpacket, in_endofpacket, in_empty};
  155. assign {out_startofpacket, out_endofpacket, out_empty} = out_packet_signals;
  156. end
  157. else begin : gen_blk1_else
  158. assign out_empty = in_error;
  159. assign in_packet_signals = {in_startofpacket, in_endofpacket};
  160. assign {out_startofpacket, out_endofpacket} = out_packet_signals;
  161. end
  162. endgenerate
  163. generate
  164. if (USE_PACKETS) begin : gen_blk2
  165. if (ERROR_WIDTH > 0) begin : gen_blk3
  166. if (CHANNEL_WIDTH > 0) begin : gen_blk4
  167. assign in_payload = {in_packet_signals, in_data, in_error, in_channel};
  168. assign {out_packet_signals, out_data, out_error, out_channel} = out_payload;
  169. end
  170. else begin : gen_blk4_else
  171. assign out_channel = in_channel;
  172. assign in_payload = {in_packet_signals, in_data, in_error};
  173. assign {out_packet_signals, out_data, out_error} = out_payload;
  174. end
  175. end
  176. else begin : gen_blk3_else
  177. assign out_error = in_error;
  178. if (CHANNEL_WIDTH > 0) begin : gen_blk5
  179. assign in_payload = {in_packet_signals, in_data, in_channel};
  180. assign {out_packet_signals, out_data, out_channel} = out_payload;
  181. end
  182. else begin : gen_blk5_else
  183. assign out_channel = in_channel;
  184. assign in_payload = {in_packet_signals, in_data};
  185. assign {out_packet_signals, out_data} = out_payload;
  186. end
  187. end
  188. end
  189. else begin : gen_blk2_else
  190. assign out_packet_signals = 0;
  191. if (ERROR_WIDTH > 0) begin : gen_blk6
  192. if (CHANNEL_WIDTH > 0) begin : gen_blk7
  193. assign in_payload = {in_data, in_error, in_channel};
  194. assign {out_data, out_error, out_channel} = out_payload;
  195. end
  196. else begin : gen_blk7_else
  197. assign out_channel = in_channel;
  198. assign in_payload = {in_data, in_error};
  199. assign {out_data, out_error} = out_payload;
  200. end
  201. end
  202. else begin : gen_blk6_else
  203. assign out_error = in_error;
  204. if (CHANNEL_WIDTH > 0) begin : gen_blk8
  205. assign in_payload = {in_data, in_channel};
  206. assign {out_data, out_channel} = out_payload;
  207. end
  208. else begin : gen_blk8_else
  209. assign out_channel = in_channel;
  210. assign in_payload = in_data;
  211. assign out_data = out_payload;
  212. end
  213. end
  214. end
  215. endgenerate
  216. // --------------------------------------------------
  217. // Memory-based FIFO storage
  218. //
  219. // To allow a ready latency of 0, the read index is
  220. // obtained from the next read pointer and memory
  221. // outputs are unregistered.
  222. //
  223. // If the empty latency is 1, we infer bypass logic
  224. // around the memory so writes propagate to the
  225. // outputs on the next cycle.
  226. //
  227. // Do not change the way this is coded: Quartus needs
  228. // a perfect match to the template, and any attempt to
  229. // refactor the two always blocks into one will break
  230. // memory inference.
  231. // --------------------------------------------------
  232. generate if (USE_MEMORY_BLOCKS == 1) begin : gen_blk9
  233. if (EMPTY_LATENCY == 1) begin : gen_blk10
  234. always @(posedge clk) begin
  235. if (in_valid && in_ready)
  236. mem[wr_ptr] = in_payload;
  237. internal_out_payload = mem[mem_rd_ptr];
  238. end
  239. end else begin : gen_blk10_else
  240. always @(posedge clk) begin
  241. if (in_valid && in_ready)
  242. mem[wr_ptr] <= in_payload;
  243. internal_out_payload <= mem[mem_rd_ptr];
  244. end
  245. end
  246. assign mem_rd_ptr = next_rd_ptr;
  247. end else begin : gen_blk9_else
  248. // --------------------------------------------------
  249. // Register-based FIFO storage
  250. //
  251. // Uses a shift register as the storage element. Each
  252. // shift register slot has a bit which indicates if
  253. // the slot is occupied (credit to Sam H for the idea).
  254. // The occupancy bits are contiguous and start from the
  255. // lsb, so 0000, 0001, 0011, 0111, 1111 for a 4-deep
  256. // FIFO.
  257. //
  258. // Each slot is enabled during a read or when it
  259. // is unoccupied. New data is always written to every
  260. // going-to-be-empty slot (we keep track of which ones
  261. // are actually useful with the occupancy bits). On a
  262. // read we shift occupied slots.
  263. //
  264. // The exception is the last slot, which always gets
  265. // new data when it is unoccupied.
  266. // --------------------------------------------------
  267. for (i = 0; i < DEPTH-1; i = i + 1) begin : shift_reg
  268. always @(posedge clk or posedge reset) begin
  269. if (reset) begin
  270. mem[i] <= 0;
  271. end
  272. else if (read || !mem_used[i]) begin
  273. if (!mem_used[i+1])
  274. mem[i] <= in_payload;
  275. else
  276. mem[i] <= mem[i+1];
  277. end
  278. end
  279. end
  280. always @(posedge clk, posedge reset) begin
  281. if (reset) begin
  282. mem[DEPTH-1] <= 0;
  283. end
  284. else begin
  285. if (DEPTH == 1) begin
  286. if (write)
  287. mem[DEPTH-1] <= in_payload;
  288. end
  289. else if (!mem_used[DEPTH-1])
  290. mem[DEPTH-1] <= in_payload;
  291. end
  292. end
  293. end
  294. endgenerate
  295. assign read = internal_out_ready && internal_out_valid && ok_to_forward;
  296. assign write = in_ready && in_valid;
  297. // --------------------------------------------------
  298. // Pointer Management
  299. // --------------------------------------------------
  300. generate if (USE_MEMORY_BLOCKS == 1) begin : gen_blk11
  301. assign incremented_wr_ptr = wr_ptr + 1'b1;
  302. assign incremented_rd_ptr = rd_ptr + 1'b1;
  303. assign next_wr_ptr = drop_on_error ? curr_sop_ptr : write ? incremented_wr_ptr : wr_ptr;
  304. assign next_rd_ptr = (read) ? incremented_rd_ptr : rd_ptr;
  305. always @(posedge clk or posedge reset) begin
  306. if (reset) begin
  307. wr_ptr <= 0;
  308. rd_ptr <= 0;
  309. end
  310. else begin
  311. wr_ptr <= next_wr_ptr;
  312. rd_ptr <= next_rd_ptr;
  313. end
  314. end
  315. end else begin : gen_blk11_else
  316. // --------------------------------------------------
  317. // Shift Register Occupancy Bits
  318. //
  319. // Consider a 4-deep FIFO with 2 entries: 0011
  320. // On a read and write, do not modify the bits.
  321. // On a write, left-shift the bits to get 0111.
  322. // On a read, right-shift the bits to get 0001.
  323. //
  324. // Also, on a write we set bit0 (the head), while
  325. // clearing the tail on a read.
  326. // --------------------------------------------------
  327. always @(posedge clk or posedge reset) begin
  328. if (reset) begin
  329. mem_used[0] <= 0;
  330. end
  331. else begin
  332. if (write ^ read) begin
  333. if (write)
  334. mem_used[0] <= 1;
  335. else if (read) begin
  336. if (DEPTH > 1)
  337. mem_used[0] <= mem_used[1];
  338. else
  339. mem_used[0] <= 0;
  340. end
  341. end
  342. end
  343. end
  344. if (DEPTH > 1) begin : gen_blk12
  345. always @(posedge clk or posedge reset) begin
  346. if (reset) begin
  347. mem_used[DEPTH-1] <= 0;
  348. end
  349. else begin
  350. if (write ^ read) begin
  351. mem_used[DEPTH-1] <= 0;
  352. if (write)
  353. mem_used[DEPTH-1] <= mem_used[DEPTH-2];
  354. end
  355. end
  356. end
  357. end
  358. for (i = 1; i < DEPTH-1; i = i + 1) begin : storage_logic
  359. always @(posedge clk, posedge reset) begin
  360. if (reset) begin
  361. mem_used[i] <= 0;
  362. end
  363. else begin
  364. if (write ^ read) begin
  365. if (write)
  366. mem_used[i] <= mem_used[i-1];
  367. else if (read)
  368. mem_used[i] <= mem_used[i+1];
  369. end
  370. end
  371. end
  372. end
  373. end
  374. endgenerate
  375. // --------------------------------------------------
  376. // Memory FIFO Status Management
  377. //
  378. // Generates the full and empty signals from the
  379. // pointers. The FIFO is full when the next write
  380. // pointer will be equal to the read pointer after
  381. // a write. Reading from a FIFO clears full.
  382. //
  383. // The FIFO is empty when the next read pointer will
  384. // be equal to the write pointer after a read. Writing
  385. // to a FIFO clears empty.
  386. //
  387. // A simultaneous read and write must not change any of
  388. // the empty or full flags unless there is a drop on error event.
  389. // --------------------------------------------------
  390. generate if (USE_MEMORY_BLOCKS == 1) begin : gen_blk13
  391. always @* begin
  392. next_full = full;
  393. next_empty = empty;
  394. if (read && !write) begin
  395. next_full = 1'b0;
  396. if (incremented_rd_ptr == wr_ptr)
  397. next_empty = 1'b1;
  398. end
  399. if (write && !read) begin
  400. if (!drop_on_error)
  401. next_empty = 1'b0;
  402. else if (curr_sop_ptr == rd_ptr) // drop on error and only 1 pkt in fifo
  403. next_empty = 1'b1;
  404. if (incremented_wr_ptr == rd_ptr && !drop_on_error)
  405. next_full = 1'b1;
  406. end
  407. if (write && read && drop_on_error) begin
  408. if (curr_sop_ptr == next_rd_ptr)
  409. next_empty = 1'b1;
  410. end
  411. end
  412. always @(posedge clk or posedge reset) begin
  413. if (reset) begin
  414. empty <= 1;
  415. full <= 0;
  416. end
  417. else begin
  418. empty <= next_empty;
  419. full <= next_full;
  420. end
  421. end
  422. end else begin : gen_blk13_else
  423. // --------------------------------------------------
  424. // Register FIFO Status Management
  425. //
  426. // Full when the tail occupancy bit is 1. Empty when
  427. // the head occupancy bit is 0.
  428. // --------------------------------------------------
  429. always @* begin
  430. full = mem_used[DEPTH-1];
  431. empty = !mem_used[0];
  432. // ------------------------------------------
  433. // For a single slot FIFO, reading clears the
  434. // full status immediately.
  435. // ------------------------------------------
  436. if (DEPTH == 1)
  437. full = mem_used[0] && !read;
  438. internal_out_payload = mem[0];
  439. // ------------------------------------------
  440. // Writes clear empty immediately for lookahead modes.
  441. // Note that we use in_valid instead of write to avoid
  442. // combinational loops (in lookahead mode, qualifying
  443. // with in_ready is meaningless).
  444. //
  445. // In a 1-deep FIFO, a possible combinational loop runs
  446. // from write -> out_valid -> out_ready -> write
  447. // ------------------------------------------
  448. if (EMPTY_LATENCY == 0) begin
  449. empty = !mem_used[0] && !in_valid;
  450. if (!mem_used[0] && in_valid)
  451. internal_out_payload = in_payload;
  452. end
  453. end
  454. end
  455. endgenerate
  456. // --------------------------------------------------
  457. // Avalon-ST Signals
  458. //
  459. // The in_ready signal is straightforward.
  460. //
  461. // To match memory latency when empty latency > 1,
  462. // out_valid assertions must be delayed by one clock
  463. // cycle.
  464. //
  465. // Note: out_valid deassertions must not be delayed or
  466. // the FIFO will underflow.
  467. // --------------------------------------------------
  468. assign in_ready = !full;
  469. assign internal_out_ready = out_ready || !out_valid;
  470. generate if (EMPTY_LATENCY > 1) begin : gen_blk14
  471. always @(posedge clk or posedge reset) begin
  472. if (reset)
  473. internal_out_valid <= 0;
  474. else begin
  475. internal_out_valid <= !empty & ok_to_forward & ~drop_on_error;
  476. if (read) begin
  477. if (incremented_rd_ptr == wr_ptr)
  478. internal_out_valid <= 1'b0;
  479. end
  480. end
  481. end
  482. end else begin : gen_blk14_else
  483. always @* begin
  484. internal_out_valid = !empty & ok_to_forward;
  485. end
  486. end
  487. endgenerate
  488. // --------------------------------------------------
  489. // Single Output Pipeline Stage
  490. //
  491. // This output pipeline stage is enabled if the FIFO's
  492. // empty latency is set to 3 (default). It is disabled
  493. // for all other allowed latencies.
  494. //
  495. // Reason: The memory outputs are unregistered, so we have to
  496. // register the output or fmax will drop if combinatorial
  497. // logic is present on the output datapath.
  498. //
  499. // Q: The Avalon-ST spec says that I have to register my outputs
  500. // But isn't the memory counted as a register?
  501. // A: The path from the address lookup to the memory output is
  502. // slow. Registering the memory outputs is a good idea.
  503. //
  504. // The registers get packed into the memory by the fitter
  505. // which means minimal resources are consumed (the result
  506. // is a altsyncram with registered outputs, available on
  507. // all modern Altera devices).
  508. //
  509. // This output stage acts as an extra slot in the FIFO,
  510. // and complicates the fill level.
  511. // --------------------------------------------------
  512. generate if (EMPTY_LATENCY == 3) begin : gen_blk15
  513. always @(posedge clk or posedge reset) begin
  514. if (reset) begin
  515. out_valid <= 0;
  516. out_payload <= 0;
  517. end
  518. else begin
  519. if (internal_out_ready) begin
  520. out_valid <= internal_out_valid & ok_to_forward;
  521. out_payload <= internal_out_payload;
  522. end
  523. end
  524. end
  525. end
  526. else begin : gen_blk15_else
  527. always @* begin
  528. out_valid = internal_out_valid;
  529. out_payload = internal_out_payload;
  530. end
  531. end
  532. endgenerate
  533. // --------------------------------------------------
  534. // Fill Level
  535. //
  536. // The fill level is calculated from the next write
  537. // and read pointers to avoid unnecessary latency
  538. // and logic.
  539. //
  540. // However, if the store-and-forward mode of the FIFO
  541. // is enabled, the fill level is an up-down counter
  542. // for fmax optimization reasons.
  543. //
  544. // If the output pipeline is enabled, the fill level
  545. // must account for it, or we'll always be off by one.
  546. // This may, or may not be important depending on the
  547. // application.
  548. //
  549. // For now, we'll always calculate the exact fill level
  550. // at the cost of an extra adder when the output stage
  551. // is enabled.
  552. // --------------------------------------------------
  553. generate if (USE_FILL_LEVEL) begin : gen_blk16
  554. wire [31:0] depth32;
  555. assign depth32 = DEPTH;
  556. if (USE_STORE_FORWARD) begin
  557. reg [ADDR_WIDTH : 0] curr_packet_len_less_one;
  558. // --------------------------------------------------
  559. // We only drop on endofpacket. As long as we don't add to the fill
  560. // level on the dropped endofpacket cycle, we can simply subtract
  561. // (packet length - 1) from the fill level for dropped packets.
  562. // --------------------------------------------------
  563. always @(posedge clk or posedge reset) begin
  564. if (reset) begin
  565. curr_packet_len_less_one <= 0;
  566. end else begin
  567. if (write) begin
  568. curr_packet_len_less_one <= curr_packet_len_less_one + 1'b1;
  569. if (in_endofpacket)
  570. curr_packet_len_less_one <= 0;
  571. end
  572. end
  573. end
  574. always @(posedge clk or posedge reset) begin
  575. if (reset) begin
  576. fifo_fill_level <= 0;
  577. end else if (drop_on_error) begin
  578. fifo_fill_level <= fifo_fill_level - curr_packet_len_less_one;
  579. if (read)
  580. fifo_fill_level <= fifo_fill_level - curr_packet_len_less_one - 1'b1;
  581. end else if (write && !read) begin
  582. fifo_fill_level <= fifo_fill_level + 1'b1;
  583. end else if (read && !write) begin
  584. fifo_fill_level <= fifo_fill_level - 1'b1;
  585. end
  586. end
  587. end else begin
  588. always @(posedge clk or posedge reset) begin
  589. if (reset)
  590. fifo_fill_level <= 0;
  591. else if (next_full & !drop_on_error)
  592. fifo_fill_level <= depth32[ADDR_WIDTH:0];
  593. else begin
  594. fifo_fill_level[ADDR_WIDTH] <= 1'b0;
  595. fifo_fill_level[ADDR_WIDTH-1 : 0] <= next_wr_ptr - next_rd_ptr;
  596. end
  597. end
  598. end
  599. always @* begin
  600. fill_level = fifo_fill_level;
  601. if (EMPTY_LATENCY == 3)
  602. fill_level = fifo_fill_level + {{ADDR_WIDTH{1'b0}}, out_valid};
  603. end
  604. end
  605. else begin : gen_blk16_else
  606. always @* begin
  607. fill_level = 0;
  608. end
  609. end
  610. endgenerate
  611. generate if (USE_ALMOST_FULL_IF) begin : gen_blk17
  612. assign almost_full_data = (fill_level >= almost_full_threshold);
  613. end
  614. else
  615. assign almost_full_data = 0;
  616. endgenerate
  617. generate if (USE_ALMOST_EMPTY_IF) begin : gen_blk18
  618. assign almost_empty_data = (fill_level <= almost_empty_threshold);
  619. end
  620. else
  621. assign almost_empty_data = 0;
  622. endgenerate
  623. // --------------------------------------------------
  624. // Avalon-MM Status & Control Connection Point
  625. //
  626. // Register map:
  627. //
  628. // | Addr | RW | 31 - 0 |
  629. // | 0 | R | Fill level |
  630. //
  631. // The registering of this connection point means
  632. // that there is a cycle of latency between
  633. // reads/writes and the updating of the fill level.
  634. // --------------------------------------------------
  635. generate if (USE_STORE_FORWARD) begin : gen_blk19
  636. assign max_fifo_size = FIFO_DEPTH - 1;
  637. always @(posedge clk or posedge reset) begin
  638. if (reset) begin
  639. almost_full_threshold <= max_fifo_size[23 : 0];
  640. almost_empty_threshold <= 0;
  641. cut_through_threshold <= 0;
  642. drop_on_error_en <= 0;
  643. csr_readdata <= 0;
  644. pkt_mode <= 1'b1;
  645. end
  646. else begin
  647. if (csr_read) begin
  648. csr_readdata <= 32'b0;
  649. if (csr_address == 5)
  650. csr_readdata <= {31'b0, drop_on_error_en};
  651. else if (csr_address == 4)
  652. csr_readdata <= {8'b0, cut_through_threshold};
  653. else if (csr_address == 3)
  654. csr_readdata <= {8'b0, almost_empty_threshold};
  655. else if (csr_address == 2)
  656. csr_readdata <= {8'b0, almost_full_threshold};
  657. else if (csr_address == 0)
  658. csr_readdata <= {{(31 - ADDR_WIDTH){1'b0}}, fill_level};
  659. end
  660. else if (csr_write) begin
  661. if(csr_address == 3'b101)
  662. drop_on_error_en <= csr_writedata[0];
  663. else if(csr_address == 3'b100) begin
  664. cut_through_threshold <= csr_writedata[23:0];
  665. pkt_mode <= (csr_writedata[23:0] == 0);
  666. end
  667. else if(csr_address == 3'b011)
  668. almost_empty_threshold <= csr_writedata[23:0];
  669. else if(csr_address == 3'b010)
  670. almost_full_threshold <= csr_writedata[23:0];
  671. end
  672. end
  673. end
  674. end
  675. else if (USE_ALMOST_FULL_IF || USE_ALMOST_EMPTY_IF) begin : gen_blk19_else1
  676. assign max_fifo_size = FIFO_DEPTH - 1;
  677. always @(posedge clk or posedge reset) begin
  678. if (reset) begin
  679. almost_full_threshold <= max_fifo_size[23 : 0];
  680. almost_empty_threshold <= 0;
  681. csr_readdata <= 0;
  682. end
  683. else begin
  684. if (csr_read) begin
  685. csr_readdata <= 32'b0;
  686. if (csr_address == 3)
  687. csr_readdata <= {8'b0, almost_empty_threshold};
  688. else if (csr_address == 2)
  689. csr_readdata <= {8'b0, almost_full_threshold};
  690. else if (csr_address == 0)
  691. csr_readdata <= {{(31 - ADDR_WIDTH){1'b0}}, fill_level};
  692. end
  693. else if (csr_write) begin
  694. if(csr_address == 3'b011)
  695. almost_empty_threshold <= csr_writedata[23:0];
  696. else if(csr_address == 3'b010)
  697. almost_full_threshold <= csr_writedata[23:0];
  698. end
  699. end
  700. end
  701. end
  702. else begin : gen_blk19_else2
  703. always @(posedge clk or posedge reset) begin
  704. if (reset) begin
  705. csr_readdata <= 0;
  706. end
  707. else if (csr_read) begin
  708. csr_readdata <= 0;
  709. if (csr_address == 0)
  710. csr_readdata <= {{(31 - ADDR_WIDTH){1'b0}}, fill_level};
  711. end
  712. end
  713. end
  714. endgenerate
  715. // --------------------------------------------------
  716. // Store and forward logic
  717. // --------------------------------------------------
  718. // if the fifo gets full before the entire packet or the
  719. // cut-threshold condition is met then start sending out
  720. // data in order to avoid dead-lock situation
  721. generate if (USE_STORE_FORWARD) begin : gen_blk20
  722. assign wait_for_threshold = (fifo_fill_level_lt_cut_through_threshold) & wait_for_pkt ;
  723. assign wait_for_pkt = pkt_cnt_eq_zero | (pkt_cnt_eq_one & out_pkt_leave);
  724. assign ok_to_forward = (pkt_mode ? (~wait_for_pkt | ~pkt_has_started) :
  725. ~wait_for_threshold) | fifo_too_small_r;
  726. assign in_pkt_eop_arrive = in_valid & in_ready & in_endofpacket;
  727. assign in_pkt_start = in_valid & in_ready & in_startofpacket;
  728. assign in_pkt_error = in_valid & in_ready & |in_error;
  729. assign out_pkt_sop_leave = out_valid & out_ready & out_startofpacket;
  730. assign out_pkt_leave = out_valid & out_ready & out_endofpacket;
  731. assign fifo_too_small = (pkt_mode ? wait_for_pkt : wait_for_threshold) & full & out_ready;
  732. // count packets coming and going into the fifo
  733. always @(posedge clk or posedge reset) begin
  734. if (reset) begin
  735. pkt_cnt <= 0;
  736. pkt_has_started <= 0;
  737. sop_has_left_fifo <= 0;
  738. fifo_too_small_r <= 0;
  739. pkt_cnt_eq_zero <= 1'b1;
  740. pkt_cnt_eq_one <= 1'b0;
  741. fifo_fill_level_lt_cut_through_threshold <= 1'b1;
  742. end
  743. else begin
  744. fifo_fill_level_lt_cut_through_threshold <= fifo_fill_level < cut_through_threshold;
  745. fifo_too_small_r <= fifo_too_small;
  746. if( in_pkt_eop_arrive )
  747. sop_has_left_fifo <= 1'b0;
  748. else if (out_pkt_sop_leave & pkt_cnt_eq_zero )
  749. sop_has_left_fifo <= 1'b1;
  750. if (in_pkt_eop_arrive & ~out_pkt_leave & ~drop_on_error ) begin
  751. pkt_cnt <= pkt_cnt + 1'b1;
  752. pkt_cnt_eq_zero <= 0;
  753. if (pkt_cnt == 0)
  754. pkt_cnt_eq_one <= 1'b1;
  755. else
  756. pkt_cnt_eq_one <= 1'b0;
  757. end
  758. else if((~in_pkt_eop_arrive | drop_on_error) & out_pkt_leave) begin
  759. pkt_cnt <= pkt_cnt - 1'b1;
  760. if (pkt_cnt == 1)
  761. pkt_cnt_eq_zero <= 1'b1;
  762. else
  763. pkt_cnt_eq_zero <= 1'b0;
  764. if (pkt_cnt == 2)
  765. pkt_cnt_eq_one <= 1'b1;
  766. else
  767. pkt_cnt_eq_one <= 1'b0;
  768. end
  769. if (in_pkt_start)
  770. pkt_has_started <= 1'b1;
  771. else if (in_pkt_eop_arrive)
  772. pkt_has_started <= 1'b0;
  773. end
  774. end
  775. // drop on error logic
  776. always @(posedge clk or posedge reset) begin
  777. if (reset) begin
  778. sop_ptr <= 0;
  779. error_in_pkt <= 0;
  780. end
  781. else begin
  782. // save the location of the SOP
  783. if ( in_pkt_start )
  784. sop_ptr <= wr_ptr;
  785. // remember if error in pkt
  786. // log error only if packet has already started
  787. if (in_pkt_eop_arrive)
  788. error_in_pkt <= 1'b0;
  789. else if ( in_pkt_error & (pkt_has_started | in_pkt_start))
  790. error_in_pkt <= 1'b1;
  791. end
  792. end
  793. assign drop_on_error = drop_on_error_en & (error_in_pkt | in_pkt_error) & in_pkt_eop_arrive &
  794. ~sop_has_left_fifo & ~(out_pkt_sop_leave & pkt_cnt_eq_zero);
  795. assign curr_sop_ptr = (write && in_startofpacket && in_endofpacket) ? wr_ptr : sop_ptr;
  796. end
  797. else begin : gen_blk20_else
  798. assign ok_to_forward = 1'b1;
  799. assign drop_on_error = 1'b0;
  800. if (ADDR_WIDTH <= 1)
  801. assign curr_sop_ptr = 1'b0;
  802. else
  803. assign curr_sop_ptr = {ADDR_WIDTH - 1 { 1'b0 }};
  804. end
  805. endgenerate
  806. // --------------------------------------------------
  807. // Calculates the log2ceil of the input value
  808. // --------------------------------------------------
  809. function integer log2ceil;
  810. input integer val;
  811. reg[31:0] i;
  812. begin
  813. i = 1;
  814. log2ceil = 0;
  815. while (i < val) begin
  816. log2ceil = log2ceil + 1;
  817. i = i[30:0] << 1;
  818. end
  819. end
  820. endfunction
  821. endmodule