I’ve now tried to write about how to convert a UART stream to a wishbone master several times over, and … each time the result has been too complex to explain within a simple blog post.
So, in good engineering fashion, let’s decompose the problem. Instead of presenting an entire wishbone controller, let me instead present you with an overview of the RTL side of a working UART to wishbone bridge that I’ve now used for many of my projects. When we build a new/simpler on this blog, we’ll need to include many of these design elements, so it’s worth taking a look at.
You can see an outline overview of the parts and pieces I’ve used before in Fig. 1.
The Transport End
At the top of this figure are the receiver and transmitter. In this design, the transport layer is a generic 8-bit interface.
Because the transport layer is so generic, it can be provided by either a serial port, JTAG port, or even a Digilent DEPP channel, such as the S6SoC uses. Indeed, even my work on the ICO board will use a fairly generic 8-bit parallel port interface.
There’s one additional requirement to this interface, necessary when the interface runs over something similar to a SPI port: there must be an idle character. That way when a character must be sent, such as when the SPI port must transmit in order to receive, the idle character can be sent. To date, I’ve used an 8’hff for this purpose–but only if I’ve needed it. That character can be generated by the transmitter, or quietly dropped in the receiver.
The Bus Master End
On the other end of the UART to wishbone bridge is the wishbone bus master that commands the entire bus interface to the chip. Any peripheral can be hung off of such a bus: flash, SDRAM, an AXI bus, network interface, an LED/switch/button interface, real–time clock, GPIO, OLEDRgb controller, UART controller, PS/2 mouse controller, and more.
In this case, the bus master accepts commands in the form of 36-bit words. These 36-bit words specify to the bus:
- What address to use (one word),
- Whether to write one word,
- Whether to stop writing, or
- Whether to read multiple words.
The read/write commands also include a bit indicating whether the address should increment between bus accesses, or whether all of the accesses will be to the same bus address.
Three specific capabilities of that can be hung off of this bus are worth mentioning.
The first is the flash controller. Because I can control the flash over a UART port, I can read, erase, and program the flash. That means that I can reconfigure the entire FPGA over UART. Even better, if you connect one of Xilinx’s ICAPE2 interfaces to the bus, you can then load and reload the FPGA’s configuration–without JTAG access.
The flash interface itself creates a unique requirement of this bus: When writing to the flash, the flash controller uses the end of the wishbone cycle (CYC line goes low) as the signal to start programming the flash. For this reason, when writing a series of values, we cannot drop the wishbone cycle line (CYC) until the last value is written. Dropping the CYC line is then the indication to the flash chip that it can start programming.
Finally, for the purposes of this blog, this wishbone interface is useful because you can now control a Wishbone Scope, whether it be a traditional scope or an RLE compressed scope which you can then use to debug any other part of your design.
That’s how powerful the wishbone bus master is.
Characters to Bits
Since this was my first interface (although now in its 3rd generation), I needed to be able to read what was going on. To accomplish this, I insisted that the interface run over printable ASCII characters: 0-9, A-Z, a-z, @ and %. The result is that, if necessary, I can read the interface by eye and understand what is being sent–although it does require a (not so secret) decoder ring to do it.
Newlines are treated as out of band characters, and used to end writes that may currently be in progress. This keeps us from using a 6-bit interface.
This also slows down the speed of the transport, since the transport layer can handle 8-bit bytes and we’re only using six of those 8-bit bytes.
Perhaps we can build a better one on this blog as time progresses?
Assembling into lines
While perhaps not required, the interface does assemble responses into lines. To do this, it inserts line breaks at the end of any response, or any time the line would otherwise overflow.
From a user’s standpoint, this makes it a lot easier to synchronize your eyes to the beginning of commands and responses–especially when/if you need to debug this interface.
Packing Bytes into Words
Any wishbone bus command requires first knowing whether you wish to read or write, a bus address, and possible a 32-bit data word.
To do all of these things, you need to be able to assemble 8-bit bytes into words that are at least 32-bits in length. That length is the minimum to hold a 32-bit data word that you wish to write, but by itself it’s not enough. The interface must also be able to indicate the type of transaction that is being requested.
While 36-bits works, it may be overkill for what we need. Perhaps we can drop this down to a 35-bit word?
UARTs are slow. Reading an FPGA’s configuration from a flash, so you know whether or not it needs to be reflashed, over a slow UART link can be painful. To speed things up, I added compression to this example bridge. For reading and writing, we use a simple compression scheme based upon a table of the most recently sent values. Addresses get compressed based upon either the difference between them and the last address, or perhaps just the low order bits of the address might be sent.
Resets and Interrupts
As a final step, the bus interface needs to handle a couple extra pieces:
When the bus is idle, the interface should send something periodically so that you know the FPGA is active on the other end.
If ever an interrupt occurs, you want that information inserted into the data stream
This logic is captured in the idle-int module.
Finally, you need some form of fault tolerance, so that if a peripheral doesn’t respond to the bus, the bus can detect that fact, reset the bus, and return an error across the channel. We use the same error code for a bus time out as any generic bus error coming from the bus itself, although we can usually tell the difference between them.
This watchdog capability is handled in the top level of the UART to wishbone bridge.
Since this bus communicates reads and writes of 32–bit words packed into six 8-bit bytes and transmitted over an 8-bit channel, it takes 60 UART baud cycles (8N1 encoding) to write one word across the bus (ignoring compression).
If you switch to 7N1 encoding, you can increase your speed by about 10%, since we were only ever using 7-bits of an 8-bit interface.
Stick with us and we’ll try to beat this number. Specifically, if we abandon a 6-bits within 8-bit interface and switch to a full 8-bit interface, we should be able to get down to about 46 baud per word–a 30% speed increase.
On the other hand, if we wish to multiplex a console port onto the channel, we may need to stick with a 7-bit interface. In that case, perhaps we can use all seven bits, instead of only 65 of the 128 values?
What isn’t shown in this diagram is the structure of the C++ software necessary to encode and decode words to send across this bus.
Still, if we can keep the interface to any redesigned bus as simple as the devbus interface that all of our interface software uses, then any software we’ve already written to use that interface will need to be relinked with the new interface library, but no other changes will be required.
A minimal interface
On this blog, we’re going to rebuild this interface. Our goal will be to design it in a manner so simple that any college student can build one. This may mean that we throw out any unused or unnecessary parts and pieces. We’ll also see if we can’t get our newer, better interface to run faster than this current one.
The result should be a simpler WB to UART bridge, such as the one shown in Fig 2.
Before we can build one of these, though, we’re going to need to spend some time learning how to build a wishbone bus master — similar to the last one, but simpler. Simple enough that it can be understood by the student, and simple enough that it requires very few hardware resources. That lesson will then inform the rest our work redesigning the interface itself.
And Elijah took his mantle, and wrapped it together, and smote the waters, and they were divided hither and thither, so that they two went over on dry ground. (2Kin 2:8)