Computer Laboratory

Course pages 2014–15

Advanced Computer Design

Exercise 3 - Nios and Qsys

Background Information

The following instructions will fast track you through using Altera's Quartus and Qsys tools. More detailed information has been provided for the Part 1b undergraduates attending the second year ECAD+Architecture practical classes - see the:

This year (2013/2014) we have new equipment - the VEEK-MT from Terasic - which replaces the tPad which is still used in the ECAD+Arch labs mentioned above. This was a late change, so the instructions for use have had to be changed in a rush. Apologies if there are rough edges.

Using Altera NIOS processor

  1. untar the following base project into a suitable place in your home file space: /usr/groups/ecad-labs/ACS-ACD/quartus/VEEK_MT_NIOS.tgz, e.g. using:
    tar xvfz /usr/groups/ecad-labs/ACS-ACD/quartus/VEEK_MT_NIOS.tgz
  2. there is some Bluespec code in PixelStream/ which is used to drive the multitouch LCD. Please build it vis:
    cd PixelStream;make;cd ..
  3. Start up Quartus (setup your path to the tools and run "quartus &")
    • don't attempt to upgrade if it asks
    • if you are asked for license information:
      • goto Tools → License Setup...
      • Under License file, enter: 27012@lmserv-altera.cl.cam.ac.uk and then hit Tab and you should find that, under Current License, it should say something like the License Type = Full Version, Subscription Expiration = 2040.12.
    • Open project: File → Open project... and select VEEK_MT_NIOS.qpf
    • Since we're going to add Bluespec components, we will need to tell Quartus where the Verilog library is for its components (FIFOs, etc.). Assignments → Settings... then click on Libraries in the category menu and the Global Library Name: /usr/groups/ecad/bluespec/current/lib/Verilog and click on Add
  4. Let's start with an outline Quartus project for the VEEK-MT FPGA boards:
    • if you click on the "Files" tab in the Project Navigator window (top left) you should see:
      • toplevel.sv - SystemVerilog top-level file for the project
      • toplevel.qsf - pin and chip definitions (i.e. mapping physical pins to useful names)
      • toplevel.sdc - Synposis style timing constraints file so that the FPGA tools know what clock frequency is being used
      • VEEK_MT_qsys/synthesis/VEEK_MT_qsys.qsys - configuration file for Qsys project with the NIOS processor system
    • a path to the Verilog component of the Bluespec library has been setup
  5. Now let's open Qsys to see our processor setup:
    • Tools → Qsys
  6. Inside Qsys, File → Open and select VEEK_MT_qsys.qsys. Now view the design. It contains:
    • a phase-locked-loop (PLL) to generate a 100MHz system clock from the 50MHz reference clock, etc. - see the ECAD lab 1 for details.
    • You'll be modifying the design in a bit, but for now just:
    • click on the Generation tab and hit the Generate button to create the Verilog for the design.
    • wait for it to finish and close Qsys
  7. Back on Quartus:
    • synthesize the design: Processing → Start Compilation (or hit ctrl-L)
    • plug in your FPGA board (usb and power) and program it (Tools→Programmer)
    • you might want to check the status of the jtagd daemon using "quartus_pgm -l"
  8. Start the NIOS II IDE (in Quartus: Tools → Nios II Software Build Tools for Eclipse) to create some software:
    • set the workspace directory to software inside your project directory and select it.
    • create a new software project and board support package (BSP = libraries to help with board specific devices)
      • File → New → NIOS Application and BSP from Template
        • browse for the SOPC information file and select VEEK_MT_NIOS.spocinfo
        • this contains information on the base addresses of devices, the amount of memory, etc.
        • set name of project avalontimer
        • leave other options as their default (example which runs without an OS)
        • click Finish
    • you now have an outline project with some sample code
    • build everything (which includes generating system specific library headers) using Project → Build All
    • let's try it on the board:
      • Select the generated binary file
      • Run → Run...
      • double-click on "NIOS II Hardware"
      • hit Run
    • you should see "Hello from NIOSII!" in the terminal window
  9. Now we're going to add our own Bluespec device "AvalonTimer"
    • copy the tree: /usr/groups/ecad-labs/ACS-ACD/bluespec-examples/AvalonTimer into your project directory
    • cd AvalonTimer then take a look at the files and do a make build to create mkAvalonTimer.v
    • N.B. the Makefile was created using makemakefile AvalonTimer.bsv mkAvalonTimer modelsim since Altera use Modelsim for simulation quite a bit so the Verilog produced by Bluespec for Modelsim is likely to work well with the Altera/Quartus synthesis system. An additional flag -aggressive-conditions was added to BSCFLAGS in the Makefile to ask the compiler to use aggressive conditions on rules which means that rules can fire even if some implicit conditions are not true provided they are guarded by a conditional.
    • start Qsys and open the VEEK_MT_qsys.qsys file again
      • hit the New... button under Component Library window
      • under the Component Type tab, set the name to mkAvalonTimer
      • hit the Files tab
        • in the "Synthesis Files" section, add the AvalonTimer/mkAvalonTimer.v file
        • hit "Analyse Synthesis Files"
      • look at the Signals and Interfaces tabs to see what it going on
        • in Interfaces look at the s0 section and set the Associated Reset to clockreset_reset
      • click Finish and say yes to the assocaited TCL file being created
      • mkAvalonTimer is now in the Component Library, so Add... it to our design
        • hover your mouse over the wiring in Connections and connect mkAvalonTimer_0 to:
          • clockreset connects to c0 on the clock_generator (the main system clock)
          • clockreset_reset connects to clk_reset on the external_clk_50MHz
          • s0 connects to data_master on the nios2_qsys_0
          • in the Export column, click on the click to export for conduit_end_0 and name it leds
        • Do System → Assign base addresses to assign the new device a suitable base address
        • generate the new design
        • look under the HDL Example see an example instantiation of this project. You'll see that we now have .leds_export at the bottom which we'll need to add to our toplevel.sv
        • close Qsys
      • Back in Quartus:
        • look in toplevel.sv where we instantiate VEEK_MT_qsys and add the newly exported signals vis: .leds_export({LEDR,LEDG})
        • also comment out the previous default assignment to LEDR and LEDG (near the bottom of toplevel.sv)
        • resynthesis the design as before, then download to the board.
      • Now we're going to drive the timer from software - fire up NIOS-IDE
        • first regenerate the BSP since the hardware has changed - in the Project Explorer pane, right click on the avalontimer_bsp and select NIOS-II → Generate BSP
        • rebuild the code ctrl-B
        • look at system.h in the BSP and you'll find hardware specific parameters including the base address of the new timer: MKAVALONTIMER_0_BASE
        • now use the following example code which makes use of system.h for hardware parameters and io.h for low-level read/write operations that bypass the cache
#include <stdio.h>
// library with hardware specific parameters
#include <system.h>
// low-level input/output library
#include <io.h>



void set_timer(int t)
{
    // write t directly to the device bypassing the processor's cache
    IOWR_32DIRECT(MKAVALONTIMER_0_BASE, 0, t);
}

int read_timer()
{
    // read the timer directly from the device bypassing the processor's cache
    return IORD_32DIRECT(MKAVALONTIMER_0_BASE, 0);
}

void stop_timer()
{
    // stop timer by writing 0 to word address 1 of the device (byte address 4)
    IOWR_32DIRECT(MKAVALONTIMER_0_BASE, 4, 0);    
}

void start_timer()
{
    // start timer by writing 1 to word address 1 of the device (byte address 4)
    IOWR_32DIRECT(MKAVALONTIMER_0_BASE, 4, 1);    
}

int read_and_stop_timer()
{
    return IORD_32DIRECT(MKAVALONTIMER_0_BASE, 4);
}


int main()
{
  printf("Starting timer test\n");

  printf("stop timer and set to zero, then read out\n");
  stop_timer();
  set_timer(0);
  printf("timer = %d\n",read_timer());
  printf("timer = %d\n",read_timer());
  printf("start timer\n");
  start_timer();
  printf("timer = %d\n",read_timer());
  printf("timer = %d\n",read_timer());
  printf("read and stop = %d\n",read_and_stop_timer());
  printf("timer = %d\n",read_timer());

  return 0;
}

Assessment

Based on AvalonTimer, create "AvalonFib" which computes fib in hardware. It should accept a source operand by writing it to a special location and provide the result via a load from a location. Write a C helper function with interface int fib(int n); which uses the hardware to compute the function.

Optional

Create and Avalon Master

The Avalon2ClientServer package also includes an Avalon master module. Use this to create a memory mapped device which scans through a region of memory performing some function on that memory (e.g. summing up all of the data). The device should have an Avalon Slave interface to communicate with the processor and an Avalon master interface which is used to scan through memory.

Try command-line builds

A Makefile is provided to perform command-line builds. Try:
make cleanall
time make
make download

Try graphical output

Try using the multitouch screen via the PixelStream Bluespec module included in this design. You can find some driver software here:
/usr/groups/ecad-labs/ACS-ACD/quartus/PixelStreamSoftware/