Lab 02: Checkoff 02 (ALU)

Fall 2023

The questions below are due on Wednesday September 13, 2023; 11:59:00 PM.
 
You are not logged in.

Please Log In for full access to the web site.
Note that this link will take you to an external site (https://shimmer.mit.edu) to authenticate, and then you will be redirected back to this page.
A Python Error Occurred:

Error on line 5 of Python tag (line 6 of source):
    kerberos = cs_user_info['username']

KeyError: 'username'

Goals: Implement an ALU and learn how to testbench for debugging.

Make sure you've done checkoff 01 beforehand! We'll be building off the work from checkoff 01 in this section.

Ok for the second part of this lab, we'll implement an ALU (Arithmetic Logic Unit).

An "Approximate" Schematic of what we're building first. Note this is not totally accurate since there are some control electronics between the FPGA and the seven segment display.

The ALU will take in two 8 bit numbers:

  • Number 0 (n0) is taken from the lower eight bits of the switch array (sw[7:0])
  • Number 1 (n1) is taken from the upper eight bits of the switch array (sw[15:8])

The buttons btn[2:0] will be used to select from one of eight operations:

  • (3'b000): Addition: n1 + n0
  • (3'b001): Subtraction: n1 - n0
  • (3'b010): Multiplication: n1 * n0
  • (3'b011): Division: n1 / n0 (integer division)
  • (3'b100): Remainder: n1 % n0 (modulo)
  • (3'b101): Bitwise AND: n1 & n0
  • (3'b110): Bitwise OR: n1 | n0
  • (3'b111): Bitwise XOR: n1 ^ n0

The result of this calculation should be displayed using the 16 green LEDs (led[15:0]).

In addition two other checks will always be performed:

  • Equality: n1 == n0 with its result presented on rgb0[2]
  • Greater than: n1 > n0 with its result presented on rgb1[0]
Test Benching

Below we've provided a basic testbench for you to locally develop and simulate this ALU. You might say, "I don't need to do a testbench or simulate, I'll just code this up and iMmEdIaTeLy run a Vivado build." These are famous last words. Many an all-nighter has begun with similar thoughts. Test benching/simulating your code sucks because you have to write more code, but it sucks way less than the making miniscule changes and then waiting hours for a hardware build to happen.

"Ten hours of hardware debugging saves you ten minutes of simulation." -A bad engineer

A testbench file is still Verilog, but it is not synthesizable Verilog. It is meant for simulation. Consequentely a testbench file should be thought of more as a regular program file that "runs". Starts at the top and goes in order as you go down. There are still rules and things, of course, but it should feel more natural to you coming from a Python/C existence in terms of its ordering/causality.

One of the great difficulties in Verilog is that it was originally meant to be a simulation language and was then bent into the Hardware Description Language role. It isn't the end of the world, but always try to keep track of the two types of files:

  • Synthesizable Verilog (files that we use to describe hardware). You will never see any sort of "time" in synthesizable Verilog
  • Simulation Verilog (testbenches). This Verilog will have a concept of time, and is meant to run and test in simulation synthesizable Verilog files.
// set the timestep on the internal simulation clock
`timescale 1ns / 1ps
`default_nettype none

//The timescale specifies the timestep size (1ns) and time resolution of rounding (1ps)
//we'll usually use 1ns/1ps in our class

module alu_tb();

  //make inputs and outputs of appropriate size for the module testing:
  logic [7:0] d0_in;
  logic [7:0] d1_in;
  logic [2:0] sel_in;
  logic [15:0] res_out;
  logic gt_out;
  logic eq_out;

  //create an instance of the module. UUT= unit under test, but call it whatever:
  //always use named port convention when declaring (it is much easier to protect from bugs)
  alu uut(.d0_in(d0_in), .d1_in(d1_in), .sel_in(sel_in),
      .res_out(res_out), .gt_out(gt_out), .eq_out(eq_out));
  //All simulations start with the the "initial block's top
  // They then run forward in order like regular code.
  //lines that are one after the other happen "instaneously together"
  //Time passes using the # notation. (#10 is 10 nanoseconds)
  // set the initial values of the module inputs
  initial begin
    d0_in = 0; //set d0_in to 0
    d1_in = 0; //same for d1_in
    sel_in = 0; //same for sel_in

    // Extremely Important!
    // Even though the system is combinatorial-only, make sure some simulation time runs before analyzing outputs
    #10; //wait 10 ns
    //now print something:
    $display("\n---------\nStarting Simulation!");
    d0_in = 12; //change values!
    d1_in = 45;

    // run through all operations and monitor outputs
    $display("d1_in      d0_in     sel_in  res_out           eq_out  gt_out");
    for(integer i = 0; i < 8; i = i + 1) begin
        sel_in = i; //set sel_in
        #10; //wait for a bit of time (10 ns)
        //then evaluate outputs:
        $display("%8b   %8b  %3b     %15b  %b       %b", d1_in, d0_in, sel_in, res_out, eq_out, gt_out);
    end

    $display("\n---------\nFinishing Simulation!");
    $finish; //finish simulation.
  end
endmodule // alu_tb

If you place the testbench file in your sim folder, from the root of your project folder, you can do:

iverilog -g2012 -o sim/alu.out sim/alu_tb.sv hdl/alu.sv

and then

vvp sim/alu.out

and outputs should appear. Use and expand and modify this starting test case above to make sure your module is doing all the right operations when needed. Try a variety of input numbers! During Checkoff 2 you will be required to show your test case is testing your system working with at least the following input pairs of numbers for all eight operations:

  • d0=0 and d1=0
  • d0=100 and d1=10
  • d0=10 and d1=100
  • d0=42 and d1=42
  • d0=7 and d1=42

When you feel confident that your module is working, run it in the checker below. Do not just write your code in the checker without testing locally.

Putting it on the Hardware

If you've done a rigorous job testing your design in simulation, then we should be ready to deploy it onto hardware.

Make an instance of your alu module inside your current top_level module. Comment out the following three lines that are currently there, since you'll now be controlling those three sets of LEDs from your ALU. directly. :

  assign led = sw;
  assign rgb0[0] = 1'b1; //red channel of RGB LED 0
  assign rgb1[2] = 1'b1; //blue channel of RGB LED 1

In addition, so you don't get distracted by the seven segment LEDs for this stage, change the values of ss0_an and ss1_an to all be 1! This will turn off all the seven segment LEDs. Build, upload and make sure it works like the video below shows. Complete the integration of your ALU module into your FPGA so that it takes inputs and outputs from all the appropriate sinks and sources like shown in the video below.

Checkoff 2:
Show your testbench testing everything. Demonstrate your final stystem working to a staff member.