This project presents more complex designs that use “hierarchical” circuits. Hierarchical circuits are higher-level circuits that use lower-level sub-circuits as building blocks. Often, the sub-circuit building blocks are commonly-used blocks like muxes or decoders, but just as often they are unique, and specifically designed for the application.
Typically, any design that can be partitioned into simpler building blocks and implemented using a hierarchical design should be built that way. There are many advantages to this “divide and conquer” approach: complex tasks that are divided into simpler tasks are easier to design, document, and debug; the simpler sub-circuits can be independently simulated and verified, making it easier to find and fix problems in the higher-level circuit; often, the simpler sub-circuits are pre-existing or well-known circuits that can readily and reliably be used; the designer can focus on interactions between particular sub-circuits one at a time, rather than trying to address larger numbers of interactions in a larger monolithic circuit; the sub-circuits can be stored in a library for future reuse; and there are many others.
In a typical hierarchical design, the first step is to partition the overall design into sub-circuits along functional boundaries. Often, these functional boundaries are somewhat obvious, as is the case with the designs presented in this project. But sometimes, the choice of where (and why) to partition a design in a certain way is not clear, and no single architecture is obviously the best. In these cases, it is typical that several candidate partitions are sketched, pros and cons of each weighed, and the most likely approach pursued further. Then, as the design proceeds, adjustments can be made. Ultimately, experience (and perhaps consultation with others) will guide such choices.
Hierarchical designs are implemented using structural Verilog. Structural Verilog source files follow the same general methods as the hierarchical design itself – Verilog modules are created for all sub-circuits, and these modules are then “instantiated” and interconnected in a higher-level module using “port mapping” statements. Each sub circuit can (and should) be independently verified, so the top-level module verification only needs to confirm the connections between modules.
Before you begin, you should:
- Know Vivado and how to use the Boolean board;
- Know how to design and implement logic circuits;
- Understand the structure and function of muxes, decoders, and shifters;
- Know how to write and run Verilog testbenches.
After you’re done, you should:
- Know how to create hierarchical designs using structural Verilog;
- Know how to use and instantiate components in higher-level designs;
- Be comfortable working with larger Vivado projects.
The first requirement in this project involves a simple communication system using a mux and de-mux circuit. The mux will select one of n signals to communicate using time-division multiplexing, and the de-mux will decode and recreate the signals on the receiving end. The mux and de-mux will be implemented in two separate Verilog files, and instantiated in a top-level module using structural Verilog.
In the second requirement, you will create a special decoder called a “Seven Segment Decoder”, or 7SD, that receives a binary number and decodes it into signals that can drive a seven-segment display. Then, your 7SD circuit will be used to drive one and/or two digits on the Boolean board seven-segment display.
A requirement in this project uses a “time base” circuit to create a regular, recurring periodic signal that can be used to automatically change a circuit’s state (or in this case, select certain signals for use at certain times). Most digital circuits use such time bases, often called “clocks”; these circuits and applications are discussed more fully in upcoming projects. For now, a brief explanation is provided below.
A stable time base can be created by driving an electro-mechanical circuit into a stable resonance, and then using that stable resonance to create an equally stable oscillating electric signal. The oscillating signal, called clock, regularly and repeatedly transitions between Vdd and GND at some frequency. A clock signal can be used by other circuits to coordinate and synchonize their output signal changes. Circuits that use a clock to coordinate state changes are called “synchronous” circuits, and in fact, the most useful digital circuits are synchronous (e.g., computers). One simple synchronous circuit is called a binary counter.
A counter is a synchronous digital circuit that counts clock signal oscillations, and outputs a binary number that shows the current count value. Since the counter’s output binary number changes (increments) each time the clock signal toggles, all the counter’s output bits toggle as well, but at lower frequencies (output bit0 of the counter toggles at one-half the clock signal’s toggle rate, output bit1 at one-quarter the clock’s rate, output bit2 at one-eight the rate, etc.). Counter output bits can be used as lower frequency clock signals, and that’s how they are used in this project. In a later project, we’ll examine sequential circuits, counters, and clock signals in detail. For now, you can just copy and use the Verilog code shown.
On the Boolean board, the main oscillator circuit creates a 100MHz clock signal. That’s a relatively high-speed signal, but a counter can be used to create lower-frequency clock signals. Note the counter block in the figure below, and the Verilog code below that. Counter output B0 in the figure is driven by counter bit 25 in the Verilog code, and so it toggles at a rate of (100MHz / 2^(25+1)), or (100,000,000 / 67,108,864), which is 1.5Hz. Counter outputs B1 and B2 in the figure therefore toggle at .75Hz and .375Hz respectively, which is slow enough to see.
1. Mux and Demux circuit
Create a mux-demux transmission system that can transmit the state of the eight slide switches to 8 LEDs using only one data wire (and three address wires). Connect the eight slide switches to the inputs of an 8:1 mux, connect the mux output to a RED led and the enable input of a 3:8 decoder, and connect the 3:8 decoder outputs to 8 green LEDs. Then create a clock divider/counter module by copying the provided code, and connect the 3-bit counter output to the multiplexor select inputs and the decoder inputs (the clock circuit will cycle through all the data inputs about 100 times per second). Program the Boolean board with your circuit, and verify that it functions correctly. The block design of your module is shown below. The tutorial will help guide you through the necessary steps: TUTORIAL: Mux Demux System
module counter ( input clk, output Y2, Y1, Y0 ); reg [27:0] counter; always @ (posedge clk) begin counter <= counter + 1; end assign Y2 = counter; assign Y1 = counter; assign Y0 = counter; endmodule
2. Design and Implement Single Digit Seven-Segment Display Decoder
Design and implement a seven-segment decoder circuit,
bin2seg that can drive a single digit on the DISP0 4-digit 7sd device on the Boolean board. Your decoder should display the decimal digits 0-9 for bit patterns 0000-1001, and A-F for bit patterns 1010-1111 (you will need to get a little bit creative to show all of the hex digits - think about lower-case letters). Use four slide switches as inputs to select the pattern to be displayed. Recall that you will need to drive the anode signal of the digit you wish to use to GND (you can drive the others to Vdd to ensure they are off - note that if you drive all of the anode signals to GND, then all four digits will show the same pattern). Figure 1 displays a decoder for a seven segment display.
3. Design and Implement Two-Digit Seven-Segment Display Decoder Using a Button
Adding to your circuit from the previous section, create a circuit that can drive a second digit on the 7 segment display device with a new digit pattern defined by the other four slide switches on your board. Since there are only seven signals available to drive the digit segments, you need only one
bin2seg component to drive those signals, and a 2:1 “bus multiplexer" to choose which set of switches are connected to the
bin2seg component. The signal used to select which switches drive the display can also be used to select which digit is enabled - using the same signal for both purposes ensures the correct data will always appear on the same display digit. A push button can be used to drive the select signal. Figure 2 below shows the two-digit seven-segment display Decoder using a button.
1. Design and Implement Two-Digit Seven-Segment Display Decoder Using a Counter
In previous sections, the push button was used to select which data will be displayed on which digit. However, in a fully functional seven segment display, different data should be displayed on all digits at the same time. To do that, you need to take the same step as in requirement 1 - use a counter to cycle through all of the selection patterns at a reasonable speed. Here is the source code of a counter module you can use:
module counter ( input clk, output Y ); reg [27:0] counter; always @ (posedge clk) begin counter <= counter + 1; end assign Y = counter; endmodule
Implement the top level module according to the diagram shown below in Fig. 3.