Practical 4: Verilog Modules

Objectives

This is not a list of tasks for you to do. It is a list of skills you will have or things you will know after you complete the lab.

Following completion of this lab you should be able to:

Guidelines

Time Estimate This practical will take approximately 6–8 hours per student, varying depending on your familiarity with Verilog. Even if you do not have a full grasp of programming in Verilog, this practical is designed to bring you up to comprehensive understanding upon completion.

Preliminary Tasks

Install ModelSim and VSCode Extensions

This practical, and all remaining practicals, will be implemented using Verilog and tested in ModelSim. If you have ModelSim already installed (via Quartus), check that you have the correct version of ModelSim INTEL FPGA STARTER EDITION 10.5b (comes with Quartus Prime 18.1). You can check this by launching ModelSim, then go to Help → About ModelSim.

If you do not have ModelSim version 10.5b...

If you do not have ModelSim installed, go to Intel’s Website to download ModelSim. Do not download Quartus that is defaulted on the website. You will only need ModelSim, not the entire Quartus Software Suite. We will be looking for the ModelSim standalone download in the Individual Files tab:

Download ModelSim-Intel® FPGA Edition (includes Starter Edition) under the Intel® Quartus® Software section. Launch and run the installer, and verify that you have installed INTEL FPGA STARTER EDITION 10.5b.

Modify modelsim.ini

The unit testing tools you will be using for this practical and all remaining practicals will require you to turn on ModelSim messages. This is required.

Navigate to the ModelSim directory on your machine. It is usually in one of these locations:

In the modelsim_ase folder you will find a file called modelsim.ini. You may need to show file extensions to see the full name of this file. Open this file in a text editor and append the following two lines to the end of the file. Make sure they are both uncommented.

    msgmode = both
    displaymsgmode = both

Save and close the file. When you create a new ModelSim project, it will duplicate this file as the base settings and enable better message display to see failed/passed unit tests.

If you cannot find a modelsim.ini file in that modelsim_ase directory, you can download and save this copy of modelsim.ini by right-clicking that link, and clicking "save link as".

Install Verilog VSCode Extensions

In VSCode, install the following extensions:

More Extension Install details (optional)
  1. Click the "Extensions" button in the Activity bar (far left). It looks like this:
  2. Search for "Verilog HDL" and install one of the one by leafvmaple.
  3. The other (Verilog-HDL/SystemVerilog/Bluespec) looks like a microchip.

If you already installed these in Practical 1, then double check that they are installed

Clone your verilog-modules Git repository

You can access your practical repository verilog-modules via Github Classroom. As in past practicals, clone the repository onto your local machine via SSH. Make sure this repository is not cloned into Microsoft OneDrive. Desktop, documents, or any other local file path is acceptable.

Verilog Modules

We will start with a guided walkthrough of how to:

You will do this for all remaining practicals. Be sure to famliarize yourself with this workflow, including the occasional quirks of ModelSim. Yes, it is a lot of steps, but if you follow this procedure you will minimize the bugs you encounter and work efficiently.

1 The Register and tb_Register modules

  1. Launch VS Code, and when it's open, choose "Open Folder" either from the main window or from the File menu.
    • Navigate to your git repo and open that folder.
  2. Open a few of the Verlog files that appear in the file navigator:
    • Register.v
    • tb_Register.v
  3. Right now editing verilog is annoying in VS Code. Install the "Verilog HDL" extension to make it nicer:
  4. Navigate back to the verilog files you opened and make sure syntax coloring works.

Set up a ModelSim project

For every practical, you will need to create your own .mpf ModelSim project file. Even if you are working in a group for later practicals, each one of you need to create your own .mpf project file. ModelSim uses absolute pathing in its project settings to reference files (e.g., that path will include your machine’s username), therefore you cannot launch someone else’s .mpf file without editing it.

  1. Start ModelSim.

  2. Create a new project for this lab

    • Choose New > New Project from the File menu.
    • Set your Project Name to include your username (e.g., practical4_rosie)
    • Browse... and set the directory to be your verilog-modules-<username> repository folder.
    • Verify that Copy Settings From is set to modelsim_ase/modelsim.ini and Copy Library Mappings is selected.
    • Click OK
  3. When prompted, choose Add Existing Files to Project

    • Add all of the `.v files from your git repo to the project.
  4. Before we continue, navigate to your repository and open the .mpf project file in a text editor. This file was created when you created a new project in ModelSim. Check that you have the lines msgmode = both and displaymsgmode = both in the file. If you followed the modelsim.ini setup carefully, those lines should appear in the file; if not, you can add them manually here.

  5. Returning to ModelSim, where your project is open, make sure you can compile them. Near each file in the list, the status column should contain a blue question mark to indicate they need compiling. Choose Compile All from the Compile menu or click the "Compile All" button in the toolbar().

    Optional elaborate compiling details

    Compile via Right Click → Compile → Compile Out-of-Date (or Compile All ):

    Or use the toolbar at the top:

  6. There will be two compile errors. Double-click the red error message and modelsim will open an error message window with a verbose description. These descriptions (hidden behind double-clicking) will be extremely helpful.

    • Read the messages carefully, then find and fix the errors. While you can edit files in ModelSim, we strongly recommend you use VS Code instead because it is more powerful. (This should be a quick fix).

    • If you edit the files in VSCode (recommended), you don't have to close ModelSim. Just switch back and forth between the two programs to edit or compile.

Examining the vunit framework and the tb_Register.v test bench.

Your instructors have created a very basic unit test framework for you to use in this course called vunit. In order to use it in a verilog test bench, you make an instance of the vunit module, then execute various tasks within that instance.

Lets look at how to use vunit in a test bench.

  1. Open tb_Register.v in VS Code. Inside the tb_Register module near the top, there are a lot of definitions:

    • The module definition (see the module keyword)

    • The vunit framework instantiation (VU())

    • The clock register (reg CLK)

    • The input drivers (write_enable, reset, data_in, default_value). These are declared reg because they will hold inputs the test bench sets.

    • The wire instance data_out, which is a probe we will connect to the output of our Register unit under test so we can read its output.

    • The declaration of UUT, which is an instance of the Register module.

    • The perpetual clock code in an initial block.

      These are the main components "on" our test bench. The rest of the code in tb_Register is the testing procedure.

  2. Scroll past the three tasks declared until you get to the initial block at the bottom. It has a comment at the top that says "Run the tests". This is the main driver for our test bench, and is where you found the compiling error.

    • This has to be down at the bottom so the tasks it refers to can be found. It's annoying, sorry.
    • There are three tests that run: one to test that reset works, one to test that write-enable works, and then finally a third test that re-checks reset again.
  3. If you scroll up to the tasks you passed before, you can see each one (when it runs) will execute a specific test. These are kind of like subroutines (but not quite). Creating tasks for each test is a nice way to break up your tests so you can quickly turn them on or off by commenting them out where they get called.

Running tb_Register in ModelSim

Let's return to ModelSim and try running tb_Register. You can do this from inside your ModelSim project:

  1. First, make sure everything is compiled.

  2. Next, click the "Library" Tab in the project view:

  3. Then expand the work library and double-click tb_Register to start the simulation.

    • NOTE: if tb_Register isn't in the work library, click back to the "Project" tab, then try closing the project (in the File menu) and then open your Practical4 project file again
    Tip 1: missing test bench in library

    In the future, if you do not find the testbench you are looking for, it is likely that the module defined in the file is different from the name of the file. ModelSim uses the name of the module, not the name of the file. This might happen if you copy/paste a testbench file but forget to update the module name.

    Tip 2: fix errors before simulating.

    When you load a testbench, ModelSim may throw another set errors in the Transcript. Some of these are fatal errors — you must resolve them, recompile, and load the testbench again. Others are warnings — it will allow the testbench to run, but your behavior will often be incorrect due to these warnings resulting in undesired behaviors. Resolve all warnings before you proceed.

  4. When the simulation starts, it should open a new window with two panels: "Objects" and "Wave". If you do not see them or accidentally close them, you can load them again via View -> Objects/Wave.

  5. Populate the waveform with the signals we are interested in. In this case, it is everything except HALF_PERIOD. Make sure tb_Register is selected in the sim view, then select all of the signals in the Objects panel and drag them over to the waveform window to add them, or type ctrl+w:

  6. From here, we can run the simulation by typing run -all in the Transcript, choosing run -all from the Simulate -> Run menu, or using the button on the toolbar

    When the simulation completes, you should see a bunch of output in the transcript (bottom of the screen), and waves in the waveform.

    Tip 3: Hiding long paths in wave names

    Notice that all the objects in the Wave panel all start with /tb Register/. This clutters the panel and makes it hard to read. Click on the Wave panel, and the Wave menu option should show up at the top of the window. Go to Wave → Wave Preferences... and set the value of # elements to 1.

    Tip 4: displaying waveform signals as hexadecimal

    The values data_in, default_value, and data_out are all in binary, which is difficult to read. Let’s change the radix to be hexadecimal instead. Highlight all three items in the Wave panel → Radix → Hexadecimal:

  7. You'll quickly notice green and red triangles on the weaveform. If not, make sure the msgmode and displaymsgmode settings are in your .mpf file.
    A green triangle indicates that a test (ASSERT) passed in the test bench, and a red one means that something failed.

  8. At the top of the waves, you'll see some inverted triangles. If you don't see these, make sure the msgmode and displaymsgmode settings are in your .mpf file.

    The triangles indicate the times when messages were posted to the Transcript. The green arrow are for "info" or a successful test (the one on the left in the image below) and the red ones (on the right in the image below) corresponds to an error or failed test.

    You can hover the mouse over a triangle to learn more about the test.

    You can also Double-click a red triangle. Try it to see what happens!

  9. In the case of our tb_Register.v, the Register module is implemented correctly but the test bench has an error.

    Use the signals on the waveform and read through the transcript output and try to identify which asserts in tb_Register.v failed. HINT: only one assert fails, but it gets executed twice by the test bench.

    Tip 5: Approaching test creation with tasks

    Spend time reading both tasks in tb_Register.v. These tasks document the approach to testing modules with ModelSim. Make sure you understand how the test progresses time using (posedge CLK) / (negedge CLK). You will be writing your own tests, so familiarize yourself with this structure before proceeding

  10. Fix the broken assert so that it tests the right thing.

  11. After you resolve the error (make your edits in VSCode), you'll need to recompile the files in ModelSim. Do this the same way you compiled the first time. You may need to change from the sim tab to the project tab to get the compile buttons.

  12. After recompiling successfully, you need to restart the simulation (Restart from the Simulate menu or the restart button)

    and then execute run -all again.

  13. Verify that the red triangles and "ERROR" messages in the transcript are gone before moving on.

  14. Save your waveform config so you can quickly reuse it later if you want:

    • Click (left-click, not right-click) in the middle of the waves.
    • Choose "Save Format" or type Control-S
    • Click the "Browse..." button.
    • In the dialog that pops up, change the name of the file from wave.do to tb_Register.do
    • Click "Save", then "OK". You can later reload this by going to File > Load > Macro File... and selecting your .do file while a simulation is running.

Once you've fixed the errors in tb_Register.v, you should save your changes. Add, commit, and push the following files to your git repository. Be sure to include a message that indicates your current progress.

DO NOT add all the temporary files made by ModelSim. It'll clutter your git repo and may cause problems down the road. git commit -a will do this, so don't use -a. In VS Code, you must choose which files to stage or it will add them all by default. Do the extra step to pick which files to commit: it will save you time in the future.

3 Create and Test ImmGen

In class we talked about the Immediate Generator that looks at the bits of an instruction to figure out how to construct an immediate.

We've provided you with an ImmGen.v file that has the start of the immediate generator, but you must finish implementing it. We're also providing you with a test bench tb_ImmGen.v that has a few tests, but you need to write more tests.

As you implement each case in ImmGen, you should be testing their correctness by writing corresponding tests in tb_ImmGen.v. You should not be implementing ImmGen in its entirety without doing any tests for individual instruction formats.

  1. If your simulation of tb_Register is still running, end that (Simulate > End Simulation menu item).
  2. Implement one type of instruction at a time in the ImmGen.
  3. For each instruction type, be sure there are at least two tests in tb_ImmGen.v to test that type of instruction. We've given you a couple for the first type of instruction (I-Types).
  4. (Q) Come up with a strategy for constructing tests. How will you know when you've tested enough? Explain how these tests substantially check enough variations for you to be confident that your ImmGen module will work for all input variation.

Follow these guidelines:

Tip: aliases for subsections of an instruction

You may create wire busses and assign them to various bits of the instruction as shorthand for subfields of an instruction. You must do this outside of any initial, task, or always blocks. For example:

wire [6:0] opcode;
assign opcode = instruction[6:0];
// now you can use "opcode" instead of "instruction[6:0]" to refer to the same bits.

You might consider doing this for the various instruction fields rs1, rs2, rd, etc.

Tip: concatenating busses in verilog

To concatenate values in verilog, put them in braces separated by commas. For example:

{12'hF00, 12'h123} // evaluates to the 24-bit value, 0xF00123
Tip: replicating (duplciating) values in verilog

You can make copies of bits in verilog (to sign extend, for example) using the replication operator:

{24{opcode[1]}} // evaluates to 24 copies of bit 1 of the opcode bus
Tip: always recomputing outputs when the input changes

Notice that this module's output is a reg. Since the immediate generator is not clocked and constructs the immediate "instantaneously", we would assume the output should be a wire and defined via assign. This is correct, however defining the entirety of imm as a single assign statement is non-trivial since we cannot use case or if/elseif statements.

Instead, the output imm is defined as a reg, but instead of defining it in a clocked always @(posedge CLK) block, we define it in an always @(instruction) block :

always @ ( instruction ) begin
    ...
end

This allows us to use the coding niceties of using a case statement and still emulate the behavior of an instantaneous assign statement. This tells Verilog to re-calculate the output value imm whenever the input instruction changes, which is basically an assign statement created as an always block. You will use this strategy to define other modules in the future (e.g., control unit, ALU, branch detection, etc.).

  1. (Q) Once you've implemented and tested ImmGen, you need to create a screenshot and annotation that shows your tb_ImmGen passes tests. Take a screenshot of the waveform and the transcript window (as shown below). Add at least three annotations to your screenshot to indicate what exactly you are testing at which sections on the waveform. Include this annotated screenshot in your worksheet submission.

  2. Add, commit, and push the following files to your git repository. Be sure to include a message that indicates your current progress.

    • tb_ImmGen.v (The edited test bench)
    • tb_ImmGen.do (if you created a waveform, add and commit it)
    • ImmGen.v (The edited ImmGen module)
    • Practical4.mpf (Your updated ModelSim project file)

4 Single and Dual Port Memory

Next, you will see how RAM is constructed and pre-populated with values (such as your machine code) in ModelSim.

Looking at Single Port Memory

In VS code, open up SP_Memory.v.

This is a basic RAM module that was autogenerated by Quartus. It is word-addressed (not byte-addressed), and each address is 10 bits long (not 32). This physical module is much smaller than a 32-bit processor supports, so we will have to engineer around that in the future.

There are two very important details about this memory module:

  1. parameter DATA_WIDTH=32 indicates that this module is word-addressed (32 bits of data per address). This is in contrast to RISC-V’s memory being byte- addressed (8 bits of data per address).
  2. parameter ADDR_WIDTH=10 indicates that this module is addressable with only 10-bits (232 rows of memory). This is in contract to RISC-V’s memory being 32-bit addressable.

The reason of this setup is because ModelSim cannot handle a ram declaration consisting of 232 rows of memory; ModelSim simply refuses to compile something so expansive. Instead, we create a ram module with 210 rows that is more comfortable for ModelSim. While this is substantially less than RISC-V’s full 32-bit addressable memory, it is enough for us to simulate small benchmark programs.

However, we are able to bulk up our memory by mapping each of the 210 addresses of ram to 32-bits (1 RISC-V word) instead of the standard 8-bits that follows RISC-V’s memory setup. This quadruples our memory without making ModelSim explode. There is very little actual code in this file, it is mostly comments. The comments explain how to create an intialization file. You can read them now or later.

Tip 6: Sketch out the address mapping for RISC-V

Before continuing, we highly encourage you to sketch out both RISC-V’s 32-bit addressable memory with 1 byte rows as well as Verilog’s 10-bit addressable memory with 4 byte rows. Understanding the differences in data and address width is imperative for the next and future practicals as you wire together a full RISC-V single-cycle processor. Feel free use the diagram below to get started:

Looking at Dual Port Memory

Open DP_Memory.v in VS Code next.

This is a version of memory that has two sets of inputs, two sets of outputs, and two clock inputs. Effectively it is two memories that share contents. Notice that it looks very similar to SP_Memory except:

Testing memory with tb_memory.v

Open up tb_memory.v. This is a test bench for both memories.

The structure of this test bench is similar to the one for the register, but there are two different modules instantiated. One is called sp_ram and one is called dp_ram.

  1. Take time to read through the two tasks, test_singleport_memory() and test_dualport_memory() to get familiar with what this test bench is testing. These are completed tests and you don't have to modify anything, but you should get famliar with how to use verilog to directly inspect the contents of modules. This technique will be useful for future practicals.

  2. Your next job is to run the test in ModelSim. Compile and start the simulation like you did for tb_Register, but this time start tb_memory.

    • When you run -all, you should see in the transcript that tests completed and none failed.

  1. Next you should configure a waveform to help you visualize both memory instances. YOU MUST configure it in this exact order because it will correspond to a worksheet question.

    1. Start by adding the signal CLK to your waveform.

    2. Next, select all the signals in the tb_memory instance that start with sp_ (shift-click or control-click to select many). Then drag them to the wave view or type Control-W to add them.

    3. When they appear in the wave panel, they will all be selected. With all of them selected, right click one of them and choose Group.... Name the group "Single Port RAM".

    4. Repeat for the dual-port connections (they start with dp_).

    5. Restart and run your simulation again. Now you should have pretty waves!

      • At this point, you may want to change some of the values on the waveform to use hexadecimal radix so they're a little easier to read. Right click them and select from the "Radix" menu to change how they are interpreted.
    6. Make sure your resulting waveform resembles the image below (click it for a bigger one):

    7. Save your waveform as tb_memory.do to avoid repeating these steps.

    8. (Q) In the lab worksheet, there is a waveform that is incomplete. Draw what you expect to come out given the inputs provided (you are adding the missing parts of the dp_q_a and dp_q_b signals). Remember that dual port memory has two clocks, and port B is activated on the falling edge of the other clock. Draw the missing signals to show what you expect the outputs to change (and write in their new values).

Completing the test_dualport_bothports() task

Currently the test_dualport_bothports task is commented out in the intial block at the bottom of the test bench. This means it doesn't run!

  1. Uncomment the two lines so that test_dualport_bothports task runs after the $info task.
  2. Restart and run the tb_memory tests and note that there will be some failures. This is because the tests are incomplete!
  3. Edit the test_dualport_bothports task to complete part 2, verifying that your waveform is correct. You can use the waveform you completed in the lab worksheet as a guide.
  4. Keep in mind that the SP_memory tests are running before the ones for DP_memory, make sure you're looking at the right parts of the waveform as you debug!
  5. Ensure that all 19 tb_Memory tests pass (review the transcript output in ModelSim)

Add, commit, and push the following files to your git repository. Be sure to include a message that indicates your current progress.

5 Create RegFile and tests

Okay, you're mostly on your own for this module. You must create a register file and test it. We'll give you the specifications, and you can choose how you want to implement and test it, but you MUST test all features of the register file. You will be using this module during future practicals, so you want it to work properly.

  1. First, create a RegFile.v file and declare a RegFile module in that file.

    • Your register file should contain 32 general purpose registers, with one exception: the zero register should always be equal to zero.
    • It will have the following inputs:
      • regnum_a - a 5-bit register specifier to read, usually this will be "rs1"
      • regnum_b - a 5-bit register specifier to read, usually this will be "rs2"
      • write_regnum - a 5-bit register specifier of which register to write ("rd", for example)
      • data_in - a 32-bit value to write into write_regnum
      • write_enable - a one-bit value that indicates whether or not to write data to write_regnum
      • reset - a one-bit value that indicates whether or not to reset the register file's contents
      • CLK - a one-bit clock signal
    • It will also have two outputs
      • regdata_a - a 32-bit value that was read from regnum_a
      • regdata_b - a 32-bit value that was read from regnum_a
    • On the rising edge (posedge) of the clock, the register file will write from data_in into the register specified by write_regnum, but only if write_enable is set to 1.
      • except if write_regnum is 0; register 0 should never change.
    • If reset is set to 1 at the rising edge, all registers should be set to zero except for register 2, which should be set to 0xfffffff0.
    • regdata_a and regdata_b continuously update and read the registers specified by regnum_a and regnum_b respectively. (IMPORTANT: This is an async read).

    Here's a picture of what you're building:

  2. (Q) Explain what purpose the RegFile will serve when you implement a processor. Where is the source of values connected to RegFile's regnum_a, regnum_b, and write_regnum inputs? Where will the outputs go?

Tip: Making an array of Registers

You can create the registers inside your regfile either as native reg data types, or using the Register module from this lab.

Also, consider looking at the ram array in memory for an example.

  1. Write tests to sufficiently test all functionality of your register file. Write tests for each part you implement as you implement the register file.

    Consider the following testing milestones to be written as individual tasks in your testbench:

    • Testing reset behavior,
    • Testing asynchronous read from regadata_a and regdata_b,
    • Testing writing behavior when write_enable=1,
    • Testing writing behavior when write_enable=0,
    • Testing writing behavior when write_regnum=0.

    In addition to these standard unit tests that checks for basic RegFile behavior, write a larger test that substantially tests RegFile — test reading/writing to all 32 registers and combinations with write_enable and reset.

    Tip: Initialize register values from test bench

    You can directly set the values of the RegFile contents in the testbench:

     task test_example();
     begin
         UUT.REGES[1] = 32'h00000001;
         UUT.REGES[2] = 32'h00000002;
         UUT.REGES[3] = 32'h00000003;
         UUT.REGES[4] = 32'h00000004;
     end
     endtask

    This allows you to test reading behavior without needing to modify them via REGES[write_regnum] = write_data syntax.

    Knowing how to directly change reg content values in the testbench will allow you to test lw and sw instructions very easily in later practicals. Commit this to memory!

    Tip: Use loops to automate similar tests

    You can use integer and repeat to set up loops to automate checks:

     integer i;
     task test_example();
     begin
         i = 0;
         repeat (32) begin
             rs1 = i;              // set value of regnum_a
             rs2 = i;              // set value of regnum_b
             #1;                   // wait for regdata_a and _b to update
             VU.ASSERT(A === i);   // if REGES[i] = i is set up
             VU.ASSERT(B === i);   // if REGES[i] = i is set up
         end    
     end
     endtask

    You can combine this with the previous tip to very efficiently test the entirety of your RegFile.

    Tip: Inspecting register file contents on the waveform

    Being able to set the contents of REGES or any other internal storage in module is useful; it will also be able to view the contents of REGES and similar storage on ModelSim. On ModelSim you are only able to view the values of the input drivers and output wires, REGES is nowhere to be found:

    REGES is not found because REGES is not defined in tb_RegFile; it is defined in RegFile. Go to the sim tab on the very left, and select UUT or what you named the instance of your RegFile. Once you select UUT, the Objects panel should update to show every wire and reg defined in RegFile, including REGES:

    From here, you can add REGES to the waveform, expand REGES, change its radix, and directly inspect the values of each of the 32 registers. You may need to restart and run the simulation again after adding REGES to the waveform.

  2. To run your testbench in ModelSim you'll need to add the new files to your ModelSim project.

    • In the Project tab (where the files are listed and the green checkmarks for compiling are visible) right click and select "Add to Project > Existing File..." then select your RegFile.v and tb_RegFile.v to the project.
    • After adding them you can compile and run the test bench the same way you have the others.
  3. (Q) On the lab worksheet describe your strategy for constructing tests for tb_RegFile. Explain how these tests substantially check enough variations for you to be confident that your RegFile module will work for all input variation.

  4. (Q) After you've completed your tests, take a screenshot of a waveform to show at least 3 of the key tests for your register file passing.

    • Your wave form should contain all 7 of the input signals to the register file, and the values of at least 2 registers relevant to your tests. Your register values should be displayed in decimal, you should pick appropriate radix settings for the other signals.
    • Your waveform should include annotations like in the immgen sample above that show where the tests occur, as well as the console output window.

Add, commit, and push the following files to your git repository. Be sure to include a message that indicates your current progress.

Working Ahead

You cannot work ahead towards later practical as that requires teams to be formed. However, you can read ahead to Practical 5 and start planning how you would construct the RISC-V single cycle processor in Verilog.

Submission and Grading

Functional Requirements

At the end of the practical you should have done these things:

Git Requirements

In addition to the list below, you should regularly commit and push whenever you fix a bug, work to a stopping point, or make any incremental updates. At minimum, you must have at least 5 commits in your repo for this practical (one for each function):

Remember, Do not add and commit every single file ModelSim creates. Only add, commit, and push .v, .do, and .mpf files.

Worksheet Requirement

All the practicals for CSSE232 have these general requirements:

General Requirements for all Practicals

  1. The solution fits the need
  2. Aspects of performance are discussed
  3. The solution is tested for correctness
  4. The submission shows iteration and documentation

Some practicals will hit some of these requirements more than others. But you should always be thinking about them.

Complete the worksheet.

Final Checklist

Grading Breakdown

Practical 4 Rubric items Possible Points Weight
Worksheet 76 50%
Code 70 50%
Total out of 100%