0% found this document useful (0 votes)
20 views

DE0-Nano-SoC Computer NiosII

This document describes a computer system implemented on the Intel DE0-Nano-SoC development board for use in computer organization and embedded systems experiments. The system contains two Nios II processors, memory components including DDR3 and on-chip memory, peripherals like analog-to-digital converters and accelerometers, and I/O ports connected to switches and lights. The system utilizes both the FPGA and Hard Processor System on the Cyclone V SoC chip, with the Nios II processors and peripherals in the FPGA and an ARM Cortex A9 dual-core processor in the HPS.

Uploaded by

cointoin
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views

DE0-Nano-SoC Computer NiosII

This document describes a computer system implemented on the Intel DE0-Nano-SoC development board for use in computer organization and embedded systems experiments. The system contains two Nios II processors, memory components including DDR3 and on-chip memory, peripherals like analog-to-digital converters and accelerometers, and I/O ports connected to switches and lights. The system utilizes both the FPGA and Hard Processor System on the Cyclone V SoC chip, with the Nios II processors and peripherals in the FPGA and an ARM Cortex A9 dual-core processor in the HPS.

Uploaded by

cointoin
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 42

DE0-Nano-SoC Computer System

with Nios® II

For Quartus® Prime 17.1

1 Introduction
This document describes a computer system that can be implemented on the Intel® DE0-Nano-SoC development and
education board. This system, called the DE0-Nano-SoC Computer, is intended for use in experiments on computer
organization and embedded systems.

To support these beginning experiments, the system contains a processor, memory, an analog-to-digital converter, an
accelerometer and some simple I/O peripherals. The FPGA programming file that implements this system, as well
as its design source files, can be obtained from the University Program section of Intel’s web site.

2 DE0-Nano-SoC Computer Contents


A block diagram of the DE0-Nano-SoC Computer system is shown in Figure 1. As indicated in the figure, the
components in this system are implemented utilizing both the FPGA and the Hard Processor System (HPS) inside
Intel’s Cyclone® V SoC chip. The FPGA implements two Nios II processors and several peripheral ports: memory,
timer modules, analog-to-digital, and parallel ports connected to switches and lights. The HPS comprises an ARM*
Cortex* A9 dual-core processor and a set of peripheral devices. Instructions for using the HPS and ARM processor
are provided in a separate document, called DE0-Nano-SoC Computer System with ARM Cortex-A9.

2.1 Nios® II Processor

The Intel Nios II processor is a 32-bit CPU that can be implemented in an Intel FPGA device. Two versions of the
Nios II processor are available, designated economy (/e) and fast (/f). The DE0-Nano-SoC Computer includes two
instances of the Nios II/f version, configured with floating-point hardware support.

An overview of the Nios II processor can be found in the document Introduction to the Intel Nios II Processor,
which is provided in the University Program’s web site. An easy way to begin working with the DE0-Nano-SoC
Computer and the Nios II processor is to make use of a utility called the Intel® FPGA Monitor Program. It provides
an easy way to assemble/compile Nios II programs written in either assembly language or the C language. The
Monitor Program, which can be downloaded from Intel’s web site, is an application program that runs on the host
computer connected to the DE0-Nano-SoC board. The Monitor Program can be used to control the execution of code
on Nios II, list (and edit) the contents of processor registers, display/edit the contents of memory on the DE0-Nano-
SoC board, and similar operations. The Monitor Program includes the DE0-Nano-SoC Computer as a predesigned
system that can be downloaded onto the DE0-Nano-SoC board, as well as several sample programs in assembly
language and C that show how to use the DE0-Nano-SoC Computer’s peripherals. Some images that show how the
DE0-Nano-SoC Computer is integrated with the Monitor Program are described in Section 7. An overview of the

Intel Corporation - FPGA University Program 1


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

Host computer

... USB DE0-Nano-SoC Arduino


Peripherals Blaster Board port

ARM
Cortex A9 JTAG Cyclone V Parallel
Ports Nios II
ports FPGA ports
MPCore (2)

FPGA Bridges
Cyclone V
Timers Timers On-chip
HPS
memory

Port Port DDR3 Parallel Parallel Port Parallel


port ports ports ports

DDR3 LEDG7-0
G-Sensor LEDG chips SW3-0 Expansion
KEY KEY1-0 ADC ports

Figure 1. Block diagram of the DE0-Nano-SoC Computer.

Monitor Program is available in the document Intel® FPGA Monitor Program Tutorial, which is provided in the
University Program web site.

All of the I/O peripherals in the DE0-Nano-SoC Computer are accessible by the processor as memory mapped
devices, using the address ranges that are given in the following subsections.

2.2 Memory Components

The DE0-Nano-SoC Computer has a DDR3 port, as well as three memory modules implemented using the on-chip
memory inside the FPGA. These memories are described below.

2.2.1 DDR3 Memory

The DE0-Nano-SoC Computer includes a 1 GB DDR3 memory that is connected to the HPS part of the Cyclone® V
SoC chip. The memory is organized as 256M x 32-bits, and is accessible using word accesses (32 bits), halfwords,
and bytes. The Nios II processor can access the DDR3 memory through the FPGA bridge, using the addresses space
0x40000000 to 0x7FFFFFFF.

2 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

2.2.2 On-Chip Memory

The DE0-Nano-SoC Computer includes a 32-Kbyte memory that is implemented inside the FPGA. This memory is
organized as 8K x 32 bits. This memory is accessible by both Nios II processors using addresses 0x08000000 to
0x08007FFF.

2.2.3 On-Chip Memories

The DE0-Nano-SoC Computer includes two additional 32-Kbyte memories that are implemented in the Cyclone V
FPGA chip. Each of these memories is organized as 8K x 32 bits, and can be accessed using either word, halfword,
or byte operations. Each Nios II processor is connected to only one of these memories and can access the memory
in the address range 0x00000000 to 0x00007FFF. Each Nios II processor uses this memory to access its reset and
exception code, as well as other code or data.

2.3 Parallel Ports

There are several parallel ports implemented in the FPGA that support input, output, and bidirectional transfers of
data between the Nios II processor and I/O peripherals. As illustrated in Figure 2, each parallel port is assigned
a Base address and contains up to four 32-bit registers. Ports that have output capability include a writable Data
register, and ports with input capability have a readable Data register. Bidirectional parallel ports also include a
Direction register that has the same bit-width as the Data register. Each bit in the Data register can be configured
as an input by setting the corresponding bit in the Direction register to 0, or as an output by setting this bit position
to 1. The Direction register is assigned the address Base + 4.

Address 31 30 ... 4 3 2 1 0

Base Input or output data bits Data register

Base + 4 Direction bits Direction register

Base + 8 Mask bits Interruptmask register

Base + C Edge bits Edgecapture register

Figure 2. Parallel port registers in the DE0-Nano-SoC Computer.

Some of the parallel ports in the DE0-Nano-SoC Computer have registers at addresses Base + 8 and Base + C, as
indicated in Figure 2. These registers are discussed in Section 3.

2.3.1 Green LED Parallel Port

The green lights LED7−0 on the DE0-Nano-SoC board are driven by an output parallel port, as illustrated in Figure 3.
The port contains an 8-bit Data register, which has the address 0xFF200000. This register can be written or read
by the processor using word accesses, and the upper bits not used in the registers are ignored.

Intel Corporation - FPGA University Program 3


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

Address

0xFF200000 Unused ... Data register


31 8 7 0

LED7 LED0

Figure 3. Output parallel port for LED.

2.3.2 Slider Switch Parallel Port

The SW3−0 slider switches on the DE0-Nano-SoC board are connected to an input parallel port. As illustrated in
Figure 4, this port comprises a 4-bit read-only Data register, which is mapped to address 0xFF200040.

Address

0xFF200040 Unused ... Data register


31 4 3 0

SW3 SW0

Figure 4. Data register in the slider switch parallel port.

2.3.3 Pushbutton Key Parallel Port

The parallel port connected to the KEY1−0 pushbutton switches on the DE0-Nano-SoC board comprises three 2-bit
registers, as shown in Figure 5. These registers have the base address 0xFF200050 and can be accessed using word
operations. The read-only Data register provides the values of the switches KEY1−0 . The other two registers shown
in Figure 5, at addresses 0xFF200058 and 0xFF20005C, are discussed in Section 3.

Address 31 30 ... 4 3 2 1 0

0xFF200050 Unused KEY1-0 Data register

Unused Unused

0xFF200058 Unused Mask bits Interruptmask register

0xFF20005C Unused Edge bits Edgecapture register

Figure 5. Registers used in the pushbutton parallel port.

4 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

2.3.4 Expansion Parallel Port

The DE0-Nano-SoC Computer includes two bidirectional parallel ports that are connected to the JP1 and JP7 40-
pin headers on the DE0-Nano-SoC board. These parallel ports include the four 32-bit registers that were described
previously for Figure 2. The base address of the port for JP1 is 0xFF200060, and for JP7 is 0xFF200070. Figure 6
gives a diagram of the 40-pin connectors on the DE0-Nano-SoC board, and shows how the respective parallel port
Data register bits, D 31−0 , are assigned to the pins on the connector. The figure shows that bit D 0 of the parallel port
is assigned to the pin at the top right corner of the connector, bit D 1 is assigned below this, and so on. Note that
some of the pins on the 40-pin header are not usable as input/output connections, and are therefore not used by the
parallel ports. Also, only 32 of the 36 data pins that appear on each connector can be used.
JP1 JP2
Pin 1 D0 Pin 1 D0
D1 D1
D2 D3 D2 D3
D4 D5 D4 D5
D6 D7 D6 D7
Unused Unused
D8 D9 D8 D9
D10 D11 D10 D11
D12 D13 D12 D13
D14 D14
D15 D15
D16 D17 D16 D17
D18 D19 D18 D19
D20 D21 D20 D21
Unused Unused
D22 D23 D22 D23
D24 D25 D24 D25
D26 D27 D26 D27
D28 D29 D28 D29
D30 D31 Pin 40 D30 D31 Pin 40

Figure 6. Assignment of parallel port bits to pins on JP1 and JP7.

2.3.5 Arduino* Expansion Parallel Port

The DE0-Nano-SoC Computer includes a bidirectional parallel port that is connected to the Arduino* Uno R3 ex-
pansion header on the DE0-Nano-SoC board. This parallel port includes the four 32-bit registers that were described
previously for Figure 2. The base address of the port is 0xFF200100. The Data register bits in this port are con-
nected to the Arduino expansion header User I/O. Thus, bit 0 in the Data register connects to the signal Arduino_IO0,
bit 1 to Arduino_IO1, and so on.

The DE0-Nano-SoC Computer also includes a one-bit output port that is connected to the Arduino Uno R3 expansion
header on the DE0-Nano-SoC board. This one-bit port has a data register that is connected to the Arduino_Reset_N
signal on the DE0-Nano-SoC board. The address of this port is 0xFF200110.

More details about the Arduino Uno R3 expansion header can be found in the DE0-Nano-SoC Board User Manual.

Intel Corporation - FPGA University Program 5


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

2.3.6 Using the Parallel Ports with Assembly Language Code and C Code

The DE0-Nano-SoC Computer provides a convenient platform for experimenting with Nios II assembly language
code, or C code. A simple example of such code is provided in the Appendix in Listings 1 and 2. Both programs
perform the same operations, and illustrate the use of parallel ports by using either assembly language or C code.

The code in the figures displays the values of the SW switches on the LED lights. A rotating pattern is displayed on
the LEDs. This pattern is rotated to the left by using a Nios II rotate instruction, and a delay loop is used to make
the shifting slow enough to observe. The pattern can be changed to the values of the SW switches by pressing a
pushbutton KEY. When a pushbutton key is pressed, the program waits in a loop until the key is released.

The source code files shown in Listings 1 and 2 are distributed as part of the Intel® FPGA Monitor Program. The
files can be found under the heading sample programs, and are identified by the name Getting Started.

2.4 JTAG* Port

The JTAG* port implements a communication link between the DE0-Nano-SoC board and its host computer. This
link can be used by the Intel Quartus® Prime software to transfer FPGA programming files into the DE0-Nano-
SoC board, and by the Intel® FPGA Monitor Program, discussed in Section 7. The JTAG port also includes a UART,
which can be used to transfer character data between the host computer and programs that are executing on the
Nios II processor. If the Intel® FPGA Monitor Program is used on the host computer, then this character data is sent
and received through its Terminal Window. The programming interface of the JTAG UART consists of two 32-bit
registers, as shown in Figure 7. The register mapped to address 0xFF201000 is called the Data register and the
register mapped to address 0xFF201004 is called the Control register.

Address 31 ... 16 15 14 . . . 11 10 9 8 7 ... 1 0

0xFF201000 RAVAIL RVALID Unused DATA Data register

0xFF201004 WSPACE Unused AC WI RI WE RE Control register

Figure 7. JTAG UART registers.

When character data from the host computer is received by the JTAG UART it is stored in a 64-character FIFO.
The number of characters currently stored in this FIFO is indicated in the field RAVAIL, which are bits 31−16 of the
Data register. If the receive FIFO overflows, then additional data is lost. When data is present in the receive FIFO,
then the value of RAVAIL will be greater than 0 and the value of bit 15, RVALID, will be 1. Reading the character
at the head of the FIFO, which is provided in bits 7 − 0, decrements the value of RAVAIL by one and returns this
decremented value as part of the read operation. If no data is present in the receive FIFO, then RVALID will be set
to 0 and the data in bits 7 − 0 is undefined.

The JTAG UART also includes a 64-character FIFO that stores data waiting to be transmitted to the host computer.
Character data is loaded into this FIFO by performing a write to bits 7−0 of the Data register in Figure 7. Note
that writing into this register has no effect on received data. The amount of space, WSPACE, currently available in
the transmit FIFO is provided in bits 31−16 of the Control register. If the transmit FIFO is full, then any characters
written to the Data register will be lost.

6 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

Bit 10 in the Control register, called AC, has the value 1 if the JTAG UART has been accessed by the host computer.
This bit can be used to check if a working connection to the host computer has been established. The AC bit can be
cleared to 0 by writing a 1 into it.

The Control register bits RE, WE, RI, and WI are described in Section 3.

2.4.1 Using the JTAG* UART with Assembly Language Code and C Code

Listings 3 and 4 give simple examples of assembly language and C code, respectively, that use the JTAG UART.
Both versions of the code perform the same function, which is to first send an ASCII string to the JTAG UART, and
then enter an endless loop. In the loop, the code reads character data that has been received by the JTAG UART, and
echoes this data back to the UART for transmission. If the program is executed by using the Intel® FPGA Monitor
Program, then any keyboard character that is typed into the Terminal Window of the Monitor Program will be echoed
back, causing the character to appear in the Terminal Window.

The source code files shown in Listings 3 and 4 are made available as part of the Intel® FPGA Monitor Program.
The files can be found under the heading sample programs, and are identified by the name JTAG UART.

2.5 Interval Timers

The DE0-Nano-SoC Computer includes a timer module implemented in the FPGA that can be used by the Nios II pro-
cessor. This timer can be loaded with a preset value, and then counts down to zero using a 100-MHz clock. The
programming interface for the timer includes six 16-bit registers, as illustrated in Figure 8. The 16-bit register at
address 0xFF202000 provides status information about the timer, and the register at address 0xFF202004 allows
control settings to be made. The bit fields in these registers are described below:

• TO provides a timeout signal which is set to 1 by the timer when it has reached a count value of zero. The TO
bit can be reset by writing a 0 into it.

• RUN is set to 1 by the timer whenever it is currently counting. Write operations to the status halfword do not
affect the value of the RUN bit.

• ITO is used for generating interrupts, which are discussed in section 3.

• CONT affects the continuous operation of the timer. When the timer reaches a count value of zero it auto-
matically reloads the specified starting count value. If CONT is set to 1, then the timer will continue counting
down automatically. But if CONT = 0, then the timer will stop after it has reached a count value of 0.

• (START/STOP) is used to commence/suspend the operation of the timer by writing a 1 into the respective bit.

The two 16-bit registers at addresses 0xFF202008 and 0xFF20200C allow the period of the timer to be changed by
setting the starting count value. The default setting provided in the DE0-Nano-SoC Computer gives a timer period
of 125 msec. To achieve this period, the starting value of the count is 100 MHz × 125 msec = 12.5 × 106 . It is
possible to capture a snapshot of the counter value at any time by performing a write to address 0xFF202010. This
write operation causes the current 32-bit counter value to be stored into the two 16-bit timer registers at addresses
0xFF202010 and 0xFF202014. These registers can then be read to obtain the count value.

Intel Corporation - FPGA University Program 7


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

Address 31 . . . 17 16 15 ... 3 2 1 0

0xFF202000 Unused RUN TO Status register

0xFF202004 Unused STOP START CONT ITO Control register

0xFF202008 Not present Counter start value (low)


(interval timer has
0xFF20200C 16-bit registers) Counter start value (high)

0xFF202010 Counter snapshot (low)

0xFF202014 Counter snapshot (high)

Figure 8. Interval timer registers.

A second interval timer, which has an identical interface to the one described above, is also available in the FPGA,
starting at the base address 0xFF202020.

Each Nios II processor has exclusive access to two interval timers.

2.6 Analog-to-Digital Conversion Port

The Analog-to-Digital Conversion (ADC) Port provides access to the eight-channel, 12-bit analog-to-digital con-
verter on the DE0-Nano-SoC board. As illustrated in Figure 9, the ADC port comprises eight 12-bit registers
starting at the base address 0xFF204000. The first two registers have dual purposes, acting as both data and control
registers. By default, the ADC port updates the A-to-D conversion results for all ports only when instructed to do so.
Writing to the control register at address 0xFF204000 causes this update to occur. Reading from the register at ad-
dress 0xFF204000 provides the conversion data for channel 0. Reading from the other seven registers provides the
conversion data for the corresponding channels. It is also possible to have the ADC port continually request A-to-D
conversion data for all channels. This is done by writing the value 1 to the control register at address 0xFF204004.
The R bit of each channel register in Figure 9 is used in Auto-update mode. R is set to 1 when its corresponding
channel is refreshed and set to 0 when the channel is read.

Figure 10 shows the connector on the DE0-Nano-SoC board that is used with the ADC port. Analog signals in the
range of 0 V to the VCC 5 power-supply voltage can be connected to the pins for channels 0 to 7.

8 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

Address 31 ... 16 15 14 12 11 ... 0

0xFF204000 Unused R Unused Channel 0 / Update

0xFF204004 Unused R Unused Channel 1 / Auto-update

0xFF204008 Unused R Unused Channel 2

... not shown

0xFF20401C Unused R Unused Channel 7

Figure 9. ADC port registers.

Gnd Ch7
Ch6 Ch5
Ch4 Ch3
Ch2 Ch1
Ch0 Vcc5

JP15

Figure 10. ADC connector.

Intel Corporation - FPGA University Program 9


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

2.7 Floating-point Hardware

The Nios II processor in the DE0-Nano-SoC Computer includes hardware support for floating-point addition, sub-
traction, multiplication, and division. To use this support in a C program, variables must be declared with the type
float. A simple example of such code is given in Listing 14. When this code is compiled, it is necessary to pass
the special argument -mcustom-fpu-cfg=60-2 to the C compiler, to instruct it to use the floating-point hardware
support.

2.8 G-Sensor

The DE0-Nano-SoC Computer includes a 3D accelerometer (G-sensor) that is connected to the HPS. The Nios II pro-
cessor can access this device via an I2C serial interface at the base address 0xFFC04000. More details can be found
in the tutorial Using the DE0-Nano-SoC Accelerometer with Nios II, available from Intel’s FPGA University Program
website.

2.9 System ID

The system ID module provides a unique value that identifies the DE0-Nano-SoC Computer system. The host
computer connected to the DE0-Nano-SoC board can query the system ID module by performing a read operation
through the JTAG port. The host computer can then check the value of the returned identifier to confirm that the DE0-
Nano-SoC Computer has been properly downloaded onto the DE0-Nano-SoC board. This process allows debugging
tools on the host computer, such as the Intel® FPGA Monitor Program, to verify that the DE0-Nano-SoC board
contains the required computer system before attempting to execute code that has been compiled for this system.

3 Exceptions and Interrupts


The reset address of the Nios II processor in the DE0-Nano-SoC Computer is set to 0x00000000. The address used
for all other general exceptions, such as divide by zero, and hardware IRQ interrupts is 0x00000020. Since the
Nios II processor uses the same address for general exceptions and hardware IRQ interrupts, the Exception Handler
software must determine the source of the exception by examining the appropriate processor status register. Table
1 gives the assignment of IRQ numbers to each of the I/O peripherals in the DE0-Nano-SoC Computer. The rest of
this section describes the interrupt behavior associated with the interval timer, parallel ports, and serial ports in the
DE0-Nano-SoC Computer.

3.1 Interrupts from Parallel Ports

Parallel ports implemented in the FPGA in the DE0-Nano-SoC Computer were illustrated in Figure 2, which is
reproduced as Figure 11. As the figure shows, parallel ports that support interrupts include two related registers
at the addresses Base + 8 and Base + C. The Interruptmask register, which has the address Base + 8, specifies
whether or not an interrupt signal should be sent to the processor when the data present at an input port changes
value. Setting a bit location in this register to 1 allows interrupts to be generated, while setting the bit to 0 prevents
interrupts. Finally, the parallel port may contain an Edgecapture register at address Base + C. Each bit in this register
has the value 1 if the corresponding bit location in the parallel port has changed its value from 0 to 1 since it was

10 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

I/O Peripheral IRQ #


Interval timer 0
Pushbutton switch parallel port 1
Second Interval timer 2
JTAG port 8
JP1 Expansion parallel port 11
JP7 Expansion parallel port 12
Arduino port 13

Table 1. Hardware IRQ interrupt assignment for the DE0-Nano-SoC Computer.

last read. Performing a write operation to the Edgecapture register sets all bits in the register to 0, and clears any
associated interrupts.

Address 31 30 ... 4 3 2 1 0

Base Input or output data bits Data register

Base + 4 Direction bits Direction register

Base + 8 Mask bits Interruptmask register

Base + C Edge bits Edgecapture register

Figure 11. Registers used for interrupts from the parallel ports.

3.1.1 Interrupts from the Pushbutton Keys

Figure 5, reproduced as Figure 12, shows the registers associated with the pushbutton parallel port. The Interrupt-
mask register allows processor interrupts to be generated when a key is pressed. Each bit in the Edgecapture register
is set to 1 by the parallel port when the corresponding key is pressed. The Nios II processor can read this register
to determine which key has been pressed, in addition to receiving an interrupt request if the corresponding bit in
the interrupt mask register is set to 1. Writing any value to the Edgecapture register deasserts the Nios II interrupt
request and sets all bits of the Edgecapture register to zero.

3.2 Interrupts from the JTAG* UART

Figure 7, reproduced as Figure 13, shows the data and Control registers of the JTAG UART. As we said in Section
2.4, RAVAIL in the Data register gives the number of characters that are stored in the receive FIFO, and WSPACE
gives the amount of unused space that is available in the transmit FIFO. The RE and WE bits in Figure 13 are used to
enable processor interrupts associated with the receive and transmit FIFOs. When enabled, interrupts are generated
when RAVAIL for the receive FIFO, or WSPACE for the transmit FIFO, exceeds 7. Pending interrupts are indicated
in the Control register’s RI and WI bits, and can be cleared by writing or reading data to/from the JTAG UART.

Intel Corporation - FPGA University Program 11


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

Address 31 30 ... 4 3 2 1 0

0xFF200050 Unused KEY1-0 Data register

Unused Unused

0xFF200058 Unused Mask bits Interruptmask register

0xFF20005C Unused Edge bits Edgecapture register

Figure 12. Registers used for interrupts from the pushbutton parallel port.

Address 31 ... 16 15 14 . . . 11 10 9 8 7 ... 1 0

0xFF201000 RAVAIL RVALID Unused DATA Data register

0xFF201004 WSPACE Unused AC WI RI WE RE Control register

Figure 13. Interrupt bits in the JTAG UART registers.

3.3 Interrupts from the FPGA Interval Timer

Figure 8, in Section 2.5, shows six registers that are associated with the interval timer. As we said in Section 2.5,
the TO bit in the Status register is set to 1 when the timer reaches a count value of 0. It is possible to generate an
interrupt when this occurs, by using the ITO bit in the Control register. Setting the ITO bit to 1 causes an interrupt
request to be sent to the processor whenever TO becomes 1. After an interrupt occurs, it can be cleared by writing
any value into the Status register.

3.4 Using Interrupts with Assembly Language Code

An example of assembly language code for the DE0-Nano-SoC Computer that uses interrupts is shown in Listing 5.
When this code is executed on the DE0-Nano-SoC board it displays a rotating pattern on the LEDs. The pattern’s
rotation can be toggled through pressing the pushbutton KEYs. Two types of interrupts are used in the code. The
LEDs are controlled by an interrupt service routine for the interval timer, and another interrupt service routine is
used to handle the pushbutton keys. The speed of the rotation is set in the main program, by using a counter value in
the interval timer that causes an interrupt to occur every 50 msec.

The reset and exception handlers for the main program in Listing 5 are given in Listing 6. The reset handler simply
jumps to the _start symbol in the main program. The exception handler first checks if the exception that has occurred
is an external interrupt or an internal one. In the case of an internal exception, such as an illegal instruction opcode
or a trap instruction, the handler simply exits, because it does not handle these cases. For external exceptions, it
calls either the interval timer interrupt service routine, for a level 0 interrupt, or the pushbutton key interrupt service
routine for level 1. These routines are shown in Listings 7 and 8, respectively.

12 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

3.5 Using Interrupts with C Language Code

An example of C language code for the DE0-Nano-SoC Computer that uses interrupts is shown in Listing 9. This
code performs exactly the same operations as the code described in Listing 5.

To enable interrupts the code in Listing 9 uses macros that provide access to the Nios II status and control registers.
A collection of such macros, which can be used in any C program, are provided in Listing 10.

The reset and exception handlers for the main program in Listing 9 are given in Listing 11. The function called
the_reset provides a simple reset mechanism by performing a branch to the main program. The function named
the_exception represents a general exception handler that can be used with any C program. It includes assembly
language code to check if the exception is caused by an external interrupt, and, if so, calls a C language routine
named interrupt_handler. This routine can then perform whatever action is needed for the specific application.
In Listing 11, the interrupt_handler code first determines which exception has occurred, by using a macro from
Listing 10 that reads the content of the Nios II interrupt pending register. The interrupt service routine that is
invoked for the interval timer is shown in 12, and the interrupt service routine for the pushbutton switches appears
in Listing 13.

The source code files shown in Listing 5 to Listing 13 are distributed as part of the Intel® FPGA Monitor Program.
The files can be found under the heading sample programs, and are identified by the name Interrupt Example.

4 Modifying the DE0-Nano-SoC Computer


It is possible to modify the DE0-Nano-SoC Computer by using Intel’s Quartus® Prime software and Qsys tool.
Tutorials that introduce this software are provided in the University Program section of Intel’s web site. To modify
the system it is first necessary to make an editable copy of the DE0-Nano-SoC Computer. The files for this system
are installed as part of the Monitor Program installation. Locate these files, copy them to a working directory, and
then use the Quartus Prime and Qsys software to make any desired changes.

Table 2 lists the names of the Qsys IP cores that are used in this system. When the DE0-Nano-SoC Computer design
files are opened in the Quartus Prime software, these cores can be examined using the Qsys System Integration tool.
Each core has a number of settings that are selectable in the Qsys System Integration tool, and includes a datasheet
that provides detailed documentation.

The steps needed to modify the system are:

1. Install the University Program IP Cores from Intel’s FPGA University Program web site

2. Copy the design source files for the DE0-Nano-SoC Computer from the University Program web site. These
files can be found in the Design Examples section of the web site

3. Open the DE0-Nano-SoC_Computer.qpf project in the Quartus Prime software

4. Open the Qsys System Integration tool in the Quartus Prime software, and modify the system as desired

5. Generate the modified system by using the Qsys System Integration tool

Intel Corporation - FPGA University Program 13


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

6. It may be necessary to modify the Verilog or VHDL code in the top-level module, DE0-Nano-SoC_Computer.v/vhd,
if any I/O peripherals have been added or removed from the system

7. Compile the project in the Quartus Prime software

8. Download the modified system into the DE0-Nano-SoC board

The DE0-Nano-SoC Computer includes a Nios II/f processor. When using the Quartus Prime Web Edition, com-
piling a design with a Nios II/s or Nios II/f processor will produce a time-limited SOF file. As a result, the board
must remain connected to the host computer, and the design cannot be set as the default configuration, as discussed
in Section 5. Designs using only Nios II/e processors and designs compiled using the Quartus Prime Subscription
Edition do not have this restriction.
I/O Peripheral Qsys Core
SDRAM SDRAM Controller
On-chip Memory On-Chip Memory (RAM or ROM)
SD Card SD Card Interface
Green LED parallel port Parallel Port
Expansion parallel ports Parallel Port
Slider switch parallel port Parallel Port
Pushbutton parallel port Parallel Port
JTAG port JTAG UART
Interval timer Interval timer
Analog-to-Digiral Converter ADC Controller
System ID System ID Peripheral

Table 2. Qsys cores used in the DE0-Nano-SoC Computer.

5 Making the System the Default Configuration


The DE0-Nano-SoC Computer can be loaded into the nonvolatile FPGA configuration memory on the DE0-Nano-
SoC board, so that it becomes the default system whenever the board is powered on. Instructions for configuring the
DE0-Nano-SoC board in this manner can be found in the tutorial Introduction to the Quartus Prime Software, which
is available from Intel’s FPGA University Program.

14 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

6 Memory Layout
Table 3 summarizes the memory map used in the DE0-Nano-SoC Computer.

Base Address End Address I/O Peripheral


0x00000000 0x00007FFF FPGA On-chip Memory
0x08000000 0x08007FFF FPGA On-chip Memory
0x40000000 0x7FFFFFFF DDR3 Memory
0xFF200000 0xFF20000F Green LEDs
0xFF200040 0xFF20004F Slider Switches
0xFF200050 0xFF20005F Pushbutton KEYs
0xFF200060 0xFF20006F JP1 Expansion
0xFF200070 0xFF20007F JP7 Expansion
0xFF200100 0xFF20010F Arduino Expansion
0xFF200110 0xFF20011F Arduino Reset
0xFF201000 0xFF201007 JTAG UART
0xFF201008 0xFF20100F Second JTAG UART
0xFF202000 0xFF20201F Interval Timer
0xFF202020 0xFF20202F Second Interval Timer
0xFF204000 0xFF20401F ADC

Table 3. Memory layout used in the DE0-Nano-SoC Computer.

Intel Corporation - FPGA University Program 15


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

7 Intel® FPGA Monitor Program Integration


As we mentioned earlier, the DE0-Nano-SoC Computer system, and the sample programs described in this docu-
ment, are made available as part of the Intel® FPGA Monitor Program. Figures 14 to 17 show a series of windows
that are used in the Monitor Program to create a new project. In the first screen, shown in Figure 14, the user specifies
a file system folder where the project will be stored, gives the project a name, and specifies the type of processor
that is being used. Pressing Next opens the window in Figure 15. Here, the user can select the DE0-Nano-SoC
Computer as a pre-designed system. The Monitor Program then fills in the relevant information in the System de-
tails box, which includes the appropriate system info and fpga configuration files, and preloader. The first of these
files specifies to the Monitor Program information about the components that are available in the DE0-Nano-SoC
Computer, such as the type of processor and memory components, and the address map. The second file is an FPGA
programming bitstream for the DE0-Nano-SoC Computer, which can downloaded by the Monitor Program into the
DE0-Nano-SoC board. Any system which contains a Hard Processor System (HPS) component must also specify
the preloader to be run immediately following the circuit being downloaded. This preloader is used to configure the
components within the HPS with the setting required for the specific board.

Figure 14. Specifying the project folder and project name.

16 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

Pressing Next again opens the window in Figure 16. Here the user selects the type of program that will be used,
such as Assembly language, or C. Then, the check box shown in the figure can be used to display the list of sample
programs for the DE0-Nano-SoC Computer that are described in this document. When a sample program is selected
in this list, its source files, and other settings, can be copied into the project folder in subsequent screens of the
Monitor Program.

Figure 17 gives the final screen that is used to create a new project in the Monitor Program. This screen shows the
default addresses of compiler and linker sections that will be used for the assembly language or C program associ-
ated with the Monitor Program project. In the figure, the drop-down menu called Linker Section Presets has been
set to Exceptions. With this setting the Monitor Program uses specific compiler and linker sections for the selected
processor. For the Nios II processor, these sections are for reset and exceptions code, and another section for the
main program, called .text. For the A9 processor, it has a section for the exception table, called .vectors, and another
section for the main program, called .text. It also shows the initial value used to set the main stack pointer for C
programs, which is the starting address of the .stack section.

Figure 15. Specifying the DE0-Nano-SoC Computer system.

Intel Corporation - FPGA University Program 17


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

Figure 16. Selecting sample programs.

Figure 17. Setting offsets for .text and .data.

18 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

8 Appendix
This section contains all of the source code files mentioned in the document.

8.1 Parallel Ports


.include "address_map_nios2.s"

/******************************************************************************
* This program demonstrates use of parallel ports
*
* It performs the following:
* 1. displays a rotating pattern on the LEDs
* 2. if any KEY is pressed, the SW switches are used as the rotating pattern
******************************************************************************/

.text # executable code follows


.global _start
_start:

/* initialize base addresses of parallel ports */


movia r15, SW_BASE # SW slider switch base address
movia r16, LED_BASE # LED base address
movia r17, KEY_BASE # pushbutton KEY base address
movia r18, LED_bits
ldwio r6, 0(r18) # load pattern for LED lights

DO_DISPLAY:
ldwio r4, 0(r15) # load slider switches

ldwio r5, 0(r17) # load pushbuttons


beq r5, r0, NO_BUTTON
mov r6, r4 # copy SW switch values onto LEDs
roli r4, r4, 8 # the SW values are copied into the upper three
# bytes of the pattern register
or r6, r6, r4 # needed to make pattern consistent as all
# 32-bits of a register are rotated
roli r4, r4, 8 # but only the lowest 8-bits are displayed on
# LEDs
or r6, r6, r4
roli r4, r4, 8
or r6, r6, r4
WAIT:
ldwio r5, 0(r17) # load pushbuttons
bne r5, r0, WAIT # wait for button release

NO_BUTTON:
stwio r6, 0(r16) # store to LED
roli r6, r6, 1 # rotate the displayed pattern

Intel Corporation - FPGA University Program 19


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

movia r7, 1500000 # delay counter


DELAY:
subi r7, r7, 1
bne r7, r0, DELAY

br DO_DISPLAY

/******************************************************************************/
.data # data follows

LED_bits:
.word 0x0F0F0F0F

.end
Listing 1. An example of Nios II assembly language code that uses parallel ports.

20 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

#include "address_map_nios2.h"
/* This program demonstrates use of parallel ports in the Computer System
*
* It performs the following:
* 1. displays a rotating pattern on the LEDs
* 2. if a KEY is pressed, uses the SW switches as the pattern
*/
int main(void) {
/* Declare volatile pointers to I/O registers (volatile means that IO load
* and store instructions will be used to access these pointer locations,
* instead of regular memory loads and stores)
*/
volatile int * LED_ptr = (int *)LED_BASE; // LED address
volatile int * SW_switch_ptr = (int *)SW_BASE; // SW slider switch address
volatile int * KEY_ptr = (int *)KEY_BASE; // pushbutton KEY address

int LED_bits = 0x0F0F0F0F; // pattern for LED lights


int SW_value, KEY_value;
volatile int
delay_count; // volatile so the C compiler doesn’t remove the loop

while (1) {
SW_value = *(SW_switch_ptr); // read the SW slider (DIP) switch values

KEY_value = *(KEY_ptr); // read the pushbutton KEY values


if (KEY_value != 0) // check if any KEY was pressed
{
/* set pattern using SW values */
LED_bits = SW_value | (SW_value << 8) | (SW_value << 16) |
(SW_value << 24);
while (*KEY_ptr)
; // wait for pushbutton KEY release
}
*(LED_ptr) = LED_bits; // light up the LEDs

/* rotate the pattern shown on the LEDs */


if (LED_bits & 0x80000000)
LED_bits = (LED_bits << 1) | 1;
else
LED_bits = LED_bits << 1;

for (delay_count = 350000; delay_count != 0; --delay_count)


; // delay loop
}
}
Listing 2. An example of C code that uses parallel ports.

Intel Corporation - FPGA University Program 21


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

8.2 JTAG* UART


.include "address_map_nios2.s"

/******************************************************************************
* This program demonstrates use of the JTAG UART port
*
* It performs the following:
* 1. sends a text string to the JTAG UART
* 2. reads character data from the JTAG UART
* 3. echos the character data back to the JTAG UART
*****************************************************************************/

.text # executable code follows


.global _start
_start:
/* set up stack pointer */
movia sp, SDRAM_END - 3 # starts from largest memory address

movia r6, JTAG_UART_BASE # JTAG UART base address

/* print a text string */


movia r8, TEXT_STRING
LOOP:
ldb r5, 0(r8)
beq r5, zero, GET_JTAG # string is null-terminated
call PUT_JTAG
addi r8, r8, 1
br LOOP

/* read and echo characters */


GET_JTAG:
ldwio r4, 0(r6) # read the JTAG UART data register
andi r8, r4, 0x8000 # check if there is new data
beq r8, r0, GET_JTAG # if no data, wait
andi r5, r4, 0x00ff # the data is in the least significant byte

call PUT_JTAG # echo character


br GET_JTAG

/******************************************************************************
* Subroutine to send a character to the JTAG UART
* r5 = character to send
* r6 = JTAG UART base address
*****************************************************************************/
.global PUT_JTAG
PUT_JTAG:
/* save any modified registers */
Listing 3. An example of assembly language code that uses the JTAG UART (Part a).

22 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

subi sp, sp, 4 # reserve space on the stack


stw r4, 0(sp) # save register

ldwio r4, 4(r6) # read the JTAG UART control register


andhi r4, r4, 0xffff # check for write space
beq r4, r0, END_PUT # if no space, ignore the character
stwio r5, 0(r6) # send the character

END_PUT:
/* restore registers */
ldw r4, 0(sp)
addi sp, sp, 4

ret

/*****************************************************************************/
.data

Listing 3. An example of assembly language code that uses the JTAG UART (Part b).

Intel Corporation - FPGA University Program 23


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

#include "JTAG_UART.h"
#include "address_map_nios2.h"

/*******************************************************************************
* Subroutine to send a character to the JTAG UART
******************************************************************************/
void put_jtag(volatile int * JTAG_UART_ptr, char c)
{
int control;
control = *(JTAG_UART_ptr + 1); // read the JTAG_UART control register
if (control & 0xFFFF0000) // if space, echo character, else ignore
* (JTAG_UART_ptr) = c;
}

/*******************************************************************************
* Subroutine to read a character from the JTAG UART
* Returns \0 if no character, otherwise returns the character
******************************************************************************/
char get_jtag(volatile int * JTAG_UART_ptr)
{
int data;
data = *(JTAG_UART_ptr); // read the JTAG_UART data register
if (data & 0x00008000) // check RVALID to see if there is new data
return ((char)data & 0xFF);
else
return (’\0’);
}
Listing 4. An example of C code that uses the JTAG UART (Part a).

24 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

#include "JTAG_UART.h"
#include "address_map_nios2.h"

/*******************************************************************************
* This program demonstrates use of the JTAG UART port
*
* It performs the following:
* 1. sends a text string to the JTAG UART
* 2. reads character data from the JTAG UART
* 3. echos the character data back to the JTAG UART
******************************************************************************/
int main(void)
{
/* Declare volatile pointers to I/O registers (volatile means that IO load
and store instructions will be used to access these pointer locations,
instead of regular memory loads and stores) */
volatile int * JTAG_UART_ptr = (int *)JTAG_UART_BASE; // JTAG UART address

char text_string[] = "\nJTAG UART example code\n> \0";


char *str, c;

/* print a text string */


for (str = text_string; *str != 0; ++str)
put_jtag(JTAG_UART_ptr, *str);

/* read and echo characters */


while (1)
{
c = get_jtag(JTAG_UART_ptr);
if (c != ’\0’)
put_jtag(JTAG_UART_ptr, c);
}
}

Listing 4. An example of C code that uses the JTAG UART (Part b).

Intel Corporation - FPGA University Program 25


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

8.3 Interrupts
.include "address_map_nios2.s"
.include "globals.s"

/*******************************************************************************
* This program demonstrates use of interrupts. It
* first starts an interval timer with 50 msec timeouts, and then enables
* Nios II interrupts from the interval timer and pushbutton KEYs
*
* The interrupt service routine for the interval timer displays a pattern
* on the LEDs, and shifts this pattern either left or right:
* KEY[0]: loads a new pattern from the SW switches
* KEY[1]: toggles the shift direction the displayed pattern
******************************************************************************/

.text # executable code follows


.global _start
_start:
/* set up the stack */
movia sp, SDRAM_END - 3 # stack starts from largest memory
# address

movia r16, TIMER_BASE # interval timer base address


/* set the interval timer period for scrolling the LED lights */
movia r12, 5000000 # 1/(100 MHz) x (5 x 10^6) = 50 msec
sthio r12, 8(r16) # store the low half word of counter
# start value
srli r12, r12, 16
sthio r12, 0xC(r16) # high half word of counter start value

/* start interval timer, enable its interrupts */


movi r15, 0b0111 # START = 1, CONT = 1, ITO = 1
sthio r15, 4(r16)

/* write to the pushbutton port interrupt mask register */


movia r15, KEY_BASE # pushbutton key base address
movi r7, 0b11 # set interrupt mask bits
stwio r7, 8(r15) # interrupt mask register is (base + 8)

/* enable Nios II processor interrupts */


movia r7, 0x00000001 # get interrupt mask bit for interval
# timer
movia r8, 0x00000002 # get interrupt mask bit for pushbuttons
or r7, r7, r8
wrctl ienable, r7 # enable interrupts for the given mask
# bits
movi r7, 1
wrctl status, r7 # turn on Nios II interrupt processing

IDLE:

26 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

br IDLE # main program simply idles

.data
/*******************************************************************************
* The global variables used by the interrupt service routines for the interval
* timer and the pushbutton keys are declared below
******************************************************************************/
.global PATTERN
PATTERN:
.word 0x0F0F0F0F # pattern to show on the LED lights
.global SHIFT_DIR
SHIFT_DIR:
.word RIGHT # pattern shifting direction

.end
Listing 5. An example of assembly language code that uses interrupts.

Intel Corporation - FPGA University Program 27


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

/*******************************************************************************
* RESET SECTION
* Note: "ax" is REQUIRED to designate the section as allocatable and executable.
* Also, the Debug Client automatically places the ".reset" section at the reset
* location specified in the CPU settings in SOPC Builder.
******************************************************************************/
.section .reset, "ax"

movia r2, _start


jmp r2 # branch to main program

/*******************************************************************************
* EXCEPTIONS SECTION
* Note: "ax" is REQUIRED to designate the section as allocatable and executable.
* Also, the Monitor Program automatically places the ".exceptions" section at
* the exception location specified in the CPU settings in SOPC Builder.
******************************************************************************/
.section .exceptions, "ax"
.global EXCEPTION_HANDLER

EXCEPTION_HANDLER:
subi sp, sp, 16 # make room on the stack
stw et, 0(sp)

rdctl et, ctl4


beq et, r0, SKIP_EA_DEC # interrupt is not external

subi ea, ea, 4 # must decrement ea by one instruction


# for external interrupts, so that the
# interrupted instruction will be run
SKIP_EA_DEC:
stw ea, 4(sp) # save all used registers on the Stack
stw ra, 8(sp) # needed if call inst is used
stw r22, 12(sp)

rdctl et, ctl4


bne et, r0, CHECK_LEVEL_0 # interrupt is an external interrupt

NOT_EI: # exception must be unimplemented


# instruction or TRAP instruction. This
# code does not handle those cases
br END_ISR

CHECK_LEVEL_0: # interval timer is interrupt level 0


andi r22, et, 0b1
beq r22, r0, CHECK_LEVEL_1

call INTERVAL_TIMER_ISR
br END_ISR

CHECK_LEVEL_1: # pushbutton port is interrupt level 1

28 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

andi r22, et, 0b10


beq r22, r0, END_ISR # other interrupt levels are not handled in
# this code

call PUSHBUTTON_ISR

END_ISR:
ldw et, 0(sp) # restore all used register to previous
# values
ldw ea, 4(sp)
ldw ra, 8(sp) # needed if call inst is used
ldw r22, 12(sp)
addi sp, sp, 16

.end
Listing 6. Reset and exception handler assembly language code.

Intel Corporation - FPGA University Program 29


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

.include "address_map_nios2.s"
.include "globals.s"
.extern PATTERN # externally defined variables
.extern SHIFT_DIR
/*******************************************************************************
* Interval timer - Interrupt Service Routine
*
* Shifts a PATTERN being displayed. The shift direction is determined by the
* external variable SHIFT_DIR.
******************************************************************************/
.global INTERVAL_TIMER_ISR
INTERVAL_TIMER_ISR:
subi sp, sp, 40 # reserve space on the stack
stw ra, 0(sp)
stw r4, 4(sp)
stw r5, 8(sp)
stw r6, 12(sp)
stw r8, 16(sp)
stw r10, 20(sp)
stw r20, 24(sp)
stw r21, 28(sp)
stw r22, 32(sp)
stw r23, 36(sp)

movia r10, TIMER_BASE # interval timer base address


sthio r0, 0(r10) # clear the interrupt

movia r20, LED_BASE # LED base address


movia r21, PATTERN # set up a pointer to the display pattern
movia r22, SHIFT_DIR # set up a pointer to the shift direction variable

ldw r6, 0(r21) # load the pattern


stwio r6, 0(r20) # store to LEDs

CHECK_SHIFT:
ldw r5, 0(r22) # get shift direction
movi r8, RIGHT
bne r5, r8, SHIFT_L

SHIFT_R:
movi r5, 1 # set r5 to the constant value 1
ror r6, r6, r5 # rotate the displayed pattern right
br STORE_PATTERN

SHIFT_L:
movi r5, 1 # set r5 to the constant value 1
rol r6, r6, r5 # shift left

STORE_PATTERN:
stw r6, 0(r21) # store display pattern

30 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

END_INTERVAL_TIMER_ISR:
ldw ra, 0(sp) # restore registers
ldw r4, 4(sp)
ldw r5, 8(sp)
ldw r6, 12(sp)
ldw r8, 16(sp)
ldw r10, 20(sp)
ldw r20, 24(sp)
ldw r21, 28(sp)
ldw r22, 32(sp)
ldw r23, 36(sp)
addi sp, sp, 40 # release the reserved space on the stack

.end
Listing 7. Interrupt service routine for the interval timer.

Intel Corporation - FPGA University Program 31


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

.include "address_map_nios2.s"
.include "globals.s"
.extern PATTERN # externally defined variables
.extern SHIFT_DIR
/*******************************************************************************
* Pushbutton - Interrupt Service Routine
*
* This routine checks which KEY has been pressed and updates the global
* variables as required.
******************************************************************************/
.global PUSHBUTTON_ISR
PUSHBUTTON_ISR:
subi sp, sp, 20 # reserve space on the stack
stw ra, 0(sp)
stw r10, 4(sp)
stw r11, 8(sp)
stw r12, 12(sp)
stw r13, 16(sp)

movia r10, KEY_BASE # base address of pushbutton KEY


# parallel port
ldwio r11, 0xC(r10) # read edge capture register
stwio r11, 0xC(r10) # clear the interrupt

CHECK_KEY0:
andi r13, r11, 0b0001 # check KEY0
beq r13, zero, CHECK_KEY1

movia r10, SW_BASE # base address of SW slider


# switches parallel port
ldwio r12, 0(r10) # load a new pattern from the SW
# switches
movia r10, PATTERN # set up a pointer to the pattern
# variable
stw r12, 0(r10) # store the new pattern to the
# global variable

CHECK_KEY1:
andi r13, r11, 0b0010 # check KEY1
beq r13, zero, END_PUSHBUTTON_ISR

movia r10, SHIFT_DIR # set up a pointer to the shift


# direction variable
ldw r12, 0(r10) # load the current shift direction
xori r12, r12, 1 # toggle the direction
stw r12, 0(r10) # store the new shift direction

END_PUSHBUTTON_ISR:
ldw ra, 0(sp) # Restore all used register to
# previous
ldw r10, 4(sp)

32 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

ldw r11, 8(sp)


ldw r12, 12(sp)
ldw r13, 16(sp)
addi sp, sp, 20

.end
Listing 8. Interrupt service routine for the pushbutton KEYs.

Intel Corporation - FPGA University Program 33


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

#include "address_map_nios2.h"
#include "globals.h" // defines global values
#include "nios2_ctrl_reg_macros.h"

/* the global variables are written by interrupt service routines; we have to


* declare
* these as volatile to avoid the compiler caching their values in registers */
volatile int pattern = 0x0000000F; // pattern for shifting
volatile int shift_dir = LEFT; // direction to shift the pattern
volatile int shift_enable = ENABLE; // enable/disable shifting of the pattern

/*******************************************************************************
* This program demonstrates use of interrupts. It
* first starts the interval timer with 50 msec timeouts, and then enables
* Nios II interrupts from the interval timer and pushbutton KEYs
*
* The interrupt service routine for the interval timer displays a pattern on
* the LED lights, and shifts this pattern either left or right. The shifting
* direction is reversed when KEY[1] is pressed
********************************************************************************/
int main(void) {
/* Declare volatile pointers to I/O registers (volatile means that IO load
* and store instructions will be used to access these pointer locations,
* instead of regular memory loads and stores)
*/
volatile int * interval_timer_ptr =
(int *)TIMER_BASE; // interal timer base address
volatile int * KEY_ptr = (int *)KEY_BASE; // pushbutton KEY address

/* set the interval timer period for scrolling the LED lights */
int counter = 2500000; // 1/(50 MHz) x (2500000) = 50 msec
*(interval_timer_ptr + 0x2) = (counter & 0xFFFF);
*(interval_timer_ptr + 0x3) = (counter >> 16) & 0xFFFF;

/* start interval timer, enable its interrupts */


*(interval_timer_ptr + 1) = 0x7; // STOP = 0, START = 1, CONT = 1, ITO = 1

*(KEY_ptr + 2) = 0x3; // enable interrupts for all pushbuttons

/* set interrupt mask bits for levels 0 (interval timer) and level 1
* (pushbuttons) */
NIOS2_WRITE_IENABLE(0x3);

NIOS2_WRITE_STATUS(1); // enable Nios II interrupts

while (1)
; // main program simply idles
}
Listing 9. An example of C code that uses interrupts.

34 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

#ifndef __NIOS2_CTRL_REG_MACROS__
#define __NIOS2_CTRL_REG_MACROS__

/*****************************************************************************/
/* Macros for accessing the control registers. */
/*****************************************************************************/

#define NIOS2_READ_STATUS(dest) \
do { dest = __builtin_rdctl(0); } while (0)

#define NIOS2_WRITE_STATUS(src) \
do { __builtin_wrctl(0, src); } while (0)

#define NIOS2_READ_ESTATUS(dest) \
do { dest = __builtin_rdctl(1); } while (0)

#define NIOS2_READ_BSTATUS(dest) \
do { dest = __builtin_rdctl(2); } while (0)

#define NIOS2_READ_IENABLE(dest) \
do { dest = __builtin_rdctl(3); } while (0)

#define NIOS2_WRITE_IENABLE(src) \
do { __builtin_wrctl(3, src); } while (0)

#define NIOS2_READ_IPENDING(dest) \
do { dest = __builtin_rdctl(4); } while (0)

#define NIOS2_READ_CPUID(dest) \
do { dest = __builtin_rdctl(5); } while (0)

#endif
Listing 10. Macros for accessing Nios II status and control registers.

Intel Corporation - FPGA University Program 35


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

#include "nios2_ctrl_reg_macros.h"

/* function prototypes */
void main(void);
void interrupt_handler(void);
void interval_timer_ISR(void);
void pushbutton_ISR(void);

/* The assembly language code below handles CPU reset processing */


void the_reset(void) __attribute__((section(".reset")));
void the_reset(void)
/*******************************************************************************
* Reset code. By giving the code a section attribute with the name ".reset" we
* allow the linker program to locate this code at the proper reset vector
* address. This code just calls the main program.
******************************************************************************/
{
asm(".set noat"); /* Instruct the assembler NOT to use reg at (r1) as
* a temp register for performing optimizations */
asm(".set nobreak"); /* Suppresses a warning message that says that
* some debuggers corrupt regs bt (r25) and ba
* (r30)
*/
asm("movia r2, main"); // Call the C language main program
asm("jmp r2");
}

/* The assembly language code below handles CPU exception processing. This
* code should not be modified; instead, the C language code in the function
* interrupt_handler() can be modified as needed for a given application.
*/
void the_exception(void) __attribute__((section(".exceptions")));
void the_exception(void)
/*******************************************************************************
* Exceptions code. By giving the code a section attribute with the name
* ".exceptions" we allow the linker program to locate this code at the proper
* exceptions vector address.
* This code calls the interrupt handler and later returns from the exception.
******************************************************************************/
{
asm("subi sp, sp, 128");
asm("stw et, 96(sp)");
asm("rdctl et, ctl4");
asm("beq et, r0, SKIP_EA_DEC"); // Interrupt is not external
asm("subi ea, ea, 4"); /* Must decrement ea by one instruction
* for external interupts, so that the
* interrupted instruction will be run */

asm("SKIP_EA_DEC:");
asm("stw r1, 4(sp)"); // Save all registers
asm("stw r2, 8(sp)");

36 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

asm("stw r3,
12(sp)");
asm("stw r4,
16(sp)");
asm("stw r5,
20(sp)");
asm("stw r6,
24(sp)");
asm("stw r7,
28(sp)");
asm("stw r8,
32(sp)");
asm("stw r9,
36(sp)");
asm("stw r10,
40(sp)");
asm("stw r11,
44(sp)");
asm("stw r12,
48(sp)");
asm("stw r13,
52(sp)");
asm("stw r14,
56(sp)");
asm("stw r15,
60(sp)");
asm("stw r16,
64(sp)");
asm("stw r17,
68(sp)");
asm("stw r18,
72(sp)");
asm("stw r19,
76(sp)");
asm("stw r20,
80(sp)");
asm("stw r21,
84(sp)");
asm("stw r22,
88(sp)");
asm("stw r23,
92(sp)");
asm("stw r25,
100(sp)"); // r25 = bt (skip r24 = et, because it is saved
// above)
asm("stw r26, 104(sp)"); // r26 = gp
// skip r27 because it is sp, and there is no point in saving this
asm("stw r28, 112(sp)"); // r28 = fp
asm("stw r29, 116(sp)"); // r29 = ea
asm("stw r30, 120(sp)"); // r30 = ba
asm("stw r31, 124(sp)"); // r31 = ra
asm("addi fp, sp, 128");

asm("call interrupt_handler"); // Call the C language interrupt handler

asm("ldw r1, 4(sp)"); // Restore all registers


asm("ldw r2, 8(sp)");
asm("ldw r3, 12(sp)");
asm("ldw r4, 16(sp)");
asm("ldw r5, 20(sp)");
asm("ldw r6, 24(sp)");
asm("ldw r7, 28(sp)");
asm("ldw r8, 32(sp)");
asm("ldw r9, 36(sp)");
asm("ldw r10, 40(sp)");
asm("ldw r11, 44(sp)");
asm("ldw r12, 48(sp)");
asm("ldw r13, 52(sp)");
asm("ldw r14, 56(sp)");
asm("ldw r15, 60(sp)");
asm("ldw r16, 64(sp)");
asm("ldw r17, 68(sp)");
asm("ldw r18, 72(sp)");

Intel Corporation - FPGA University Program 37


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

asm("ldw r19, 76(sp)");


asm("ldw r20, 80(sp)");
asm("ldw r21, 84(sp)");
asm("ldw r22, 88(sp)");
asm("ldw r23, 92(sp)");
asm("ldw r24, 96(sp)");
asm("ldw r25, 100(sp)"); // r25 = bt
asm("ldw r26, 104(sp)"); // r26 = gp
// skip r27 because it is sp, and we did not save this on the stack
asm("ldw r28, 112(sp)"); // r28 = fp
asm("ldw r29, 116(sp)"); // r29 = ea
asm("ldw r30, 120(sp)"); // r30 = ba
asm("ldw r31, 124(sp)"); // r31 = ra

asm("addi sp, sp, 128");

asm("eret");
}

/******************************************************************************
* Interrupt Service Routine
* Determines what caused the interrupt and calls the appropriate
* subroutine.
*
* ipending - Control register 4 which has the pending external interrupts
******************************************************************************/
void interrupt_handler(void) {
int ipending;
NIOS2_READ_IPENDING(ipending);
if (ipending & 0x1) // interval timer is interrupt level 0
{
interval_timer_ISR();
}
if (ipending & 0x2) // pushbuttons are interrupt level 1
{
pushbutton_ISR();
}
// else, ignore the interrupt
return;
}
Listing 11. Reset and exception handler C code.

38 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

#include "address_map_nios2.h"
#include "globals.h" // defines global values

extern volatile int pattern, shift_dir, shift_enable;


/*******************************************************************************
* Interval timer interrupt service routine
*
* Shifts a PATTERN being displayed on the LED lights. The shift direction
* is determined by the external variable key_dir.
******************************************************************************/
void interval_timer_ISR() {
volatile int * interval_timer_ptr = (int *)TIMER_BASE;
volatile int * LEDG_ptr = (int *)LED_BASE; // LED address

*(interval_timer_ptr) = 0; // clear the interrupt

*(LEDG_ptr) = pattern; // display pattern on LED

if (shift_enable == DISABLE) // check if shifting is disabled


return;

/* rotate the pattern shown on the LEDG lights */


if (shift_dir == LEFT) // rotate left
if (pattern & 0x80000000)
pattern = (pattern << 1) | 1;
else
pattern = pattern << 1;
else // rotate right
if (pattern & 0x00000001)
pattern = (pattern >> 1) | 0x80000000;
else
pattern = (pattern >> 1) & 0x7FFFFFFF;

return;
}
Listing 12. Interrupt service routine for the interval timer.

Intel Corporation - FPGA University Program 39


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

#include "address_map_nios2.h"
#include "globals.h" // defines global values

extern volatile int pattern, shift_dir, shift_enable;


/*******************************************************************************
* Pushbutton - Interrupt Service Routine
*
* This routine checks which KEY has been pressed and updates the global
* variables as required.
******************************************************************************/
void pushbutton_ISR(void) {
volatile int * KEY_ptr = (int *)KEY_BASE;
volatile int * slider_switch_ptr = (int *)SW_BASE;
int press;

press = *(KEY_ptr + 3); // read the pushbutton interrupt register


*(KEY_ptr + 3) = press; // Clear the interrupt

if (press & 0x1) // KEY0


pattern = *slider_switch_ptr;

if (press & 0x2) // KEY1


shift_dir = shift_dir ^ 1;

return;
}
Listing 13. Interrupt service routine for the pushbutton KEYs.

40 Intel Corporation - FPGA University Program


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

8.4 Floating Point


/*******************************************************************************
* This program demonstrates use of floating-point numbers
*
* It performs the following:
* 1. reads two FP numbers from the Terminal window
* 2. performs +, -, *, and / on the numbers
* 3. prints the results on the Terminal window
* Note: Please enable "Echo input" in the terminal window
******************************************************************************/
#include <stdio.h>

int flush()
{
while (getchar() != ’\n’)
;
return 1;
}

int main(void)
{
float x, y, add, sub, mult, div;

while (1)
{
printf("Enter FP values X: ");

while ((scanf("%f", &x) != 1) && flush())


; // get valid floating point value and flush the invalid input
printf("%f\n", x); // echo the typed data to the Terminal window

printf("Enter FP values Y: ");

while ((scanf("%f", &y) != 1) && flush())


; // get valid floating point value and flush the invalid input
printf("%f\n", y); // echo the typed data to the Terminal window

add = x + y;
sub = x - y;
mult = x * y;
div = x / y;
printf("X + Y = %f\n", add);
printf("X - Y = %f\n", sub);
printf("X * Y = %f\n", mult);
printf("X / Y = %f\n", div);
}
}
Listing 14. An example of code that uses floating-point variables.

Intel Corporation - FPGA University Program 41


November 2017
DE0-N ANO -S O C C OMPUTER S YSTEM WITH N IOS® II For Quartus® Prime 17.1

Copyright © Intel Corporation. All rights reserved. Intel, the Intel logo, Altera, Arria, Avalon, Cyclone, Enpirion,
MAX, Nios, Quartus and Stratix words and logos are trademarks of Intel Corporation or its subsidiaries in the U.S.
and/or other countries. Intel warrants performance of its FPGA and semiconductor products to current specifications
in accordance with Intel’s standard warranty, but reserves the right to make changes to any products and services
at any time without notice. Intel assumes no responsibility or liability arising out of the application or use of any
information, product, or service described herein except as expressly agreed to in writing by Intel. Intel customers
are advised to obtain the latest version of device specifications before relying on any published information and
before placing orders for products or services.

*Other names and brands may be claimed as the property of others.

42 Intel Corporation - FPGA University Program


November 2017

You might also like