Description
The case statement, Adders and ALUs
Learning Objectives
In this lab you will design (a) multiplexers using the case statement, (b) a simple ripple-carry adder, and (c) an Arithmetic Logic Unit (ALU), a fundamental component of each processor. You will also gain more practice with hierarchical design in Verilog and with using binary and hexadecimal numbers.
Marking Scheme
Each lab is worth 4% of your final grade, but you will be graded out of 8 marks for this lab, as follows.
• Prelab + Simulations: 3 marks
• Part I (in-lab): 1 mark
• Part II (in-lab): 1 mark
• Part III (in-lab): 3 marks
Preparation Before the Lab
Carefully review the background section below, as well as the “Preparation Before the Lab” instructions in the Lab 2 handout.
You are required to complete Parts I to III of the lab by writing and testing your Verilog code. Show your schematics, Verilog code, and simulations for Parts I to III to the teaching assistants. You must simulate your circuit with ModelSim using reasonable test vectors written in the format described in Lab 2 and Lab 3 handouts. The term test vector simply refers to one combination of inputs that you will use to test your design. Each simulation should consist of multiple test vectors, sufficient to demonstrate that your design functions as intended.
In-lab Work
You are required to implement and test all of Parts I to III of the lab. You need to demonstrate all parts to the teaching assistants. As a reminder, the device name is 5CSEMA5F31C6 from the Cyclone V family.
Background
Representing Constants
Verilog has a specific notation for representing constants (i.e., literal values). The following code snippet creates a 1-bit wire named a, which is connected to ground (logic-0).
wire a; assign a = 1’b0; The number before the single quote is a decimal number representing the bit width (i.e., the number of binary digits, also known as bits). This is 1 for a single wire, but is higher for a bus (i.e., a collection of wires). The letter after the single quote is called the radix. Its possible values are letters b, d, h, or o to specify whether the value that follows is in binary, decimal, hexadecimal, or octal notation. (Octal representation is rarely used.) Lastly, the value after the radix is the number in that numerical representation.
For example, 2’b10 corresponds to decimal number two, while 8’h1a (or 8’h1A) to decimal number 26. The latter is written in binary as 8’b0001_1010 and in decimal as 8’d26. Verilog allows you to use underscores to separate groups of bits to improve readability. Here we separated groups of 4-bits as they each correspond to a single hexadecimal digit. Note that underscore characters are optional.
More Verilog Operators
This section presents various Verilog operators that you might find useful for this lab.
• Arithmetic Operators: + (addition), – (subtraction), * (multiplication), / (division), % (remainder), ** (exponentiation).
• Reduction Operators: These are unary operators that reduce a vector to a single bit value. The operators are: & (AND all bits), | (OR all bits), and ˆ (XOR all bits). You can prepend ˜ to any of these to get reduction NAND, NOR and XNOR operators respectively. An example of a reduction AND operation is & 3’b010 which is equivalent to an AND operation between all three bits of the value 3’b010, and will produce 1’b0. Similarly, & 3’b111 will produce 1’b1.
• Concatenation: Verilog uses curly braces for concatenation. For example, {2’b01, 1’b1} will produce 3’b011. Concatenation can be used in both the left hand side, and the right hand side of an assignment statement.
• Replication: {n{m}} will replicate n-times the value m. For example, {3{2’b01}} is equivalent to 6’b010101.
More Advanced ModelSim commands
The wave.do file in Lab 2 contained simple ModelSim commands that forced a signal to logic 0 or logic 1 (e.g., force {SW[0]} 0), followed by run commands that ran the simulation for a predetermined number of nanoseconds before applying a different test vector. However this approach does not scale well as your designs become more complex and have more inputs. ModelSim allows you to apply a periodic signal to your simulation’s inputs which makes creation of test vectors much easier.
The format of a more advanced force command is the following:
force {<signal_name>} <initial value> <initial time>, <new value> <new time>
-repeat <repeat time> -cancel <cancel time>
This will set the signalname to initial value at initial time after the current time and will set it to new value time new time after the current time. This square wave will repeat repeat time after the current time and you can choose to cancel it at cancel time. In all cases, you can explicitly specify the time quantum in your force command (e.g., by writing ns) after any time value. You can use shorthands -r and -c instead of -repeat and -cancel.
Here is an example of test vectors for two 1-bit inputs a and b. Notice that the square wave applied to b has twice the period of the square wave applied to a, thus modeling all four possible input combinations, the same way they’d be present in a truth table.
force {a} 0 0, 1 20 -repeat 40 force {b} 0 0 ns, 1 40 ns -r 80
Also do not forget to use -timescale 1ns/1ns as an argument to the vlog command, as we did in the wave.do file provided in Lab 2. The -timescale switch tells ModelSim what the default time unit is when no unit is specified (first number), and what the smallest unit of time to simulate should be (second number).
Part I
For this part of the lab, you will learn how to use always blocks and case statements to design a 7-to-1 multiplexer.
An always block allows us to describe a circuit using behavioral style, using case and if statements. However, the circuit produced from this description still consists of basic logic gates.
Any identifier that appears on the left hand side of the equal (=) sign inside an always block must have been declared as a reg type in the module containing the always block. Please note that you cannot use a wire for this purpose.
The model Verilog code for a 7-to-1 multiplexer built using a case statement is shown below. The seven inputs are from the signals named Input[6:0]. The output is called Out, and it is declared as a reg type, as explained above. The select lines are called MuxSelect[2:0].
reg Out; // declare the output signal for the always block
always @(*) // declare always block begin case (MuxSelect[2:0]) // start case statement
3’b000: Out = Input[0]; // case 0
3’b001: Out = Input[1]; // case 1
3’b010: Out = Input[2]; // case 2
3’b011: … // case 3
3’b100: … // case 4
3’b101: … // case 5
3’b110: … // case 6
default: …
endcase end // default case
The always block uses an asterisk in the sensitivity list to indicate that the block describes combinational logic, i.e., any logic where the outputs rely strictly on the inputs. You will learn more about combinational and sequential logic later. For now, use the asterisk in the always block for a case statement as shown above.
Using SW6−0 as the data inputs and SW9−7 as the select signals, display on LEDR0 the output of a 7-to-1 multiplexer using the case statement style as shown above.
2. Write Verilog code for a 7-to-1 multiplexer, based on the template provided above. Use switches SW9−7 on the DE1-SoC board as the MuxSelect inputs and switches SW6−0 as the Input data inputs. Connect the output to LEDR0. (PRELAB)
4. Create a new Quartus Prime project for your circuit. Make sure it is stored in your W: drive.
5. Compile the project.
6. In Quartus Prime, select Tools > Netlist Viewers > RTL Viewer and observe the circuit that got produced from your Verilog code. Note that Quartus uses slightly different symbol for the multiplexer than what you have seen in class: select inputs are denoted by name instead of being drawn from the top of the symbol.
Part II
Figure 1(a) shows a circuit for a full adder, which has the inputs a, b, and ci, and produces the outputs s and co. Parts b and c of the figure show a circuit symbol and truth table for the full adder, which produces the two-bit binary sum cos = a + b + ci. Please note that the + operator here means addition and not logic OR. Figure 1(d) shows how four instances of this full adder module can be used to design a circuit that adds two four-bit numbers. This type of circuit is called a ripple-carry adder, because of the way that the carry signals are passed from one full adder to the next. Write Verilog code that implements this circuit, as described below. Be sure to use what you learned about hierarchy in Lab 2.
Perform the following steps:
2. Write a Verilog module for the full adder subcircuit and write another Verilog module that instantiates four instances of this full adder. Name the input ports A, B and cin, and the output ports S and cout. Note: You should NOT use the arithmetic addition operator + in your Verilog implementation of the full-adder. Doing so will earn you 0 marks for this part. (PRELAB)
Figure 1: A ripple-carry adder circuit.
4. Create a new Quartus Prime project for the adder circuit. Make sure it is stored in your W: drive. In the new top-level module, use switches SW7−4 and SW3−0 to connect to inputs A and B respectively. Use SW8 for the carry-in, cin, of the adder. Connect the outputs of the adder, cout and S, to the LEDs LEDR9 and LEDR3:0 respectively.
5. Compile the project.
6. In Quartus Prime, select Tools > Netlist Viewers > RTL Viewer and observe the circuit that got produced from your Verilog code. Try expanding modules in the diagram, and selecting different hierarchy levels in the Netlist Navigator on the left.
Part III
Using Part II from this lab and the HEX decoder from Lab 2 Part III, you will implement a simple Arithmetic Logic Unit (ALU). An ALU has two data inputs and can perform multiple operations on the data inputs such as addition, subtraction, logical operations, etc. The output of the ALU is selected by function inputs that specify the function to be performed by the ALU. The easiest way to build an ALU is to implement all required functions and connect the outputs of the functions to a multiplexer. Choose the output value for the ALU using the ALU function inputs to drive the multiplexer select lines. The output of the ALU will be displayed on the LEDs and HEX displays.
Shown in the case statement below are the operations to be implemented in the ALU for each function value in pseudo code format. The ALU has two 4-bit inputs, A and B and an 8-bit output, called ALUout[7:0]. Note that in some cases, the output will not require the full 8 bits so do something reasonable with the extra bits, such as making them 0 so that the value is still correct. Adding zeros in front of any positive number does not change the value of that number; this process is called sign-extension.
Note that it is not permissible to enclose a module instantiation inside an always block. An always block is only used to describe one part of the circuit using behavioral style (e.g., using a case statement). If you want to connect inputs or outputs of an instance of a module to the circuit described using an always block, you should create a module instance outside the always block and use wires to connect the two circuits.
always @(*) // declare always block begin case (function)
0: Make the inputs appear at the output, with A in the most significant four bits and B in the least significant four bits.
1: A + B using the adder from Part II of this Lab
2: A + B using the Verilog ‘+’ operator
3: A XOR B in the lower four bits and A OR B in the upper four bits
4: Output 1 (8’b00000001) if at least 1 of the 8 bits in the two inputs is 1 using a single OR operation 5: Output 1 (8’b00000001) if there is an even number of high bits in both the two inputs A and B together.
default: … // default case, output 0
endcase
end
The A and B inputs connect to switches SW7−4 and SW3−0 respectively. Use KEY2−0 for the function inputs. Display ALUout[7:0] in binary on LEDR7−0; have HEX0 and HEX2 display the values of B and A respectively in hexadecimal and set HEX1 and HEX3 to 0. HEX4 and HEX5 should display ALUout[3:0] and ALUout[7:4] respectively in hexadecimal.
Perform the following steps:
2. Write a Verilog module for the ALU including all inputs and outputs. (PRELAB)
4. Create a new Quartus Prime project for your circuit, and compile the project.
5. In Quartus Prime, select Tools > Netlist Viewers > RTL Viewer and observe the circuit that got produced from your Verilog code. Try expanding modules in the diagram, and selecting different hierarchy levels in the Netlist Navigator on the left.
Note: In your simulation, KEY3−0 are inverted. Remember that the DE1-SoC board recognizes an unpressed pushbutton as a value of 1 and a pressed pushbutton as a 0.
Reviews
There are no reviews yet.