Is there a RISC-V target / How to use “soft” cores on FPGA target boards?#
Our FPGA target boards aren’t just for hardware developers: they also let you grab an open-source microprocessor and run it as a “soft” core on the FPGA.
That’s one of the reasons why the Husky kit includes an iCE40 FPGA target board: it’s a very easy way to work and play with an open-source RISC-V core.
If you’ve never used FPGA boards or soft cores before, you may think that this requires a lot of work to set up. But we’ve done all of that hard work for you! All you need to do is to install a RISC-V compiler, then you can use it as would would any other NewAE microprocessor target board.
We’ve put this entry in the “basic” category because using the neorv32 RISC-V softcore on the iCE40 FPGA target is very easy to do.
In this note we’ll talk about 3 different soft cores, in increasing order of complexity.
Supported Capture Hardware:
❌ CW-Nano
✅ CW-Husky
Partially Supported Capture Hardware:
✅ CW-Lite
✅ CW-Pro
neither support programming the CW312-XC7A35 target (you can use an external programmer such as the Xilinx Platform Cable instead)
some of the captures here require more samples than the Lite can handle; see How can I capture more samples? to work around this)
Supported Targets: (not all targets support all soft cores)
✅ CW312T-iCE40
✅ CW312T-XC7A35
✅ CW305
Required ChipWhisperer software installation:
✅ 6.0
Featured Soft Cores:
✅ neorv32 (RISC-V)
✅ lowRISC Ibex (RISC-V)
✅ Arm DesignStart (ARM)
%run '../connect.ipynb'
1. neorv32 RISC-V core on CW312T-iCE40#
The ChipWhisperer repository includes a pre-built neorv32 RISC-V core. Look to our iCE40 target page for more information about this core.
Of the soft cores included in this notebook, this is the easiest one to use and develop for: all you need to install is a riscv compiler (riscv32-unknown-elf-gcc or riscv64-unknown-elf-gcc).
Then, compiling firmware for this core is as easy as setting PLATFORM = 'CW308_NEORV32':
PLATFORM = 'CW308_NEORV32'
CRYPTO_TARGET='TINYAES128C'
SS_VER='SS_VER_1_1'
%%bash -s "$PLATFORM" "$CRYPTO_TARGET" "$SS_VER"
cd ../../../../firmware/mcu/simpleserial-aes
make PLATFORM=$1 CRYPTO_TARGET=$2 SS_VER=$3 -j
Building for platform CW308_NEORV32 with CRYPTO_TARGET=TINYAES128C
SS_VER set to SS_VER_1_1
SS_VER set to SS_VER_1_1
Blank crypto options, building for AES128
riscv32-unknown-elf-gcc (crosstool-NG 1.24.0.498_5075e1f) 10.2.0
undation, Inc.2020 Free Software Fo
This is free software; see the source for copying conditions. There is NO
not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
mkdir -p objdir-CW308_NEORV32
.
Welcome to another exciting ChipWhisperer target build!!
.
.
.
.
Compiling:
Compiling:
Compiling:
.
Compiling:
-en simpleserial-aes.c ...
-en .././simpleserial/simpleserial.c ...
-en .././hal/hal.c ...
Compiling:
-en .././hal//neorv32/neorv32_cfs.c ...
-en .././hal//neorv32/neorv32_cpu.c ...
.
.
Compiling:
Compiling:
.
.
-en .././hal//neorv32/neorv32_gpio.c ...
-en .././hal//neorv32/neorv32_gptmr.c ...
.
Compiling:
Compiling:
Compiling:
-en .././hal//neorv32/neorv32_mtime.c ...
rv32/neorv32_neoled.c ...
.
-en .././hal//neorv32/neorv32_pwm.c ...
Compiling:
.
-en .././hal//neorv32/neorv32_rte.c ...
.
Compiling:
.
Compiling:
Compiling:
-en .././hal//neorv32/neorv32_slink.c ...
-en .././hal//neorv32/neorv32_spi.c ...
-en .././hal//neorv32/neorv32_trng.c ...
.
-e Done!
.
Compiling:
Compiling:
.
-en .././hal//neorv32/neorv32_twi.c ...
.
-en .././hal//neorv32/neorv32_uart.c ...
Compiling:
Compiling:
-en .././hal//neorv32/neorv32_wdt.c ...
-en .././hal//neorv32/neorv32_xip.c ...
.
-e Done!
Compiling:
.
-en .././hal//neorv32/neorv32_xirq.c ...
.
Compiling:
-en .././hal//neorv32/neorv32_hal.c ...
Compiling:
.
-en .././hal//neorv32/syscalls.c ...
-e Done!
Compiling:
.
-e Done!
-en .././crypto/tiny-AES128-C/aes.c ...
Compiling:
.
-e Done!
-e Done!
-en .././crypto/aes-independant.c ...
Assembling: .././hal//neorv32/crt0.S
embler-with-cpp -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv -Wl,--gc-sections -lm -lc -lgcc -lc -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 -DF_CPU=7372800 -Wa,-gstabs,-adhlns=objdir-CW308_NEORV32/crt0.lst -I.././simpleserial/ -I.././hal/ -I.././hal/ -I.././hal//neorv32 -I.././simpleserial/ -I.././crypto/ -I.././crypto/tiny-AES128-C .././hal//neorv32/crt0.S -o objdir-CW308_NEORV32/crt0.o
-e Done!
-e Done!
-e Done!
-e Done!
.././hal//neorv32/syscalls.c:103:6: warning: "/*" within comment [-Wcomment]
e int *)EXIT_REG = exit_status;
|
.././hal//neorv32/syscalls.c:134:19: warning: 'struct timeb' declared inside parameter list will not be visible outside of this definition or declaration
134 | int _ftime(struct timeb *tp)
^~~~~
.././hal//neorv32/syscalls.c: In function '_write':
s.c:248:9: warning: implicit declaration of function 'neorv32_uart0_putc'; did you mean 'neorv32_uart0_printf'? [-Wimplicit-function-declaration]
248 | neorv32_uart0_putc(*(char *)(ptr++));
| ^~~~~~~~~~~~~~~~~~
| neorv32_uart0_printf
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
.
LINKING:
-en simpleserial-aes-CW308_NEORV32.elf ...
Memory region Used Size Region Size %age Used
9.50% ram: 6224 B 64 KB
rom: 5740 B 64 KB 8.76%
512 B 0.00% 0 GB
-e Done!
.
.
.
.
Creating load file for Flash: simpleserial-aes-CW308_NEORV32.hex
impleserial-aes-CW308_NEORV32.bin
R .signature simpleserial-aes-CW308_NEORV32.elf simpleserial-aes-CW308_NEORV32.hex
lf-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature simpleserial-aes-CW308_NEORV32.elf simpleserial-aes-CW308_NEORV32.bin
Creating load file for EEPROM: simpleserial-aes-CW308_NEORV32.eep
.
riscv32-unknown-elf-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \
-lma .eeprom=0 --no-change-warnings -O ihex simpleserial-aes-CW308_NEORV32.elf simpleserial-aes-CW308_NEORV32.eep || exit 0
Creating Extended Listing: simpleserial-aes-CW308_NEORV32.lss
n-elf-objdump -h -S -z simpleserial-aes-CW308_NEORV32.elf > simpleserial-aes-CW308_NEORV32.lss
Creating Symbol Table: simpleserial-aes-CW308_NEORV32.sym
-CW308_NEORV32.elf > simpleserial-aes-CW308_NEORV32.sym
Size after:
text data bss dec hex filename
l-aes-CW308_NEORV32.elf 11692 2dac simpleseria
+--------------------------------------------------------
me.efault target does full rebuild each ti
+ Specify buildtarget == allquick == to avoid full rebuild
+--------------------------------------------------------
+--------------------------------------------------------
+ Built for platform iCE40 Target with neorv softcore with:
+ CRYPTO_TARGET = TINYAES128C
+ CRYPTO_OPTIONS = AES128C
+--------------------------------------------------------
Programming the neorv32 bitfile along with the firmware is handled by our NEORV32Programmer class.
Running our usual Setup_Generic.ipynb (with PLATFORM set to 'CW308_NEORV32') will set this up for you:
%run '../../../../jupyter/Setup_Scripts/Setup_Generic.ipynb'
INFO: Found ChipWhisperer😍
scope.adc.clip_errors_disabled changed from True to False
scope.adc.lo_gain_errors_disabled changed from True to False
prog
chipwhisperer.capture.api.programmers.NEORV32Programmer
Then simply point to the firmware that you just compiled:
cw.program_target(scope, prog, '../../../../firmware/mcu/simpleserial-aes/simpleserial-aes-CW308_NEORV32.bin')
That’s it! You can interact with the target as you would any other “hard” core running simpleserial-aes.
scope.gain.db = 28
scope.adc.samples = 100000
trace = cw.capture_trace(scope, target, bytearray(16), bytearray(16))
cw.plot(trace.wave)
2. lowRISC Ibex RISC-V core on CW312T-XC7A35 or CW305.#
Next up is the lowRISC Ibex RISC-V core.
The ChipWhisperer repository includes a pre-built FPGA bitfile for both our XC7A35 and CW305 target boards.
Look up our XC7A35 target page for more information about this core.
This core is loaded onto the FPGA differently from the neorv32 core: Setup_Ibex.ipynb takes care of programming our pre-compiled FPGA bitfile (but does not handle the target firmware).
Note
Only CW-Husky supports programming the CW312-XC7A35 target FPGA. If you have a CW-Lite or Pro, you’ll need to use an external programmer (e.g. Xilinx Platform Cable) for this. (CW-Lite/Pro can program the CW305 target FPGA.)
PLATFORM = 'CW312_IBEX' # for CW312-XC7A35
#PLATFORM = 'CW305_IBEX'
SS_VER = "SS_VER_1_1"
%run '../../../../jupyter/Setup_Scripts/Setup_Ibex.ipynb'
INFO: Found ChipWhisperer😍
scope.gain.gain changed from 28 to 22
scope.gain.db changed from 27.844036697247706 to 25.091743119266056
scope.adc.samples changed from 100000 to 5000
(ChipWhisperer Scope WARNING|File ChipWhispererHuskyClock.py:525) ADC frequency must be between 1MHz and 300000000.0MHz - ADC mul has been adjusted to 3
(ChipWhisperer Scope WARNING|File ChipWhispererHuskyClock.py:528) ADC frequency exceeds specification (250 MHz).
This may or may not work, depending on temperature, voltage, and luck.
It may not work reliably.
You can run scope.adc_test() to check whether ADC data is sampled properly by the FPGA,
but this doesn't fully verify that the ADC is working properly.
Set scope.clock.pll._no_warning_freq if you don't want
to see this message anymore.
✅ FPGA programmed. Next you need to program the firmware using the load_demo_system.sh command from the Ibex repository.
If you’re using the CW305, the output of Setup_Ibex.ipynb will tell you how its jumpers need to be set. This is important! Without the correct settings, the target won’t get a clock.
(On the CW312-XC7A35 you’re all set: you don’t need to change CW313 jumpers from the default settings you would use with our “regular” targets.)
Again you’ll need a riscv compiler (riscv32-unknown-elf-gcc or riscv64-unknown-elf-gcc). It’s recommended you use one of lowRISC’s toolchain releases.
Compiling firmware for this core is done in the usual way:
%%bash -s "$PLATFORM" "$CRYPTO_TARGET" "$SS_VER"
cd ../../../../firmware/mcu/simpleserial-aes
make PLATFORM=$1 CRYPTO_TARGET=$2 SS_VER=$3 -j
Building for platform CW312_IBEX with CRYPTO_TARGET=TINYAES128C
SS_VER set to SS_VER_1_1
SS_VER set to SS_VER_1_1
Blank crypto options, building for AES128
riscv32-unknown-elf-gcc (crosstool-NG 1.24.0.498_5075e1f) 10.2.0
undation, Inc.2020 Free Software Fo
This is free software; see the source for copying conditions. There is NO
not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
mkdir -p objdir-CW312_IBEX
.
Welcome to another exciting ChipWhisperer target build!!
.
.
.
.
Compiling:
Compiling:
.
Compiling:
Compiling:
-en simpleserial-aes.c ...
Compiling:
-en .././simpleserial/simpleserial.c ...
-en .././hal/hal.c ...
/ibex/ibex_hal.c ...
-en .././hal//ibex/demo_system.c ...
.
.
.
.
Compiling:
Compiling:
Compiling:
.
Compiling:
-en .././hal//ibex/gpio.c ...
.en .././hal//ibex/pwm.c ..
-en .././hal//ibex/spi.c ...
Compiling:
-en .././hal//ibex/timer.c ...
-en .././hal//ibex/uart.c ...
.
Compiling:
.
.
-en .././crypto/tiny-AES128-C/aes.c ...
Compiling:
Assembling: .././hal//ibex/crt0.S
mc -mabi=ilp32 -static -mcmodel=medany -Wall -g -fvisibility=hidden -nostartfiles -ffreestanding -DF_CPU=7372800 -Wa,-gstabs,-adhlns=objdir-CW312_IBEX/crt0.lst -I.././simpleserial/ -I.././hal/ -I.././hal/ -I.././hal//ibex -I.././simpleserial/ -I.././crypto/ -I.././crypto/tiny-AES128-C .././hal//ibex/crt0.S -o objdir-CW312_IBEX/crt0.o
-en .././crypto/aes-independant.c ...
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
.
LINKING:
-en simpleserial-aes-CW312_IBEX.elf ...
Memory region Used Size Region Size %age Used
8.82% ram: 5056 B 56 KB
stack: 4 KB 8 KB 50.00%
-e Done!
.
.
.
Creating load file for Flash: simpleserial-aes-CW312_IBEX.hex
.
312_IBEX.elf simpleserial-aes-CW312_IBEX.hexom -R .fuse -R .lock -R .signature simpleserial-aes-CW
BEX.eepg load file for EEPROM: simpleserial-aes-CW312_I
Creating load file for Flash: simpleserial-aes-CW312_IBEX.bin
.eeprom --set-section-flags=.eeprom="alloc,load" \
ngs -O ihex simpleserial-aes-CW312_IBEX.elf simpleserial-aes-CW312_IBEX.eep || exit 0
.
own-elf-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature simpleserial-aes-CW312_IBEX.elf simpleserial-aes-CW312_IBEX.bin
Creating Extended Listing: simpleserial-aes-CW312_IBEX.lss
unknown-elf-objdump -h -S -z simpleserial-aes-CW312_IBEX.elf > simpleserial-aes-CW312_IBEX.lss
ing Symbol Table: simpleserial-aes-CW312_IBEX.sym
BEX.elf > simpleserial-aes-CW312_IBEX.syms-CW312_I
Size after:
text data bss dec hex filename
l-aes-CW312_IBEX.elf848 9148 23bc simpleseria
+--------------------------------------------------------
me.efault target does full rebuild each ti
+ Specify buildtarget == allquick == to avoid full rebuild
-----------------------------------------
+--------------------------------------------------------
th Ibex softcore with:W305 or CW312-A35 wi
+ CRYPTO_TARGET = TINYAES128C
+ CRYPTO_OPTIONS = AES128C
+--------------------------------------------------------
Unfortunately, programming this firmware onto the target requires an external JTAG programmer; however it doesn’t need to be expensive: Tigard works well.
Other tools supported by openocd can also be used.
Regardless of which tool you use, you will need to connect its TMS, TCK, TDI, TDO, and GND to the appropriate target header.
For the CW305, this is the 14-pin header labeled “FPGA JTAG”, located right next to the USB jack.
For the CW312-XC7A35, you can either use the target’s “FPGA Jaytag” header, or the JTAG pins found on various CW313 headers. In either case, ensure the “CW JTAG Select” DIP switches are set appropriately: we need to be connected to the FPGA’s JTAG port. The XC7A35 target page has the information that you need. (if you’re unsure: set switches 1-4 to “off”, 5-8 to “on”)
Once you’ve connected the programming hardware, you’re ready to load the target firmware. Instructions for this will depend on your programming hardware. You may need to adapt the instructions provided in the ibex-demo-system repository.
If you are using a Tigard, we’ve got you covered: simply copy the openocd script and configuration file.
Open and edit the configuration file to set _EXPECTED_ID correctly for your FPGA (i.e. a35 or a100).
Then, run the the script as follows:
%%bash
../ibex_files/load_demo_system_chipwhisperer.sh run ../../../../firmware/mcu/simpleserial-aes/simpleserial-aes-CW312_IBEX.bin
Open On-Chip Debugger 0.11.0+dev-ga89de9f76 (2024-05-30-09:12)
Licensed under GNU GPL v2
orts, readp
http://openocd.org/doc/doxygen/bugs.html
DEPRECATED! use 'adapter driver' not 'interface'
DEPRECATED! use 'ftdi vid_pid' not 'ftdi_vid_pid'
DEPRECATED! use 'ftdi channel' not 'ftdi_channel'
DEPRECATED! use 'adapter speed' not 'adapter_khz'
DEPRECATED! use 'ftdi layout_init' not 'ftdi_layout_init'
ftdi_layout_signal'di layout_signal' not '
DEPRECATED! use 'ftdi layout_signal' not 'ftdi_layout_signal'
prefer_sba` is deprecated. Please use `riscv set_mem_access` instead.
force hard breakpoints
Info : clock speed 500 kHz
Info : JTAG tap: riscv.cpu tap/device found: 0x0362d093 (mfg: 0x049 (Xilinx), part: 0x362d, ver: 0x0)
Info : datacount=2 progbufsize=8
Info : Examined RISC-V core; found 1 harts
Info : hart 0: XLEN=32, misa=0x40101104
Info : starting gdb server for riscv.cpu on 3333
Info : Listening on port 3333 for gdb connections
4300 bytes written at address 0x00000000
downloaded 4300 bytes in 0.120959s (34.716 KiB/s)
verified 4300 bytes in 0.136941s (30.664 KiB/s)
Doing reset
Info : JTAG tap: riscv.cpu tap/device found: 0x0362d093 (mfg: 0x049 (Xilinx), part: 0x362d, ver: 0x0)
From here on, things are easy again: you can interact with the target as you would any other “hard” core running simpleserial-aes.
scope.gain.db = 32
scope.adc.samples = 20000
trace = cw.capture_trace(scope, target, bytearray(16), bytearray(16))
cw.plot(trace.wave)
3. Arm DesignStart cores on CW312T-XC7A35 or CW305.#
This is much more involved: here you need to build the bitfile yourself.
Arm has a detailed step-by-step guide for this. We’ve worked to make this as simple as possible for you by adapting their guide to our FPGA target boards. However this still requires you to use Vivado, which can be a little daunting if you’ve never used it before.
But it’s worth it: at the end you’ll have a soft-core Arm bitfile on which you can run our simpleserial-based firmware, just like in the previous two examples.
Find our detailed step-by-step guide in our DesignStart repository.
assert not scope.adc.errors, scope.adc.errors