Computer Laboratory

Course pages 2012–13

Advanced Computer Design Exercise - 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:

Using Altera NIOS processor

  1. unzip the following base project into a suitable place in your home file space: /usr/groups/ecad-labs/ACS-ACD-1213/quartus/tPad_NIOS.zip
  2. 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, the License Type = Full Version", Subscription Expiration = "2040.12.
    • Open project: File -> Open project... and select tPad_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
  3. Let's start with an outline Quartus project for the tPad 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
      • tPad_NIOS.qsys - Qsys project with the NIOS processor system
    • a path to the Verilog component of the Bluespec library has been setup
  4. Now let's open Qsys to see our processor setup:
    • Tools -> Qsys
  5. Inside Qsys, File -> Open and select tPad_NIOS.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 Generate tab and hit the Generate button to create the Verilog for the design.
    • wait for it to finish and close Qsys
  6. 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"
  7. 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 Template
        • select NIOS II C/C++ application, click OK
        • browse for the SOPC information file and select tPad_NIOS.spocinfo
        • this contains info. on 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:
      • Run->Run...
      • double-click on "NIOS II Hardware"
      • hit Run
    • you should see "Hello from NiosII!" in the terminal window.
  8. Now we're going to add our own Bluespec device "AvalonTimer"
    • copy the tree: /usr/groups/ecad-labs/ACS-ACD-1213/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 again
      • hit the '''New...''' button under Componet Library window
      • hit the "HDL Files" tab
        • hit '''Add...''' and select {{{AvalonTimer/mkAvalonTimer.v}}}
        • this should import cleanly but with one warning
        • 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''' which should then remove the warning
        • 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 -> Auto 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 '''.timer_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 tPad_NIOS and added the newly exported signals vis: .timer_leds_export({LEDR,LEDG})
          • 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 // library with hardware specific parameters
#include // low-level input/output library
#include 


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

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.