Connecting the Supersmall to your System

So, you've tested the supersmall so that you know that it works, you've even written and executed your own code for it, and now you're wondering, "How do I actually get data on and off this thing?" Well, thanks to Altera's SOPC builder, which is included in Quartus II, the task is practically trivial.

First, uncomment the "EXTMEM" definition in supersmall/defines.v. This opens up the Avalon bus interface in the top-level module (supersmall/system.v), so that it can work properly with SOPC builder. If you forgot to do this before starting SOPC builder, you'll have to refresh the system (hotkey is [f5]), or SOPC builder will fail to generate the system, complaining about mismatches between the tcl description and the actual design.

Next, start up Quartus II, and open the "sopcquartus" project in the sopcquartus directory of the supersmall package. Go to the "tools" menu, and select "SOPC Builder". After a little setup, the SOPC builder interface should open in front of you.

SOPC Builder screenshot

As you can see above, the SOPC builder builder interface provides an easy way of connecting memory-mapped peripherals to the processor. This isn't intended as a full-fledged guide to SOPC builder, (see Altera's web site for one of those), but simply a quick tour to get you started, along with some supersmall-specific information.

Adding the supersmall

Now, you'll notice that, assuming you've done everything correctly above, the supersmall processor's already been added for you and is connected to a few peripherals (internal memories, a JTAG UART, and a performance counter). If you want, you can simply keep this setup and add your peripherals onto it. In that case, skip ahead to the next section, "Adding Peripherals". However, if rather than using the sopcquartus project, you're using your own setup, here's how to add the supersmall to your SOPC builder setup:

Go to the tools menu, select "options", change the options for "IP search path", and add the "sopcquartus" folder to the IP search path. Then click "finish". After a bit of loading, you'll notice a new section in the component library on the left-hand side: Processors. Inside there, you'll find three new additions:

Supersmall Processor
The default supersmall soft processor configured to be an Avalon Master
Supersmall Processor (exceptions disabled)
The same processor, except compiled without the ENABLE_EXCEPTIONS definition.
The full supersmall processor with an attached verilog test bench that prints out similar information to that found in test_bench.v. This is useful for debugging and validating the SOPC version of the supersmall processor in a simulator, although you won't be able to program it onto actual hardware.

Feel free to switch them in and out as necessary: except for exceptions, their interfaces and behaviour should be absolutely identical. To add one, simply select it and click the "Add" button.

After some more processing, you'll notice the GUI interface comes up with two modifiable constants, "START_ADDR" and "EXCEPTION_ADDR", set to ridiculous numbers like "67108864". Of course, those of you with excellent hexadecimal literacy will realize that that's just the decimal form of 0x04000000. Although Quartus will automatically convert the hexadecimal constants into decimal, it's possible to enter either decimal or hexadecimal values (prefixed with "0x") into the box if you wish to change these addresses. I recommend against it however unless necessary, since it has a habit of breaking things in unexpected places, particularly the supersmall's test suite.

After selecting "finish" in that dialog box, the supersmall will be added to your design, and you can start connecting peripherals.

Adding Peripherals

Using SOPC builder, adding peripherals is incredibly simple. If a core already exists for what you need, simply find it in the list on the left hand side, click add, fill in a few fields depending on what the core is, and watch as it is magically added to your design. If you want to add your own custom peripheral, it's a bit more work, but reading through Altera's documentation should guide you on the specifics.

Once the peripheral is added to your design, there are two things you need to do: first, connect the peripheral's interface to the supersmall's "dmem" interface, so that it can be controlled using loads and stores. Then, decide where to put your peripheral's memory range.


The supersmall has no memory-management unit (MMU), and as a result, has a flat memory access model: if you attempt to load a word from address 0xf00f1234, the address you load is the same address the hardware sees. Now, on the default, non-SOPC builder setup, any unused address bits are simply dropped. When using SOPC builder however, it's a bit different: all the address bits are read, and are used to decide exactly which device is being accessed at once. This means, when laying out your memories in SOPC builder, it is imperative to ensure that certain memory ranges are covered, since otherwise, attempts to load data from those locations will instead retrieve garbage (usually 0xffffffff). Here's a table illustrating the sensitive areas of memory that will need to be covered:

Description Memory Address Range Growth Direction Definition
Instruction Memory 0x0400_0000+ Up supersmall/tools/lsi.ld
Data memory (preloaded) 0x1000_0000+ Up supersmall/tools/lsi.ld
Stack memory 0x7fff_0ebc- Down supersmall/tools/lsi.ld
JTAG UART (optional) 0xbeef_0000+ Fixed SOPC builder

Although all these address ranges are somewhat arbitrary, I don't recommend changing them unless you know what you're doing: it's very easy to accidently start breaking things once you start playing around with the linker.

However, when adding your own peripheral, the only thing you need to be concerned about is not letting your peripheral's memory range overlap with any other ones. As well, I wouldn't recommend sticking it at the default 0x0+ memory range. Other than that, pick something you can remember, make sure to use it when writing drivers for your peripheral, and you should be good to go.

The only place where this doesn't necessarily apply is with instruction memory: as long as you have a separate memory connected to the processor's imem interface, and this memory is the only one connected there, it'll always get accessed, and you don't have to worry about overlap. However, it is necessary that at least the lower 16 bits of the instruction memory begin at 0x0000, or you'll likely have problems with execution beginning in the wrong location. As well, if you wish to connect the instruction memory so that it's actually accessible via the data memory interface, you'll have to make sure that it doesn't overlap with any other memory ranges.


Once everything's connected in SOPC builder, you can click "Generate", and after some processing, SOPC builder will churn out the required verilog files. Now, all you need to do is instantiate the design, using the template in the $PROJECTNAME_inst.v file, and connect everything up to your board. The sopcquartus project in the supersmall distribution is setup to do this properly for the Terasic DE3, but it should be simple enough to integrate it into whatever your current design flow is.


SOPC builder also makes it extremely easy to test that your design will work as expected using Modelsim. First, select the "Tools" drop-down menu, and click on options. There, make sure the "Application Path" of the Modelsim HDL simulator is pointing to wherever it is installed on your computer. Then, before generating the project, ensure that the "Simulation" checkbox is checked off, and after generation, hit "Simulate" to launch Modelsim.

Within Modelsim, SOPC builder sets up some special commands to help you work with the design, but I've also provided a script in sopcquartus/DE3test_sim that adds all the waveforms from simulate_gui, allowing easier debugging. Execute it by either running "do" for the regular supersmall processor, or "do" for the debug version of the processor. Both will add all the relevant waveforms, plus the special SOPC builder ones, and run the design for 400 us, giving you a similar workspace as that provided by simulate_gui.