2
\$\begingroup\$

I am working through a weird problem. We are pin constrained on our FPGA and need to control a common bus. This was all fine and good as all the software was sequential, but now some requests will be coming in at the same time for devices, but will now have to be put into a queue.

How should I take care of making sure that everything gets shoved into a FIFO without priority and without dropping data? I've got the outer design complete for controlling everything up until the bottle-neck where everything gets shoved into the pipe before being granted access to our "bus". Some requests will take a long time to come in, but will do so concurrently from an FPGA whereas software commands will come in sequentially, but less predictably. If I don't care about the order in which I grant access to the "bus", what is the best way to pipe all of this information into a single FIFO under the assumption that some commands will be coming in at the same time without knowing how many there will be? I would like to avoid having to request/ack/grant if possible as I would like all of this to be taken care of by a single component that just receives a bunch of data and takes care of the complexity. What is the easiest way to accomplish this?

\$\endgroup\$
  • \$\begingroup\$ Almost full msg and almost empty? \$\endgroup\$ – Sunnyskyguy EE75 Sep 13 '18 at 23:25
  • 2
    \$\begingroup\$ If you don't want to apply backpressure (using request/ack/grant) then you have to decide what should happen if data comes in faster than it goes out. \$\endgroup\$ – immibis Sep 13 '18 at 23:36
  • \$\begingroup\$ Do you have a guarantee that the average needed bandwidth over a limited time is lower than the available bandwidth on the bus? Is this limited time reasonable? Is not dropping messages a hard requirement? Are all these questions harder to answer than just supporting backpressure? \$\endgroup\$ – DonFusili Sep 14 '18 at 8:42
  • \$\begingroup\$ @DonFusili So our available bandwidth on the bus is able to support the worst case scenario where every "master" is requesting time, however dropping data is a very strict requirement. Backpressure is a difficult question since the data coming in is from an ADC that is running continuously and we cannot affort to pause this processing. I am looking for an interface that can keep up without building backpressure as my concern is not the bus itself, but the servicing of bus time. \$\endgroup\$ – nichollsg Sep 14 '18 at 18:53
  • \$\begingroup\$ @DonFusili One idea I had was to provide a FIFO or simple buffer on each source and using an arbiter to service these FIFOs while they are not empty. I have heard of axi streams (we're using Xilinx) but am not too familiar with implementing them. My original hope of a single FIFO pretty much guarantees that I will need to pause processing time somewhere while each component waits for a grant, so I forsee issues at this point in the system. Do you have suggestions for an axi stream like interface? \$\endgroup\$ – nichollsg Sep 14 '18 at 18:57
1
\$\begingroup\$

If you only have one 'sink,' then you have to arbitrate. You'll have to apply backpressure to any source that has yet to receive a grant. If you can't apply backpressure to whatever is generating the requests directly, then the only option is to put in a 'large enough' FIFO on each source and apply backpressure to those FIFOs. The trick is figuring out how big those FIFOs need to be to eliminate drops - maybe some sources can accept backpressure, maybe some send more often and therefore require deeper FIFOs, etc. You can usually make FIFOs of depth 16-128 or so using distributed RAM with 1 LUT per bit.

AXI stream is super simple, it's just a ready and a valid signal that go along with the data. Valid is high when the data is valid, ready indicates that the sink is ready to receive the data, and data is transferred when both valid and ready are high. When you connect a FIFO with a 'traditional' FIFO interface, you can map input_ready, input_valid, output_ready, and output_valid onto read, write, full and empty like so:

read = output_ready && output_valid
write = input_ready && input_valid
input_ready = !full
output_valid = !empty
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.