UART in VHDL (A VHDL Primer)
These pages outline a small VHDL module I designed to illustrate the nature of VHDL. The actual functional module is that of a UART, hardware that is commonly used to transmit and receive binary data over an RS-232 data link, and possibly an analogue telephone system via a modem.
If you wish to skip the upcoming essay, a link to the schematics and code can be seen adjacent on the left. In addition the same information is available as a Serial Port resource kit, which you can download.
For anyone who is more familiar with conventional languages like C/C++, in general terms VHDL is described as a concurrent language, where C or Pascal, are non-concurrent. Possibly the best way to illustrate the implication of this is by considering the nature of a thread. In C, Pascal, and many others a thread is an executive context. As a part of the computer, many threads may execute concurrently. In some cases, depending on the hardware capability, the threads may actually execute one after the other in an interleaved manner. In either case, from the perspective of the programmer, these threads either appear to, or actually do, run in parallel. From the perspective of VHDL, the method by which this is done, may appear somewhat cumbersome, since these languages are not concurrent languages. In essence, for C, Pascal and others, creating a new thread is quite like starting a new program.
VHDL is something of a gem, because it is the entry point to the production of digital integrated circuits, or simply "chips". Although VHDL is a text based language like C or Pascal, typically there are a range of tools that allow detailed graphical description of language semantics. These tools then generate VHDL directly. Although VHDL is typically compiled in the same way as C/C++ et al., an important conceptual difference is present. A typical VHDL compiler might either produce instructions for a virtual machine which allows debugging, or it might produce an EDIF (Eee Diff) netlist, or even a GDSII (Gee Dee Ess Two) artwork, which can then be used to manufacture semiconductor devices. Once produced the basic meaning of the VHDL is implemented directly in the silicon chip.
There are cross compilers available which will allow C in particular to either be converted directly to VHDL, or to run in a processor which is then implemented in VHDL, on the semiconductor device. In either case there is a critical difference between manually devised VHDL, and say cross compiled C. In C one thinks merely of the next thing to do. With VHDL one must be thinking about the logic gates, and particularly the flip-flops, which will be implemented.
In a semiconductor, and in the natural world, many things are happening at once. By nature VHDL must be a concurrent language in order to express the relationship between calculations which are occurring simultaneously. In VHDL there is no need to spawn a new thread, like a new program, in a highly mechanistic way. This C or Pascal procedure is simply an inherent part of the VHDL language. It is perhaps an extreme to say that in VHDL one must strive to prevent concurrency, because that would be a difficulty. Nevertheless the equivalent of a thread can occur with little necessary thought or concern.
Looking in the other direction, there is no practical reason why VHDL could not be used to write computer programs. VHDL is pretty nearly the ADA language dressed in a slightly different coat. Where VHDL is focussed on hardware implementation, ADA is a formal programming language targeted at microprocessor. Nevertheless, the differences in the coat are everything. In many ways VHDL seems a more direct route to the goal, but perhaps this is because I am an electronics engineer.
Aside from military and aerospace applications ADA is rarely used for developing software. Perhaps this is because languages like C are perceived to be "easier". In practice, I think this is too simplistic a view. In a typical multithreaded C program, or even in ADA, the overhead of creating a thread is considerable. In C/C++, this is true in both programming and execution terms. For ADA, mainly only in execution terms. For quite natural functional reasons, with the advent of commonly available multiprocessing microprocessors and for performance reasons multithreading is more and more frequently done. Certainly, multiprocessor computers make the execution overhead smaller and smaller.
The trouble with multithreading in C is that the relationship between individual threads can easily become fiendishly complex. It is easy to create problems that, as a programmer you can never quite get your head around. For this reason then, a concurrent language like VHDL is perceived as fiendishly complex by a majority who are more familiar with non-concurrent languages. What is not neccesarily appreciated is that because the language is inherently concurrent, and there is no overhead associated with the creation of a new "thread", there is no incentive, or desire to create huge monolithic functional modules with extreme complexity. In VHDL one is always dealing with the simple "atomic" issues of concurrency, and as a consequence there is never a build-up of ambiguity. VHDL is not commonly considered Object Oriented, but it is so, just on a microscopic scale. I think I would describe it as "fine grain".
I am not trying to claim that equivalent functionality is produced as quickly in VHDL. This is, however, more appropriate than considering VHDL as a "hard" language. Nevertheless, the difference in performance between say C++ and VHDL, is simply massive. One is essentially trading design time against execution time. To illustrate the differences in performance, side by side a tight loop in C performing a single floating point calculation is limited by the processor, the cache and external memory. In VHDL one may simply ask "how much computation is required?". This can be asked, safe in the knowledge that any conventional software limit can be exceeded. This is true because space (semiconductor real estate) can be directly traded against time available for computation. Certainly, conventional software implementation can also trade in this way by increasing the number of computers, but in VHDL there is no computer overhead. If the only part of the computer in use is, say, the ALU, why put on the requirement for additional disk drives, power supplies and so on?
Looking at both C++ and VHDL, side by side, one must conclude that the ideal development effort would consider all of the problems that exist, and result in a product which is fully scalable and can achieve virtually boundless performance. When one adopts a language such as C or Pascal, one is simplifying the design process at a fundamental level. The penalty of such a decision is to accept that there is a limit to the product of complexity and performance. For most normal and rational purposes this is not a problematic penalty, but as the demand for complex high performance systems increases, so does the need for a concurrent implementation.
If you've got this far, you're probably wondering what all this has to do with an old fashioned UART. On the next pages we'll see why the UART is not so easy to implement directly in C++. In the mainstream RS-232 has broadly been replaced by USB. We'll also look at why it's still a pretty handy technology for development, test and other general purpose engineering functions.