Modern Digital Design for the Radio Amateur
by John Wiseman
(Originally published in QEX magazine, December 1997)
Introduction
Within the last few years, three major technological advances have combined to revolutionize the design of digital logic circuits. First, FPGA chips have become large and fast enough to perform significant circuit functions, while also becoming affordable for the typical amateur radio experimenter. Second, the usage of VHDL as a circuit descriptor and simulator has made it possible to design large digital circuits quickly and easily. And third, the emergence of digital logic synthesis software tools that can read and operate on VHDL circuit descriptions has considerably simplified the job of translating the design description into a functional logic design. A cursory glance through the electronic engineering job advertisements in newspapers and trade magazines will verify the importance that companies place on these skills, as many digital design jobs now require a working knowledge of FPGA design, VHDL, and logic synthesis.
In this paper, I will describe an FPGA-based circuit that was designed and implemented with VHDL and digital logic synthesis to control a direct digital synthesizer and a vacuum fluorescent front panel display in a home-brew transceiver. I will describe the basics of FPGAs and how they fit into the digital logic design hierarchy, the details of this particular circuit implementation, some background material on VHDL design techniques, simulation results, logic compilation, programming, and circuit prototyping.
Previous designs of circuits such as the one described here have used software programmed microprocessors as the controlling elements.1,2 This design takes advantage of the inherent modularity of VHDL and synthesized FPGA devices, by allowing powerful high speed digital logic functions that cannot be implemented in microcontrollers or even DSP chips to be added later, at the designers leisure, by merely adding I/O wires to the existing FPGA chip. As an example of this technique, I have already written and simulated VHDL that describes digital logic that is used to randomly dither the output of a direct digital synthesizer to help with spur reduction.3 This logic can be easily fit within the spare gates and I/O pins of the FPGA that is currently used in the radio for tuning and display. In this way, both low and high performance digital logic may be incorporated into one single integrated circuit with a single design methodology.
Digital Hardware Technology
In the hierarchy of digital circuit design, the most complex level is full custom design. In full custom, the designer has complete control over all of the design variables such as speed, layout, voltage, power consumption, etc., by designing at the transistor level and may trade off one or more of these variables for more performance in one of the others. This high level of performance comes at a very high price, however, as these circuits are usually the most expensive in terms of engineering development dollars. Of course they also require very sophisticated design tools as well as highly trained circuit specialists to design them. Last but not least, a state-of-the-art fabrication facility must build the integrated circuit and test it. Leading edge amateur radio experimenters regularly use complex full custom integrated circuits such as DSP chips in their designs that they have purchased from semiconductor companies, but very few would have the resources to design their own full custom chip!
Application Specific Integrated Circuits (ASICs) were invented to give digital designers the ability to implement circuits that approach the performance levels of full custom chips, but with lower development costs and less overall design and fabrication time. A particular type of ASIC is designed to be an "array of gates", in which digital logic gates are arranged in a fixed pattern on a substrate, and the fabrication process consists of connecting these gates together to perform a particular function by defining custom metalization layers for the chip. Because the circuit designer is not working at the transistor level as in full custom design, the job is considerably easier, but the ultimate performance will be somewhat lower as the designers freedom of choice is more limited. Gate arrays are available from many vendors that utilize gate counts of more than 1 million, with clocking speeds of greater than 100 MHz. Although cheaper to design and develop than full custom, this technology is still way out of the reach of amateur level experimenters, with typical non-recurring engineering costs of around $100K for complex designs, as well as expensive design tool packages being required for chip design and simulation.
Field Programmable Gate Array (FPGA) technology is basically a third level in the digital circuit design hierarchy, and holds considerable promise for the advanced amateur radio experimenter. If carefully designed, an FPGA can perform sophisticated logic functions at clock rates of greater than 50 MHz., with densities of up to 100,000 gates. An FPGA is an off-the-shelf part that is available from several semiconductor suppliers such as Actel, Altera, AT&T, Cypress, Xilinx and several others. It is designed to be like an ASIC, in that an array of gates or logic elements is placed unconnected on a substrate, and the designer coupled with the design software defines the connections. The connections for the FPGA are performed by the user, "in the field", therefore the term Field Programmable Gate Array. This is in contrast to an ASIC, where the connections are done by defining metalization layers at the semiconductor factory. FPGA logic element connections are basically done in two ways. The first defines a connection that is permanently made. This connection, once made, cannot be changed, and results in a one-time programmable part. This is usually fine for stable designs, and generally results in a faster circuit at somewhat lower prices. The second connection type is the one that is probably of most interest to amateur radio experimenters, and that is the many-time programmable style. Here, the connection is accomplished either with EEPROM (Electrically Erasable Programmable Read Only Memory) or SRAM (Static Random Access Memory) technology. The EEPROM based FPGA devices require no external device support, but they must be programmed either by placing the entire chip into a PROM programmer (with the proper adapter which can be quite large and expensive) or in some cases, via a serial link to a PC programming card. The design that I am going to demonstrate utilizes an Altera 81500 FPGA using SRAM connection technology that is programmed at reset via an inexpensive 8-bit parallel EPROM. These memory chips are very easy to program with standard PROM programmers without the need for expensive footprint adapters or additional PC board programming cards.
A level below FPGAs are the various Programmable Array Logic (PAL) and Programmable Logic Device (PLD) chips.4 These chips are generally used as "house cleaning" devices on circuit boards by combining relatively simple logic functions together in one chip, instead of several inefficiently utilized SSI or MSI integrated circuit packages.
The lowest level of digital design (outside of discrete transistors of course!) is done with Small-Scale Integration (SSI) or Medium-Scale Integration (MSI) integrated circuits, such as 7400 TTL or 4000 CMOS. These chips are typically available in 14 to 28 pin DIPs, and experimenters and hobbyists have been using wire-wrap, point-to-point, or PCB interconnection technologies to construct working boards with these chips. Back in the "bad old days", I worked on systems where I designed and debugged prototype wire-wrap boards that consisted of approximately 200 integrated circuits. These types of projects clearly showed the problems inherent to this style of design, such as technology specific specifications, package-to-package timing delays, interconnection wire cross-talk, clock skew, power consumption, etc. Also, one of the most difficult things about designs such as these are that if changes need to be made for whatever reason, they can be very difficult to actually implement. The design example that is illustrated in this paper would be fairly impractical to implement in discrete integrated circuits for usage in a small radio, but circuit construction is easily done with a modern FPGA device. The overall job is made even easier by using VHDL and logic synthesis as the design description tools for the FPGA.
Functional Design Goals
The digital circuit design described in this paper needs to perform two distinct functions. These functions are to communicate frequency information to the DDS chip in a parallel format, and to interface with the front panel display unit in a serial format. There are five input signals to the FPGA chip that control the state of the output lines. There are also six output signals that are subdivided into three signals that interface with the DDS, and three signals that interface with the display unit. These signals are detailed in Table 1 and are shown in block diagram form in Figure 1.
Signal Name |
# of Bits |
Input/Output |
Source/ Destination |
Function |
Clock |
1 |
Input |
|
Master Clock |
Reset |
1 |
Input |
Reset Circuit |
Power-Up Reset to Default Values |
Fine Tuning |
1 |
Input |
Front Panel Toggle Switch |
"On" - 10 Hz. Tuning "Off" - 1 kHz. Tuning |
Up |
1 |
Input |
Front Panel Push Button |
Increase Operating Frequency |
Down |
1 |
Input |
Front Panel Push Button |
Decrease Operating Frequency |
DDS Strobe |
4 |
Output |
DDS Interface |
Data Strobes for DDS Interface |
Timer Output |
1 |
Output |
DDS Interface |
End-of-Cycle for Testing Purposes |
DDS Data Output |
8 |
Output |
DDS Interface |
DDS Frequency Data |
Serial Data Output |
1 |
Output |
Front Panel Display Unit |
Serial Setup and Character Data |
Serial Clock Output |
1 |
Output |
Front Panel Display Unit |
Serial Clock |
CS Output |
1 |
Output |
Front Panel Display Unit |
Chip Select for Display Unit |
Table 1
Several of these signals require further explanation. The direct interface to the DDS chip is via a 24-bit parallel bus. In my previous design, I had added a PC parallel port interface board to the DDS input, resulting in an 8-bit parallel interface to any external device. I decided that it would be more trouble than it would be worth to undo this portion of the design, so I left the 8-bit to 24-bit receive/transmit latches in place, and did not incorporate them directly into the FPGA design, which could certainly have been done. In this manner, I can still use my PC parallel port interface if I choose to go back to that at some time in the future. Because of the multiplexed 8-bit data interface, the design requires four control signals, DDS Strobe 0-3.
The serial interface to the front panel display unit is fairly standard, with a data input, a clock input, and a chip select. The clock signal, Serial Clock Output, is gated so that it is activated only when needed to reduce potential noise from being coupled back into the receivers analog circuitry. For more detailed explanations of these signals and the required timing, one may request the Futaba NA16SD03AB data sheet from the factory.
The signal Timer Output is not actually used externally to the FPGA chip, but it is brought out as an output line for testing and verification purposes. I had initially used it as a "marker" in my simulations to define the end of a frequency update cycle, but then thought that it would be a good idea to have this signal available for potential display on an oscilloscope or logic analyzer at a later time. With so many available I/O pins on the FPGA, this is generally a good practice. In this case, this signal will toggle to a logic high for two clock pulses after the update cycle is completed. I have programmed this to occur after approximately one quarter of a second in this application.
The user interface controls were designed for simplicity, and also to somewhat mimic the functionality that was previously used in the PC software based design. In the PC controlled DDS interface, I had programmed the software to operate such that the Up arrow on the keyboard was the coarse frequency increment, while the down arrow was the coarse frequency decrement. Likewise, the right arrow was the fine frequency increment and the left arrow was the fine frequency decrement. The C code that controlled this process was written such that the user could enter any desired values for the fine and coarse frequency delta values, but I found that I used values of 10 Hz. and 1000 Hz. respectively under most conditions. Because of this, I decided to "hardwire" these values directly into the VHDL circuit description as default values. This reasoning is what led to the decision to use single push buttons for Up and Down, along with a toggle switch for Fine Tuning.
Now with a tuning resolution as wide as 1000 Hz., as well as a push button interface, it is not desired to tune too quickly. As a matter of fact, some time delay between frequency updates even when the buttons are being continually depressed is desired. My own personal preference based on the changing audio pitch of the scanned signals, as well as the visual update of the front panel display itself, has led me to choose a value of about one quarter of a second to be "hardwired" into the VHDL code as a constant value. Of course the trade-off for a delay time of this magnitude is that it will take approximately 13 seconds to scan 50 kHz. (Fine Tuning off), but for me that is fine.
All of this serves to illustrate part of the beauty of designing hardware with a language such as VHDL, then using synthesis tools to generate the FPGA logic. Preprogrammed constants such as the fine and coarse frequency delta values and the tuning time delay may be modified later by simply changing a single value in the VHDL code, recompiling, then reprogramming the FPGA or its EEPROM. What previously would have taken many hours of redesign, most likely resulting in the addition of "dead bug" chips to the board, along with the attending etch cuts and wire substitutes, now only takes a matter of minutes. In this respect, designing hardware is very similar to designing a quality software application for an embedded microprocessor or even a PC application such as the one that I had used previously for my tuner.
FPGA Circuit Description Using VHDL
By deciding to use FPGA technology for the hardware implementation of this design, we will satisfy several overall design goals such as relatively low power consumption, small circuit board area, and ease of reprogramming for debugging and future potential functionality enhancements. How then do we define the logic design for the FPGA? As was shown in the hierarchy of hardware design section, FPGA design at the board level allows us to design the hardware in as high a level of abstraction as we can reasonably afford. The goal for the actual FPGA circuit description design is to also remain as "high level" as possible, removing us from as many of the design variables as possible such that the design is quick and easy. This is where the power of VHDL coupled with logic synthesis is clearly demonstrated.
What is VHDL ?
In the early 1980s, the Department of Defense sponsored a program called Very High Speed Integrated Circuit, or VHSIC for short. Several different companies were involved, along with different circuit technologies, and a way to consistently describe these various designs in a technology independent manner was sought. From this effort, the VHSIC Hardware Description Language (VHDL) was born. One of the reasons that VHDL has proven popular with designers and Computer Aided Engineering (CAE) software developers alike is that it has been standardized as IEEE Standard 1076 and United States Department of Defense MIL-STD-454L. It is worth mentioning that another hardware description language called Verilog has become popular in the last few years as well. The next few years will decide which language becomes dominant, or whether both will peacefully coexist with both logic designers and CAE software vendors.
VHDL is a software language that is used to model and describe the workings of hardware. There are basically three styles of VHDL coding that are actively used. These styles are behavioral, RTL (sometimes also referred to as dataflow), and structural VHDL, which are hierarchical in nature. The highest level in the VHDL hierarchy, or the most abstract in nature, is the behavioral style. Generally behavioral VHDL is used to describe an algorithm or a system without regard for the clock cycles that actual hardware might utilize to perform the work. This style is useful for initial or baseline system simulations, or even as a system specification. Register Transfer Language (RTL) VHDL is sort of a middle ground description, where functionality is based on a clock cycle. In RTL, the designer thinks more in terms of how digital hardware is usually implemented. In this way, a collection of clocked registers is updated via various transfer functions. This is the level that most of the current generation of digital logic synthesis tools operate at, and it is the style that I have used to write the VHDL program in this paper. The lowest level of abstraction is structural VHDL, where previously defined components are essentially "hardwired" into the circuit. This level of VHDL is somewhat analogous to the drawing of schematics, as all individual connections must be fully specified. This is really gate level design at this point, and as such functionality is based on clock cycles as well as time itself.
In practice, the three main styles of VHDL described above are often mixed or blended together. It is desired to work at the highest level of abstraction possible for efficiency. To get the synthesis tools to perform adequately, however, it usually means that the designer must describe hardware at the RTL level. If the resulting synthesized circuit still does not meet critical design criteria such as speed, area, or power consumption, then the designer may have to mix in structural VHDL, and literally place predefined optimized functions into the logic design. Those familiar with software design will notice that this is somewhat similar to how programs are developed for real-time applications such as DSP. In this case, a high level language such as C is used with a compiler that generates assembly code. Only if necessitated by speed or memory limitations does the programmer go down a level of abstraction and use assembly language directly.
Some VHDL Basic Concepts
VHDL is very good in design applications such as the one described in this paper, but I will be the first to admit that it does come at a price. VHDL is a verbose language, and can be somewhat intimidating to learn. It is certainly not my intention to give a VHDL tutorial in this short paper (several textbooks Ive read havent done it justice!), but it is important to demonstrate a few quick examples to give a sense for the look and feel, as well as the power of the language when coupled to modern logic synthesis tools.
A typical software language such as C executes all of its instructions in a sequential manner, one after the other. In VHDL, instructions are executed concurrently. If it is desired to execute instructions such as conditional tests in a sequential manner, then these instructions are placed into design units called processes. Processes themselves are executed in a concurrent fashion, therefore ordering within the top-level of the program, the architecture, is irrelevant. Because of their importance in the RTL design style, I will give several process examples in the next section.
At the higher level, VHDL code will consist of an entity and an architecture. The entity in this design is used to declare and define the generic constants that are used throughout, as well as to define the I/O ports for the device. These I/O ports must have an associated name, type and mode. The architecture is really the main body of code for the design, where the actual simulation behavior of the entity is defined. Local signals must be declared here, and the statement region can only consist of concurrent statements. These concurrent statements can also be separate processes containing sequential statements.
At the lower level, VHDL objects can be described as signals, variables, and constants. Signals are used to communicate between other concurrent statements or among other processes. They are analogous to wires in a hardware sense. The syntax for updating signals is new_signal <= old_signal, where the signal new_signal takes on or receives the value of the signal old_signal. All signals in the design must be declared, along with an indication of what type they are. Being what is known as a strongly typed language, VHDL will check to make sure that the designer correctly matches signals within a design. An example of this is that the compiler will report an error if new_signal is declared as an 8-bit vector, but old_signal is a 12-bit vector. A note on syntax is that VHDL names are case insensitive, but they must be contiguous with no spaces. That is why my descriptive signal names contain underscores when more than one word are involved. Variables are used internally to processes as instantaneous data storage. As in a traditional programming language, variables are updated immediately, unlike signals which are scheduled and updated at the end of the simulation cycle. Constants are used to hold values that do not change, and are generally used to make the VHDL code easier to read and modify later.
VHDL Process Examples
The concept of the VHDL process with internal signal assignments is best demonstrated with some examples. In this section I have chosen four separate processes that show some important functions. These are the actual processes that are used in the DDS/Display Controller VHDL code.
Combinatorial and Sequential Logic
The first example process that I am giving is one that describes a pulse generation function. The desired pulse is to be two clock cycles wide, and is used to trigger the initial default conditions for the display and the DDS chip at reset. The way that this works is that Reset_Int (latched Reset signal) is delayed with two inferred flip-flops within the IF Clock statement. Note that the term inferred refers to the fact that the synthesis tool will interpret what I have written in software to mean a clocked delay, implemented in hardware with a flip-flop. Reset_Int is delayed by the first flip-flop, with the output labeled as the signal Reset_Del. This signal is then delayed by the second inferred flip-flop to create Reset_Del_1. Notice that these two consecutive statements will be updated in parallel during the update phase. A shift register of N bits could be described with this technique by writing N consecutive assignment statements within the an IF Clock statement.
This process also contains a combinatorial statement. This statement performs an exclusive OR function on the original signal Reset_Int and the two clock pulse delayed version just created. This will result in a single pulse lasting for two clock cycles, that occurs immediately after Reset goes high. Note that this XOR statement is not contained within the IF Clock statement, as it is not desired to be clocked logic.
An interesting thing for the beginner to do is to convince himself that the synthesis tool is indeed putting out the intended hardware from the VHDL description. I ran this process through the Synopsys FPGA Compiler and plotted out a schematic of the resulting gate level logic. If you inspect Figure 2, you will see that the resulting logic is indeed what was intended when the process was written. Note that the exclusive OR function was implemented in terms of AND/OR gates, along with inverters, as the Altera library that I was using did not have exclusive OR primitive functions.
Initialization:
PROCESS(Clock, Reset_Int, Reset_Del_1)
-- Note: Comments in VHDL are denoted with the double dash symbol (--).
-- This process produces a single pulse, Init_Signal, which is used to trigger the initial
-- system outputs following a reset.
BEGIN
IF Clock = 1 AND ClockEVENT THEN
Reset_Del <= Reset_Int;
Reset_Del_1 <= Reset_Del;
END IF;
Init_Signal <= Reset_Int XOR Reset_Del_1;
END PROCESS Initialization;
Sequential Logic With Feedback
With this process, it is desired to produce a clock for the serial section that is a divide-by-two of the input clock. A simple method for accomplishing this in discrete logic design is to use a D flip-flop, connecting the inverse-Q output back to the D input. That is essentially what is modeled here, with the addition of a clock enable function (Serial_Clock_Enable) and a reset function (Reset_Int).
This process is desired to be synchronous, so a D flip-flop is inferred with the IF Clock statement. Within this statement, another IF statement is used to test whether Serial_Clock_Enable is low (= 0), OR Reset_Int is low. If either of these cases are found to be true, then it is desired to output a constant high logic level, with no clocking. This is done with the Serial_Clock_Preout <= 1 statement. If both of these conditions are not satisfied, then it is desired to output the divide-by-two clock, and this function is contained within the ELSE portion of the statement. The statement Serial_Clock_Preout <= NOT Serial_Clock_Preout assigns an inverted version of this signal to itself on every rising edge of the clock, thus emulating the divide-by-two D flip-flop described above.
Again, as in the previous process example, I have given the gate level schematic output of the Synopsys FPGA Compiler for this process to show that the gate level representation is what is desired (see Figure 3). In this case, it is clear that an inverted version of the output is fed back to the D input of a flip-flop, and that this input is enabled by both the Reset_Int and the Serial_Clock_Enable lines.
Serial_Clock_Divider:
PROCESS(Clock)
-- This process produces a divide-by-2 clock for the serial section.
BEGIN
IF Clock = 1 AND ClockEVENT THEN
IF Serial_Clock_Enable = 0 OR Reset_Int = 0 THEN
Serial_Clock_Preout <= 1;
ELSE
Serial_Clock_Preout <= NOT Serial_Clock_Preout;
END IF;
END IF;
END PROCESS Serial_Clock_Divider;
State Machine Description With the CASE Statement
Having read through the previous two process descriptions and having seen the gate level output schematics, you might be wondering to yourself what all the fuss is. It would appear that I have gone to great lengths to describe in many words what a schematic can describe with relatively few lines and symbols. This may be true for the simplest of circuits, but it becomes far more powerful when the advantages of software based higher level languages are coupled with synthesis tools for design of state machines, counters, etc. In these instances, relatively few powerful commands can synthesize down to hundreds if not thousands of gate equivalents, thus saving the designer considerable amounts of time and effort.
A powerful method of describing state machines with VHDL is with the CASE statement. As an example of the usage of this statement, I have included the following processes that describe a state machine within the DDS and display interface design that generate three outputs. These outputs are Output Strobe 0-3, which go directly to the DDS interface circuitry, Data Mux Enable, and Cycle Over, both internal signals that are used for control purposes.
First, take a look at the structure of the process Output State Combinational. As its name implies, this process is going to control the output state of the state machine, and it is not sequential, or clocked in nature. As such, there is no IF Clock type statement in the process. For the design of the state machine, start with the number of different states that are desired. In this case, I want eighteen discrete output states, so I block off eighteen distinct WHEN sections as shown below. Each of these blocks is started off with the statement WHEN State(N) => , where N ranges from 0 to 17. Each of these statements within a block is followed by the signal assignments that make up the desired outputs of the state machine at that particular time. A closing statement, Next_State <= State(N+1), is used to tell the state machine what the desired next state is to be. When the 18th and final state is being executed (N=17), the Next State transition will be to go back to State0. But what are the signals labeled as State0 - State17 that represent these output states? They are all enumeration literals, each of them elements of an enumeration list. To use these, we must declare a new user-defined data type, and I call that States_Enum_Type. This declaration must be done before any signal declaration and process listing within the VHDL code. As such, I have given not only the processes of interest here, but the ARCHITECTURE template as well, showing the structure and placement of the TYPE declaration within it.
Now because the enumeration literals State0 - State17 are used to update the signals Current_State and Next_State, we must declare these signals to be of TYPE States_Enum_Type. This is also elaborated in the example below for clarity.
Finally, to tie all of this together, the sequential process Output_State_Sequential is also given as part of this example. The purpose of this process is to synchronize the output from the combinational process Output_State_Combinational in a fashion that the synthesis tool will recognize as an efficiently organized hardware description.
In the previous process examples, I gave schematic outputs that allowed a beginner to verify that the VHDL description did indeed synthesize into the correct gate level representation by checking the schematic output, which is probably the more familiar method of circuit description for older-style digital logic designers. This rapidly becomes impractical as the size of the synthesized circuit surpasses more than a handful of gates, and is unnecessary anyway once you become comfortable with the VHDL description. The point to be made here is that the VHDL code IS the circuit representation. When you become comfortable with it, you will find it easier to think in VHDL terms anyway, and the "crutch" of having to refer to schematic representations will go away. As such, no output schematics for the FPGA logic are shown from this point on in this paper.
ARCHITECTURE test1 OF test_logic_3 IS
-- Types are defined here.
TYPE States_Enum_Type IS ( State0, State1, State2, State3, State4, State5,
State6, State7, State8, State9, State10, State11,
State12, State13, State14, State15, State16, State17
);
SIGNAL Current_State: States_Enum_Type;
SIGNAL Next_State: States_Enum_Type;
BEGIN
Output_State_Sequential:
PROCESS(Clock)
-- This process synchronizes the output from the process defined by
-- Output_State_Combinational.
BEGIN
IF Clock = 1 AND ClockEVENT THEN
IF Reset_Int = 0 THEN
Current_State <= State17;
ELSIF Reset_Int = 1 AND Cycle_Enable = 1 THEN
Current_State <= Next_State;
ELSE
Current_State <= State17;
END IF;
END IF;
END PROCESS Output_State_Sequential;
Output_State_Combinational:
PROCESS(Current_State)
-- This process defines the state machine that controls the generation of
-- Output_Strobe, Data_Mux_En, And Cycle_Over. Next_State is latched to
-- Current_State in PROCESS Output_State_Sequential.
BEGIN
CASE Current_State IS
WHEN State0 =>
Output_Strobe <= "0000";
Cycle_Over <= 0;
Data_Mux_En <= "000";
Next_State <= State1;
WHEN State1 =>
Output_Strobe <= "0001"
Cycle_Over <= 0;
Data_Mux_En <= "000";
Next_State <= State2;
WHEN State2 =>
Output_Strobe <= "0000"
Cycle_Over <= 0;
Data_Mux_En <= "000";
Next_State <= State3;
WHEN State3 =>
Output_Strobe <= "0010"
Cycle_Over <= 0;
Data_Mux_En <= "001";
Next_State <= State4;
*
*
*
WHEN State17 =>
Output_Strobe <= "1000";
Cycle_Over <= 0;
Data_Mux_En <= "101";
Next_State <= State0;
WHEN OTHERS =>
Output_Strobe <= "0000";
Cycle_Over <= 0;
Data_Mux_En <= "000";
Next_State <= State0;
END CASE;
END PROCESS Output_State_Combinational;
VHDL With Arithmetic Operations
This process demonstrates the usage of higher level functionality such as adders and subtractors. Again, the usage of code within the IF Clock statement infers a synchronous nature to the circuit, and the usage of IF - ELSIF statements allows conditional functionality depending on the status of various control signals.
The first condition checked is for the status of the Reset line. If it is at a logic low level, then the default values for the receive and transmit frequency will be loaded into DDS_Data_Counter_Rx and DDS_Data_Counter_Tx respectively. If Reset is not active, then the status of the control inputs Up, Down, and Fine Tuning is checked to determine what operation to perform. In the case of Up_Int = 1 AND Fine_Tuning_Int = 1 (along with Timer_Preind = 0, a timing reference), then the value of the constant Fine_Tuning_Offset will be added to the previous value of DDS_Data_Counter_Rx and _Tx. In this design, Fine_Tuning_Offset is fixed at the unsigned 24-bit representation of 10, for 10 Hz. increments.
Likewise, if Down_Int = 1 AND Fine_Tuning_Int = 1, then the value of Fine_Tuning_Offset (10) is subtracted from the previous value of the data counters. The remaining two conditional tests are for when the Fine_Tuning_Int signal is in the 0 state, indicating that fine tuning is shut off and that coarse tuning is desired. If Up_Int is = 1, then the value of Coarse_Tuning_Offset is added to the data counters. If Down_Int is = 1, then it is subtracted from the data counters. Again, Coarse_Tuning_Offset is a constant, and it is set in this design at the unsigned 24-bit representation of 1000, for 1000 Hz. increments. If all of the conditional tests fail, then the previous states of the data counters are used, and no change is made to the DDS frequency.
Now all of this was a real mouthful, wasnt it? The actual VHDL process as shown below is much more concise and to the point than the English language description, once you are familiar with how to read and understand it. This is one reason why VHDL is often used as a system specification as was mentioned previously.
DDS_Counter:
PROCESS(Clock)
-- This process defines the count, up or down, procedure for the DDS
-- interface portion of the output.
BEGIN
IF Clock = 1 AND ClockEVENT THEN
IF Reset_Int = 0 THEN
DDS_Data_Counter_Rx <= Rx_Reset_Freq;
DDS_Data_Counter_Tx <= Tx_Reset_Freq;
ELSIF (Up_Int = 1 AND Timer_Preind = 0) AND Fine_Tuning_Int = 1 THEN
DDS_Data_Counter_Rx <= DDS_Data_Counter_R + Fine_Tuning_Offset;
DDS_Data_Counter_Tx <= DDS_Data_Counter_Tx + Fine_Tuning_Offset;
ELSIF (Down_Int = 1 AND Timer_Preind = 0) AND Fine_Tuning_Int = 1 THEN
DDS_Data_Counter_Rx <= DDS_Data_Counter_Rx - Fine_Tuning_Offset;
DDS_Data_Counter_Tx <= DDS_Data_Counter_Tx - Fine_Tuning_Offset;
ELSIF (Up_Int = 1 AND Timer_Preind = 0) AND Fine_Tuning_Int = 0 THEN
DDS_Data_Counter_Rx <= DDS_Data_Counter_Rx + Coarse_Tuning_Offset;
DDS_Data_Counter_Tx <= DDS_Data_Counter_Tx + Coarse_Tuning_Offset;
ELSIF (Down_Int = 1 AND Timer_Preind = 0) AND Fine_Tuning_Int = 0 THEN
DDS_Data_Counter_Rx <= DDS_Data_Counter_Rx - Coarse_Tuning_Offset;
DDS_Data_Counter_Tx <= DDS_Data_Counter_Tx - Coarse_Tuning_Offset;
ELSE
DDS_Data_Counter_Rx <= DDS_Data_Counter_Rx;
DDS_Data_Counter_Tx <= DDS_Data_Counter_Tx;
END IF;
END IF;
END PROCESS DDS_Counter;
Processing the Complete VHDL Code
The complete VHDL code describing this design is too long to be included here in its entirety, but it can be downloaded via FTP by visiting the ARRL website at http://www.arrl.org/qexfiles/. I would encourage taking a look at the code, as most of the processes used are variations of the four given above, and are not hard to understand. I have tried to use a fair amount of comments in the code at critical places where it may be difficult to follow the logic. I have also included a second file that is a VHDL testbench. This code is not required directly for compilation of the FPGA design, but it is necessary to perform a simulation. If you download the code for inspection, note that at the end of the testbench code there is a commented section labeled "Test Vectors". This section actually exists as a separate file, and is read by the testbench code, then used as input stimulus for the design simulation. In this manner, the designer can quickly and easily test all of the desired functions of the circuit.
Now that we have a complete VHDL description of the circuit that we wish to build, we can proceed to the simulation stage. After simulating the circuit for the required functionality, we will process the design using the Synopsys logic synthesizer and the Altera FPGA compiler.
VHDL Functional Simulation
The VHDL simulator that I prefer to use is produced by Model Technology Incorporated. It has a very sophisticated user interface that includes separate windows for most of the desired testing and debugging functions, such as displaying updated variables and signals, a source code display list with single-step and breakpoint capabilities, and a waveform input/output trace graphics display. I have included a photograph (Figure 4) showing what a typical testing/debugging session looks like within the Model Technology VHDL simulator. Note that the display computer is a PC running Windows NT, but the simulator is actually running on a Sun workstation under UNIX, via X-Windows software.
The simulator reads the compiled VHDL circuit description software as well as the compiled VHDL testbench code, and produces an output that may be checked at whatever level the designer deems to be appropriate. Very complex and sophisticated designs might produce large output files that need to be computer checked and compared to "standard" output files that are generated by other means such as C code or even behavioral VHDL. In the case of the circuit designed here, a visual check of the output within the waveform window is sufficient for verification purposes. The functionality items that I have chosen to simulate fully before programming the FPGA are 1) that the correct default information is output after a power-up reset, 2) the Up and Down controls work properly, both with and without the Fine Tuning control, 3) the desired time delay between updates is implemented correctly, and 4) that no timing violations will be present either at the DDS interface or the display interface module.
In general, simulation will be a two step process. The first step is as described above where the technology independent VHDL code is simulated for correct performance on a clock cycle basis, with no inherent timing dependencies. The second step is a back annotation of timing information into the simulator. What this does is allow the designer to take timing information that is generated from the actual routed gate level design and verify that the real design still works as planned.
Logic Synthesis
After verifying that the VHDL code does what is expected of it via simulation, the code can be read by the logic synthesis tool. The dominant force in the digital logic simulation field today is Synopsys, and that is the tool that is used for the synthesis of the FPGA in this paper. Synopsys markets several tools for the ASIC/FPGA design market, and the one that is used here is aptly named FPGA Compiler. FPGA Compiler performs several tasks, such as the mapping to flip-flops in I/O modules as well as mapping to complex flip-flops (if available in the library), finite state machine optimization, technology specific proprietary lookup table mapping transformations, and the generation of timing constraints that are used by the place and route tools.5
Since FPGA Compiler transforms the VHDL into technology specific implementations, it is necessary for it to access vendor supplied FPGA design libraries. This particular design uses an Altera 81500 FPGA, so it is necessary to use the FLEX 8000 family design libraries from Altera. After compilation to the target library, a primitive netlist is generated by FPGA Compiler and stored in Electronic Data Interchange Format (EDIF). This standard text-based file format is commonly used to transfer design files among different vendors software packages. In this case, it will provide a common format in transferring data from Synopsys FPGA Compiler to Alteras MAX+PLUS II design package.
FPGA Postprocessing and Layout
There are several more processing steps that must be done before a programming file may be generated for the EPROM. These final steps are performed within the Altera environment, in a software package called MAX+PLUS II.6 The first thing that must be done is to read in the EDIF file that was generated by the Synopsys FPGA Compiler. This data is then further processed to generate place and routing information for FLEX 8000 FPGA family devices. Along the way, design rule checking is done to make sure that good design practices are followed. This step can provide useful information to the designer, as it flagged to me the fact that I did not initially have synchronizing flip-flops on the asynchronous Up and Down input signal lines. After the logic is fully partitioned into real Altera logic elements, a fitting operation is done to determine what particular part from within the FLEX 8000 family will accommodate the design. If it is known in advance that a particular part will be used and that it is large enough in terms of both gate count and pin count, then this stage can be skipped.
When the selected part is placed and routed, final timing information for the FPGA design is generated. This information is then back annotated to the VHDL simulator, via a VHDL netlist output from the Altera software, and the simulation is checked to make sure that the design still works. If not, then various things can be done, such as rewriting the VHDL source code for more efficiency, optimizing some of the various parameters within the Synopsys environment, or even specifying a faster FPGA device. In the case of this particular chip, timing is very loose as the main clock is only 1 MHz. and no further processing was found to be needed.
The last stage within the Altera environment is a final assembly. Among other things, an output file in Intel hex format is generated that can be used to program the FPGA EPROM. At this point, the design is now ready to be tested in the system.
FPGA Programming
The Altera FLEX 8000 family of FPGA devices can be programmed in several ways. They can be programmed via an external device such as a PC or a microprocessor, or they can program themselves on power-up, either with a small footprint serial PROM or a standard 8-bit wide parallel EPROM. In the latter cases, self-programming is accomplished via signals on dedicated I/O lines of the FPGA that are automatically generated internally. For simplicity and economics, this design uses a 32K byte parallel EPROM for automatic programming. The MAX+PLUS II software generates an Intel hex programming file as part of its final output, and this is loaded directly into a standard PROM programmer.
Circuit Construction and Testing
The circuit board construction was fairly standard, as the board consists of only a handful of parts. After all, consolidation is one of the main goals of FPGA usage. The main problem with this design, is that the Altera 81500 chip that I used is most economically priced in a 240 pin quad flat pack package. This particular package has its leads spaced at only 0.5 mm, and is virtually impossible to handwire directly onto a breadboard. Because of this, I had to purchase a prototyping adapter. This adapter has a surface mount position for the chip on the top, with circuit board traces leading to a more conventional pin grid array arrangement on the bottom. This adapter can then be mounted on a breadboard with wires to the individual pins. The particular adapter that is used here is one that was originally designed for a Motorola MC68360, and is manufactured by Emulation Technology, Inc. With the relatively low clock frequency of 1 MHz. used in this design, plus the fact that my FPGA outputs were programmed for a slow slew rate, conventional point-to-point wiring is acceptable as long as the wires are kept reasonably short. For higher speed designs that have more I/O pins switching voltage levels simultaneously, this might not be an acceptable solution, and a PC board may have to be constructed to handle the switching transients that are generated.
Initial testing of the FPGA with the radio was done by using an FPGA test board that contained a 1.0 MHz. clock oscillator, a 32K byte EPROM, and an Altera 81500 FPGA chip. This particular board was designed to be general purpose in that only the parallel connections to and from the EPROM were wired directly, along with power and ground to the FPGA. All other chip I/O pins are routed to header pins, and may be connected as needed by the designer to other chips or peripherals. This is the set-up that is shown in Figure 5.
After the vacuum fluorescent display and the DDS interface were wired to the FPGA test board header pins, power was applied. After some initial testing, it was determined that although the DDS interface was indeed functioning correctly and the receiver was tuning correctly, the characters on the display were not in the correct order and were not being updated correctly. After some consultations over the telephone with a Futaba engineer, it was pointed out to me that there was an error in the design specification that had come with the display unit. The specification says that the maximum time between bytes that are sent to the display unit must be 12 microseconds. What it should say is that the minimum time between bytes must be 12 microseconds. My initial design called for a delay period of 5 microseconds, so this was increased to 20 microseconds by providing a divide-by-4 clock to this portion of the circuit. This modification was made to the VHDL in a matter of minutes, and then after recompilation (I didnt bother to resimulate this minor change) a new EPROM was programmed. After replacing the EPROM, the circuit was powered up again and all functions were found to be working correctly. This process is in stark contrast to what would have to have been done if the design were implemented in discrete digital logic chips. In this case, the modification would have required a separate chip to provide the two extra D flip-flops. If the design was wire-wrapped, then the clock net would have to have been separated and rewired into the divide-by-4 circuit. If a printed circuit board was used, then etch cutting and IC dead-bugging would have been necessary to make the change. In either case, this would have been a time consuming and messy approach.
Design Methodology Review
Lets review what the technologies presented in this paper have done for us. First, the usage of an FPGA chip has allowed us to design a fairly complex digital logic circuit that previously would have taken many discrete integrated circuits to build. The circuit design may be modified slightly or even totally redesigned by merely reprogramming a standard EPROM. By treating designs such as this one as modules, it is possible to incorporate more than one module together into a larger FPGA. As an example, I could incorporate a DSP filter onto the same FPGA as the tuner/display function demonstrated here and save even more circuit board area. Second, using VHDL as the circuit description gives us a fast and efficient, technology independent, standard way of describing hardware, that may be machine read because of its software nature. An example of this extremely important concept is that anybody can download my VHDL source code from the ARRL site mentioned previously and compile it locally. This compiled VHDL can then be used with a digital logic synthesizer (the third major piece of this methodology) and the appropriate vendor libraries to implement the circuit. Since we are operating in a technology independent mode, it is quite easy to then synthesize to another vendors chips, for example Xilinx or AT&T. This is much easier than if the design was initially described in schematic form, as considerable modifications are generally necessary when transferring a schematic based design between different vendor technologies.
Between the FPGA chip itself, the VHDL code, and the logic synthesis stage of the project, it is probably most important for the designer to have an in-depth knowledge of VHDL and how to use it effectively than it is to understand the absolute low-level details of the FPGA architecture, or even how the synthesis software works. Of course the right chip must be chosen for the right job, and there are various choices within the simulation environment that can ultimately make or break a design, but in general the VHDL will have the largest effect on most designs such as the one described here. That is one of the main reasons why several detailed VHDL process examples were given previously.
More Economical Alternatives
The design environment that I have described in this paper consists of software packages from three separate vendors. The VHDL simulator is from Model Technology, the FPGA Compiler is from Synopsys, and the place and route tools are from Altera, all UNIX versions running on a Sun workstation. This "professional" level approach is great for the designer, but very expensive. Fortunately, there are some alternatives in the market that will allow development of fairly sophisticated FPGA devices without having to spend a fortune in software tools. If it is desired to work with Altera FPGA devices exclusively, then the MAX+PLUS II software package can be purchased with a VHDL compiler and a simulator. This package is available for PCs running Windows NT, as well as a UNIX version for workstations.
A true bargain is the offering from Cypress Semiconductor that supports their own programmable devices. These chips are smaller than the FPGA described in this paper, but may still be quite useful to the amateur radio experimenter, and the design kit is geared more towards the VHDL/programmable logic beginner. This kit contains a book entitled "VHDL for Programmable Logic", VHDL design software, a PC programming interface, and samples of one of their programmable chip offerings. Cypress has recently advertised this product in several electronics trade magazines for only $175.
Conclusion
The emergence of large and fast FPGA chips that may be reprogrammed many times has created new opportunities for leading edge amateur radio experimenters. The example that was described in this paper was one of low speed tuner and display control, yet these chips are powerful enough to also perform other advanced functions such as high speed digital signal processing at IF rates that standard DSP chips or microprocessors cannot handle. New software methods, such as VHDL and digital logic synthesis, are giving designers the ability to create and modify working circuits with FPGA chips in considerably less time than was possible before. This style of digital design methodology was previously available only to professional engineers, but as prices of both the chips and the software necessary to design and program them continue to fall, more opportunities for the experimenter and hobbyist will become available.
VHDL Suggested Reading List
I have found the following textbooks to be quite useful for the initial learning of VHDL, as well as for use as references for more advanced applications:
VHDL, Douglas Perry, McGraw-Hill 1994, ISBN 0-07-049434-7.
VHDL Techniques, Experiments, and Caveats, Joseph Pick, McGraw-Hill 1996, ISBN 0-07-049906-3.
VHDL for Logic Synthesis, Andrew Rushton, McGraw-Hill 1995, ISBN 0-07-709092-6.
Internet Information Sources
The following Internet newsgroups are useful sources of information for VHDL and FPGA issues for all levels of expertise:
comp.lang.vhdl
comp.arch.fpga
The following World Wide Web sites contain product information for some of the software design packages and FPGA chips mentioned in the article:
http://www.synopsys.com (Synopsys logic synthesis software)
http://www.altera.com (FPGA software compiler & chips)
http://www.cypress.com (low-end VHDL & programmable logic design starter kit)
Notes
1Curtis Preuss, "Building a Direct Digital Synthesis VFO," QEX, July 1997, p 3.
2Don Kirk, "The Ultimate VFO," QEX, April 1996, p 13.
3George Zimmerman & Michael Flanagan, "Reducing Spurious Output of NCOs: Random noise added to either amplitude or phase prior to truncation," NASA Tech Briefs, June 1994, reference #NPO-18789.
4Advanced Micro Devices, PAL Device Handbook, 1988, Section 1.
5Synopsys, FPGA Synthesis Class Notes, October 1995.
6Altera, 1996 Data Book, Section 12.