Altera NIOS II jots
About this post
These are things I wrote down at different stages of introducing myself to Nios II and its environment. Nothing really consistent nor necessarily the right way to do things.
Jots
- Open Qsys. Follow this post.
- Went for Nios II classic, used Nios/e (no Hardware multiplication, as the target device doesn’t have it. Set instruction cache to 2 kB, and no data cache
- Add 16 kB on-chip memory (Basic > On-Chip Memory > On-Chip Memory (RAM or ROM) ). Data width 32 bits, set hex file to raminit.hex (to be found at verilog/raminit.hex)
- Attach memory to processor’s Avalon master
- Attach peripherals
- Connect clk_0′s clock output to all clock inputs (including processor’s).
- Same with reset
- Assign base addresses automatically: System > Assign Base Addresses
- Enter the CPU configuration, and assign the Reset and Exception Vectors to the onchip memory (this issues an offset to the addresses, per the peripheral’s offsets).
- Build the Qsys project. Among all (Verilog) files, it generates a processor.sopcinfo file.
Software
- Launch Nios II Software Build Tools for Eclipse (from Qsys or Quartus)
- Pick a path for the workspace
- Pick File > New > Nios II Application and BSP from Template. Assign the SOPC information file as processor.sopcinfo as generated before, and pick the “Hello World” template. There’s also a much smaller “Minimal Hello World” which allows communication with the JTAG UART.
- Build the project. Eh, it failed. Not enough memory (printf is heavy. There’s a thinner version, but doesn’t matter now)
- Go back to Qsys, and make on-chip memory 40960 bytes large (40kB, fitter fails if it’s 48 kB). Re-run Assign Base Addresses.
- Build the Qsys project again
- Regenerate the BSP: In Eclipse, right-click the BSP project, pick Nios II > Generate BSP (NOT from the top menu’s Nios II, there is no such option there!). Or alternatively, within a NIOS2 shell (see below), and from the BSP project’s home directory, go
nios2-bsp-generate-files --settings settings.bsp --bsp-dir .
- Rebuild: Project > Clean… and clean all, with the rebuild option set.
- To add a lot of files to a project: Right-click the project, pick Import…, General > File System. Click Browse… and navigate to the directory where the files are and pick the directory. Then choose the desired files. Pick Advanced below, and pick “Add links” (it works).
- To add an existing file to the project: Right-click the project, New > File > Advanced, check “Link to file in the file system” and pick the file. Then right-click the file (or several files) and pick “Add to Nios II build”
- To remove a file, first right-click it, and pick “Remove from Nios II build”. Then right-click and delete. Failing to remove the file first will make the build system continue to look for it.
- Creating a new application, based upon an existing BSP, and including the relevant source file sets it all up.
- To compile manually, right-click the project, go to Nios > Nios command shell… (that opens a shell window) and type “make”
- It’s also possible to copy the relevant elements in the PATH variable, and compile with “make” outside this shell window. Or set up the environment, as shown here.
- I had a stubborn linking error with alt_main.c having an undefined reference to ‘main’ because I didn’t read my own note above about how to add a file to a project. It turned out that the Makefile doesn’t include any of the C source files (C_SRCS assigned to nothing in the Makefile). I ended up adding these entries manually. That allowed at least a manual build with the command shell, as mentioned in the bullet above.
- The Eclipse project seems to consists of the Makefile, the .cproject XML file containing mostly useless mumbo-jumbo, and the .project XML file, which contains information about source files and build targets. There’s also .settings/language.settings.xml, which also seems not to contain anything relevant.
- When creating a custom component, and an interrupt is required, be sure to associate the interrupt sender interface with an “Associated Addressable Interface” (e.g. associatedAddressablePoint set to avalon_slave_0 in the component’s tcl file). Otherwise, the interrupt will no be assigned an entry nor controller, so *_IRQ and *_IRQ_INTERRUPT_CONTROLLER_ID end up assigned with -1 in system.h.
- For a shell prompt (“NIOS2 shell”) with all paths set up properly, go e.g.
/bulk/software/altera/lite-15.1/nios2eds/nios2_command_shell.sh
Running against hardware
Note: Quartus’ programmer and the “Run” environment on Eclipse are mutually exclusive, competing for the USB bitblaster.
- Make sure you’ve quit Quartus’ programmer (actually not necessary. Just be sure that the blue LED on the USB Blaster is off).
- Also make sure to “terminate launch” on the Eclipse side before attempting to reprogram the FPGA (pressing the red stop-like button on the Nios Console is enough.
- Pick the “hello” project (that is, not the BSP) and go to top menu: Run > Run configurations…, pick Target Connection tab. Both a processor and a byte stream device should be enlisted (the latter is the jtaguart). Refresh to make sure it’s actually there.
- If it says “Connected system ID hash not found on target at the expected base address” at the top, select “Ignore mismatched system ID” and “Ignore mismatched system timestamp”. This happens when there’s no system ID peripheral in the Qsys design.
- The “Hello world from NIOS!!” should appear in the Nios II console
- The base addresses etc. are listed in system.h inside the BSP (hello_bsp in my case).
- This program printed out “Hello world” as well as blinked the LEDs:
#include <stdio.h> #include <unistd.h> #include <io.h> #include <system.h> #include <altera_avalon_pio_regs.h> int main() { int i; printf("Hello from Nios II!\n"); while (1) { IOWR_ALTERA_AVALON_PIO_DATA(PIO_BASE, ((-i) & 7)); i++; usleep(100000); } return 0; }
- To generate a hex file, right-click the project (“hello”) and pick Make Targets > Build…, chooise mem_init_generate and click the Build button. The juicy part in the process was
elf2hex hello.elf 0x00010000 0x00019fff --width=32 --little-endian-mem --create-lanes=0 mem_init/raminit.hex
- Alternatively, go (skip to the “make” statement if already in a NIOS shell)
/path/to/altera/15.1/nios2eds/nios2_command_shell.sh make mem_init_generate
- It noteworthy that the tools spotted my choice of the file name, even though it’s not located where Quartus expects it.
- Giving the hex file to Quartus resulted in a lot of lines saying
Warning (113015): Width of data items in "raminit.hex" is greater than the memory width. Wrapping data items to subsequent addresses. Found 1280 warnings, reporting 10 Warning (113009): Data at line (2) of memory initialization file "raminit.hex" is too wide to fit in one memory word. Wrapping data to subsequent addresses. Warning (113009): Data at line (3) of memory initialization file "raminit.hex" is too wide to fit in one memory word. Wrapping data to subsequent addresses. Warning (113009): Data at line (4) of memory initialization file "raminit.hex" is too wide to fit in one memory word. Wrapping data to subsequent addresses.
etc.
But this is most probably OK, as the processor worked immediately after FPGA configuration. - Redirect printf() and other stdout to UART: By default, the standard output goes to the JTAG UART. To change this, right-click the BSP project, pick Nios II > BSP Editor. Pick the “Main” tab, navigate to “hal > common” (it usually starts there anyhow) and change the stdout target to the desired UART. And regenerate the BSP.