Studio 4B


Overview / Reminder

  • Work in groups of 3!

Studio Setup

Follow the steps from Studio 4A! The assignment link is link

Names

Open questions.md and list the names of everyone in your group.

Fulladder: Again

Use task 2.1 to (again) complete a behavioral model of a full adder (you can use work from last studio).

A fulladder adds a single column of digits. A multi-bit adder will require adding several columns and, consequently, can be built by chaining together several full adders. For example (from Wikipedia’s Adder article):

Wikipedia's Full Adder

Recall tht you can instantiate existing parts, like the fulladder with syntax something like:

partname instance_name( .part_port(local_signal_to_connect), ... )

For example, an OR gate may have a module definition that looks something like:

module myOr(
    output logic out,
    input logic in0,
    input logic in1
);
   ...

A second module could use it like:

// in My Module
logic ored, soup, salad;
...
myOr anOr(.in0(soup), .in1(salad), .out(ored));

Note:

  • This creates a part and clearly associates the names used for the part’s ports (the out, in0, and in1 of myOr) to the names of signals in the current module (the ored, soup, and salad).
    • It would also be possible to rely on the position of signals (myOr anOr(ored, soup, salad)), but using port names for connections can significantly reduce errors because one can easily read the details of how connections are being made. For example, .clock(clock_a) would clearly indicate that clock_a is being used to provide the clock to a specific part.
  • The example is creating a single myOr instance and giving it a name of anOr. It’s possible to omit the instance name (myOr(ored, soup, salad))
    • If there were multiple instances (multiple myOrs) being created, the instance name (like anOr) can be used when debugging test benches to undertand which signals apply to a specific instance of myOr. Using a descriptive instance name is a good proactice.

Hint: Constants are commonly used in HDL and can be used directly for inputs. You’ll probably need to use one (er, or zero) here. Often it’s necessary to make sure the number of bits used for a constant matches what is needed. You can review the Verilog Number Formats section of Lecture 4A.

Use task 2.2 to simulate / test your work.

Use task 2.3 to confirm your work via a testbench.

Use task 2.4 to complete question 2.4 in questions.md

Mapping to hardware

Your kits contain an iCE40 UP5k FPGA. Review the Data sheet for the iCE40 UP5K. In particular look at Figure 3.2, whcih describes the “PLBs” in the UP5K. Until now we’ve been using HDLs to depict circuits using digital logic schmatics, which don’t exactly correspond to how the FPGA will be used.

Use task 2.5 to see how our synthesis tools utilize the FPGA. Complete question 2.4 in the questions.md

Multi-bit addition

Use task 3.1 to complete a structural model of a 4-bit adder using 4 instances of your full adder.

Caution!

Be sure to use 4 instances of the fulladder!

Use task 3.2 to simulate your work

Confirm that it can add multi-bit numbers. The inputs and outputs are no longer simple, binary value. Hovering over an input or output will allow you to use the base being used to enter or show that value:

Input Box and Base

Caution!

You must update values and then click out of the input box for the simulator to use the updated value. (If the cursor is still in the box, it isn’t clear that you are done typing a new value)

Use task 3.3 to verify your work via a testbench

Making it real

Caution!

If you have not already tested using hardware with your computer, please go through the FPGA Programming page!

Windows Caution!

Windows requires a specific device driver to correctly communicate with the UPduino. Installing the driver may be sensitive to both the specific USB port that’s used and/or the specific UPduino that’s used. Please be sure to either use the same hardware and USB port used in the past or reinstall the driver if you encounter errors (See: FPGA Programming).

Testing your adder

Task 3.5 creates a bitstream file for your four-bit adder. If done correctly, the left four push buttons will control the left most digit. The right most four push buttons will control the middle digit. Each nibble will be added, using your four-bit adder, and the result will be displayed on the rightmost digit. The carry will be shown in the decimal point of the second digit.

After generating the bitstream, upload it to your UPduino.

Led & Key Adder

State Machines

statemachine.sv

Complete code for a statemachine that implements the “Every third” behavior covered in class. (Slides). Review the example provided and be sure to use a sensitvity list on reset and clk.

Every Third

Simulate

Use the simulator to confirm that it works as expected.

A Testbench

Use task 4.3 and 4.4 to complete a test bench to verify that it works correctly.

Warning!

The testbench view that shows waveforms does not automatically update when the testbench is re-run.

  • Be sure to close the waveform view before re-running the testbench.
  • And/or if, following a testbench run, the waveforms look unchanged, close the waveform view and try one more time to confirm the behavior.
  • Be sure to also watch the Problems tab for potential syntax errors or issues. Sometimes the waveform view may open to prior results if there’s a syntax error.

You may want to review the fulladder testbench (task 2.4). It looks and behaves a lot like a traditional computer program. The initial begin block does define a set of sequential statements. It uses notation like #10 to advance the simulation time. #10 would advance the simulation 10 units of time, #5 would advance it 5 units of time, etc. It uses assignment statements to control the inputs and outputs to parts. It uses $error() tasks to indicate if/when errors occur.

Create a test that controls the reset and clock:

  1. Use a for-loop, as shown in the fulladder testbench, to iterate 10 times. (You may need to add a variable declaration!)
  2. During each iteration:
    1. Go through a clock cycle and confirm that the output is 0. (It should be in S0 at the top of the loop, so after the first full clock cycle it should be in S1). Use the $error() task to show an error message if it’s incorrect.
    2. Do another clock cycle and again check the output.
    3. And another.

If your test bench “passes” the first time, change one of the conditions being checked for an error to be deliberately wrong and re-run testbench to confirm the circuit is not behaving as the testbench expects.

Verification: Complete code to verify your work

Deploy to hardware

Task 4.5 creates a bitstream file for your statemachine. You will provide both the reset (reset) and the clock (clk) via buttons and the segements on the rightmost display will light when q is 1:

Hardware for Statemachine

Confirm:

  1. It starts in the S0 state, where q is 1: The right-most display will show an 8 when q is 1. (The decimal point on the rightmost digit merely indicates if the clock button is currently pressed. The decimal point on the next digit over indicates if reset is currently pressed)
  2. Repeatedly clocking it causes q to be 1 every third time.
  3. Answer question 4.5.

Complete question 4.6 in questions.md

Submission / End-of-class: Commit And Push

1. First, be sure to commit and push files to GitHub (as shown in studio)

1.1

Source Selection

1.2

Commit Message

Caution!

Failure to type in a commit message will cause VSCode to open a window to enter the message (in the editor area) and the Source Control pane will appear to be stuck (a waiting animation) until you type in a message and close the message pane.

1.3

Commit and Push

2. Then go to GitHub.com and confirm the updates are on GitHub

End of Studio: Stop the Codespace

Caution!

Be sure to “stop” your Codespace. You have approximately 60 hours of Codespace time per month. Codespaces often run for ~!5 minutes extra if tabs are just closed.

Codespace