Lab 1: Warmup & Instruction fetch -> Register read

Last updated 1/11 11:33am

Due: Jan 20nd -- check up. MANDATORY that you meet with the TAs and discuss your progress.

Fully due Jan 30th. NOTE UPDATED DEADLINE

Updated Sunday 1/26

Part 1: (HARDWARE TRACK only)

The primary purpose of this part is to make sure all of the pieces of your tool chain are working for you. Start by downloading the "starter.tar" file from the course webpage. This bundle contains several files of note:

    top.v      This is the top level Verilog module for the chip
    
    cpu.v      This is where you put your CPU design
        
    debug_console.py  This is the debug console.  Run by typing "python ./debug_console.py" after
               Your design has been downloaded to the board.  Each time you download
               a design to your board you will need to run this console program again.
               And be sure to exit from this script *before* downloading a new design.
    
    usb/       This directory contains all of the USB interfacing code.
               You shouldn't need to edit anything here.

    SConstruct This is a "scons" file (equivalent to a Makefile).

    pins.pcf   This defines where pins on the FPGA go.  You shouldn't need to edit this.

    apio.ini   This is just a configuration file for the build tool (apio).

To get started please look at work through the TinyFPGA BX tutorial here. In particular you need all of the associate tools (apio, scons, icestorm, iverilog, and tinyprog). For good measure, it is also useful to have verilator installed.

After working through the BX tutorial, reset your board by hitting the button on it. Then go to the directory where you unpacked the starter.tar files. Type

    apio build
    apio upload

    python ./debug_console.py
If it works you should see it print out hex numbers continuously. If it does not work, try starting the debug console again. Sometimes it takes USB a bit to connect and run the software stack on your computer. If it doesn't work, contact Mark or the TA's for help. Sometimes the place and route tool fails to route a design that meets the USB timing requirements. When this happens there's a way to re-run the P&R tool with a different random seed and get it to work.

Frequent places where things go wrong:

TinyFPGA BX does not come with a cable. SOME cables do not route data pins, only power. If you connect the board and you can't program it, try a new board. I have a lot of cables if you need one. Just ask me.

Part 2: HW & SW track Instruction fetch through register read

In this part you are going to design the front end of your processor. In particular, instruction fetch and register read. Semantically your code needs to do the following:

    1. inst = code_memory[pc]
    2. pc = pc + 4
    ----clock cycle boundary
    3. if (inst == branch)
    4.     pc = compute_target(pc, inst)
    
    5. r1 = register_file(rm(inst));
    6. r2 = register_file(rn(inst));

To decode the above code snippet lines 1-4 represent the instruction fetch and 5-6 represent register read. Line 1 represents fetching the current instruction from instruction memory using the current value of PC. Then lines 2-4 represent updating PC either by PC + 4 or by PC + branch_value at the next positive edge of the clock depending on whether the current instruction is a branch or not. Lines 5-6 represents reading out two values from the register file (which values are readout depends on the instruction).

You must decode and partially process the following instructions: B (Branch) including all of the condition codes, BL, MOV, MVN, LDR, STR, ADD, SUB, CMP, TST, TEQ, EOR, BIC, ORR. For now you do not need to support instructions that require three register reads or two register writes.

On a branch you should discard the instruction that is fetched that is after the branch.

To demonstrate that your Verilog works use the debug ports to output useful information. For example, you can fill the register file with useful information using an initial block and program the code memory with instructions that read various registers.

Software track: To demonstrate your code works, print out the instruction and some decoded informaton about it. Inputs, outputs, etc.

Hardware track: You can then pipe bits from the register file to the debug ports. Similarly, you can decode the constant that is contained in the instruction and then pipe bits of this constant to the debug ports. Remember it is incumbent on you to ensure your design works and to be able to demonstrate that it works with sufficient tests that you can show to the instructors.

As previously stated, I encourage you to use "behaviorial synthesis". But follow a trust but verify model. Write clean Verilog, but look at what is getting synthesized. In particular pay close attention to LUT and BRAM usage. You will want to periodically run the P&R tool manually like this:

     ~/.apio/packages/toolchain-icestorm/bin/arachne-pnr -d 8k -P cm81 -p pins.pcf -o hardware.asc hardware.blif
And study the output. In particular the output right near the top where it says "After packing". Look at LC usage and BRAM usage. When you add the register file to your design you want it to use BRAMs and not LCs. So watch these counts before/after adding that part of your design.

1/26 Update

There has been quite a lot of questions about what I mean by "decode a few things". It is intentionally vague. What I intend for you to do in this lab is build the instruction memory and the register file. Then to show that you are reading instructions correctly and accessing the register file correctly, to decode and print out semantically useful things about the instructions and the contents of the register file the instructions access. But that raises the question "what sorts of semantically useful things?" For this I only specified the condition codes and register fields. But I also specified a few instructions. It is sufficient for this lab for you to print out what the instruction is (ADD, B, etc), what the condition code is (AL, EQ, etc), and what the register fields are. Note that I also asked you to process unconditional branches. The purpose of this is so you can write a simple loop and stick that in your instruction memory and have it print out useful things continiously.

Here's a made up example of a possible output your code. Note that yours does not have to look like this at all, I'm just showing a reasonable option:

    PC: 0x0000000   AL     ADD    R4    R4=0x00000000  R5=0x00001000
    PC: 0x0000004   AL     B      0005
Your output need not be pretty. Remember you are demonstrating this to the TA's for the grade. So you will get a chance to explain what your output means to them.

If your design does not output anything to the debug ports, there are a number of things that could be at fault. One of them that may vary well be it is the debugger did not synthesize correctly. While the debugger is based on the TinaFPGA bootloader code, this code relies on a USB Verilog implementation that is, eh, a work in progress. What I have found useful to try is to pass different random seed values to the place and router tool. In other words, re-run the tools likes this:

     ~/.apio/packages/toolchain-icestorm/bin/arachne-pnr -d 8k -P cm81 -p pins.pcf -o hardware.asc -q hardware.blif -s 2

     apio upload

     python ./debug_console.py