Sunday, May 10, 2020

Visual Studio FPGA Tips and Traps

This weekend I went from File-New-Project, Right-Click - Build... to a ULX3S bit file! This was originally supposed to be my blog on using Visual Studio to build (synthesize) Verilog FPGA code. Instead, this first part is just a discussion of text editor issues to be aware of in Visual Studio.

TL;DR. It can be done! Be aware of BOM, CR/LF, 32/64 bit, and other quirky issues.

My first success pic tweeted: running yosys in "right-click, build" in Visual Studio. 

Text editor issues? How can that be? Visual Studio ("VS") has been around for years. How can there be problems with something as basic as a text editor? The answer lies in the history of differences between Linux and Windows. My workstation is a Windows machine. The day job is a Microsoft shop and all of my development is on Windows. The key tools I use every day only run on Windows. My FPGA toolchain however, is all in Ubuntu Linux: WSL Ubuntu on Windows, to be exact.

With WSL came some really amazing capabilities in Windows. Just having a Linux prompt on a Windows machine that is in a DOS-like window and not a VM is just magical. But the really incredible thing is that you can call Linux apps from DOS, and you can call DOS/Windows apps from WSL! Also: The file system is shared! My C:\workspace directory for Windows is /mnt/c/workspace in WSL. (be careful when accessing WSL directories; in particular DO NOT access the Linux files inside of your %LOCALAPPDATA% folder; perhaps you found the rootfs directory in Local\Packages\CanonicalGroupLimited.UbuntuonWindow...)

Snip of warning to not edit WSL %LOCALAPPDATA% files.

Still, it is good to be aware of the directory, as it can use up a LOT of disk space. Even though I keep most of my GitHub repos and toolchain source in my C:\workspace directory, my WSL rootfs still takes up 25GB and 450,000 files.

Windows WSL rootfs files

So just because you can access those files from Visual Studio: DON'T.

Be aware that in WSL2, there's apparently a performance issue when using /mnt. All my work is in the original WSL. I do not yet have WSL2, as insider build 18917 is required. So I can't really speak to this.

Alas with these new found capabilities, the underlying fundamental differences between Windows and Linux become increasingly painful for developers. I encountered this years ago with my first Raspberry Pi. Yes, I was the kind of person that would mount the file system on my Raspberry Pi as a network share and edit files in... yes, you guess it: Visual Studio. This was almost a WSL-like experience with a putty terminal session and a drive map that made it look like my Raspberry Pi was a local file system.

There are some terrible gotchas in Visual Studio for Linux users. Not only will VS take a text file with LF line-ending characters and silently replace them with CR/LF at save time... (Linux does not play well with carriage returns at the end of lines in bash shell scripts)... no, even worse is when creating a simple text file, VS decides on its own to quietly add 3 hidden BOM characters at the beginning of the file. Many Linux apps will be quite intolerant of that when expecting a simple text file. 

So the first thing to be aware of... is that Visual Studio by default creates text files with BOM characters, when doing the Right Click on Project - Add - New Item - Text File:

My suggestion to Microsoft here is to add options to this list. The "TextFile with BOM" file option should be explicitly labeled as such as creation time, along with UTF-16 encoded files. If nothing else, a Text File should be just that: a plain, nothing-else, just UTF-8 character file.

Many people will say "why not just use VS Code?". Yes, it is true VS Code handles this all vastly better. I did have my own issues with VS Code, such as a problematic files.eol setting, but that was resolved and these days VS Code is really quite impressive.  For example, here's VS Code with a clear option of encoding and CRLF settings at the bottom of the editor:

Still, I am most comfortable in Visual Studio. Plus, thank you Day Job for the MSDN Enterprise subscription. I like the rich features, debugging, and vast array of other tools. I do use VS Code, but for different things. Even without the enterprise level, the free Visual Studio Community Edition is still quite excellent.

Fortunately, there are folks at Microsoft that are listening! I had a great offline discussion with @robotdad who will hopefully will be able to encourage some of these things to changed. This has got to be a priority if Microsoft is going to embrace WSL.

So how does the BOM issue manifest itself? The first time I tried to do an FPGA build in Visual Studio, it failed with a bizarre error message:

At first, it is a curious "no such command read_verilog" message. But upon closer inspection, what are those odd characters between "command" and "read"? Those pesky BOMs.

Now, there's no easy way that I've found to fix this. One option is to open the file with VS Code. But how crazy is that?? The whole point is to use Visual Studio with FPGA devices. Next - Visual Studio has a built-in Binary Editor. Right click on the file and select "Open with..." then choose "Binary Editor:

When viewing the file here, we can immediately see there's more than meets the eye:

As this is a binary editor, you can simply put the cursor on either the text or hex digits and press delete or backspace to remove the extra three characters.

This is such a big problem in Visual Studio, that there's an entire Fix File Encoding Extension that was first released 8 years ago, with nearly 30,000 downloads! Clearly I'm not the only one that has had this problem.

Although the above solutions work well for the 3 leading BOM characters, it is not so great for finding an replacing all the CR/LF characters with just LF. This too, is a key feature that Visual Studio shockingly ignores. A cardinal rule of text editors: if you find a text file that has line endings with only LF characters, leave it that way upon save! Instead, Visual Studio will silently replace the LF characters with CR/LF and/or add them. Try running a bash script in WSL with CR characters for line endings. Not a pretty sight. The symptom that you have errant CR characters will be the \r' : command not found" like this.
./ line 5: $'yosys\r': command not found

The dos2unix command in WSL becomes your friend.  I also have a script for converting all script files. Although an external command, this fixes both the BOM and CRLF issues. Note also: the GitHub integration does a really poor job of recognizing these changes - particularly when hidden characters are the only change in a text file.

The problems are not limited to copy and paste from other applications! Copy a block of text file editing a file in VS that is known to have only LF line terminations... and then paste it back into the same file. Check out the result with the binary editor: all of the LF terminations have been replaced with CR/LF. Not cool. No-one ever noticed or cared in Windows, but this is just horrible for files used in Linux. For example: I ran into this when processing lpf files with nextpnr.

Suggestion to Microsoft: honor line endings and fix the GitHub detection and change tracking of line endings.

Bigger suggestion to Microsoft: have some sort of "strip hidden  characters and formatting when pasting text" capability in Windows. Search for "ctrl-shift v" (the intuitive solution); it typically doesn't work. There are so many apps that I copy and paste first into Notepad, then in destination, just because I don't want all the original formatting. I've been burned on more than one occasion copying sample code from a PDF, or a web site like stackoverflow, or often just some quote from a web page that I'm pasting into an email - and get more than I bargained for with hidden characters and wonky formatting that I don't want. This is also a problem in Windows alone: copy some Linux commands from Notepad into a bash script in Visual Studio... yup, you got it: the line endings are all CR/LF even if the file was only using LF. Under no circumstances should LF-only text be pasted back as LF/CR. 

The next thing to be aware of: on at least some (most?) systems... is that Visual Studio is still a 32-bit app. On a 64-bit operating system, WSL will be 64 bit. What's the big deal? Well, if you want to call a WSL app from Visual Studio on a 64 bit system, you cannot do this:

wsl yosys Verilog.ys

You can do that from a DOS prompt, but not from a VS build script. Otherwise an error like this will occur:

1>------ Build started: Project: SampleFail, Configuration: Release Any CPU ------
1>  'c:\windows\system32\wsl.exe' is not recognized as an internal or external command,
1>  operable program or batch file.
1>C:\Users\gojimmypi\source\repos\SampleFail\SampleFail\SampleFail.csproj(16,5): error MSB3073: The command "c:\windows\system32\wsl.exe yosys Verilog.ys" exited with code 9009.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Whaat? "not recognized as an internal or external command"? Yet the wsl.exe file is right there! Well, there are more magic tricks going on behind the scenes to make 32bit and 64 bit apps all work together. This is called the File System Redirector. Read the first sentence on that page, it is not a typo:
The %windir%\System32 directory is reserved for 64-bit applications on 64-bit Windows.
Yes, System32 is for 64 bit apps. Pretty crazy, eh? So ya - the solution is wow. No, literally: WOW64. I've used this in registry access at the day job, but this was the first I had seen it for file systems. The trick here is a magical pseudo-directory called Sysnative. If you go looking for it, you won't find it:

But if you try to use it in a path from Visual Studio.... voila! But note you cannot use this interactively in a DOS prompt:

%windir%\Sysnative\wsl.exe yosys Verilog.ys

In the category of feature requests for Microsoft: it would be awesome to have a DOS command prompt have the option "run as 32bit app" to test and debug Visual Studio build scripts that can "see" the Sysnative directory.

Suggestion to Microsoft: have an environment variable that ensures proper usage of System32 or Sysnative automatically. I suppose the PROCESSOR_ARCHITECTURE is a workaround. (look for values like AMD64, x86, see stackoverflow) . For me, I'll probably use the if exist:
echo off
IF EXIST "%windir%\Sysnative\wsl.exe" (
  echo "Using Sysnative\wsl"
  ) ELSE ( 
    IF EXIST "%windir%\System32\wsl.exe" (
      echo "Using System32\wsl"
      ) ELSE (
        echo " WSL Not found!"

So in the end, yes: there are quite a few "issues" for the Visual Studio WSL user. Most seem to be relatively simply, petty fixes. I'm hoping these issues can be addressed by Microsoft so that the Visual Studio development with WSL is a bit more friendly.

Sunday, April 12, 2020

More on FOMU Circuit Python in WSL.

After the previous pains of getting Circuit Python to just build for the FOMU, it is time to move on to more interesting things.... actually putting it on the FOMU!

Back to my first notes on this topic, the dfu-util is needed. There are a variety of sources of this app. Unfortunately the only one I was able to get working was from the ad-spam-laden sourceforge (it's really a shame what that site has become). Fortunately there's a ULX3S dfu-util repo with a precompiled binary. No ads.  (If you, too are tired of so may ads, check out my pi-hole blog).

At this early stage of the game, there's really quite limited documentation available. One observation from the Makefile is that during the (by default relatively quiet) build of Circuit Python... the only thing happening there is just that: the RISC-V (more specifically VexRiscv) compile of "C" code into a binary DFU file. This means that the FOMU needs to have been pre-configured: make the FPGA a soft CPU.

Fortunately, I had already loaded foboot onto my FOMU. Specifically, I took the shortcut of using a pre-built version of hacker-updater-v2.0.3.dfu as noted here. To do something using with another FPGA, say... the ULX3S... clearly I'm going to have to get control of building that bitstream.

But for now, let's run with that. The FOMU is configured as a soft CPU, which we learned from the Circuit Python text file is a VexRisc. The "only" thing needed is some code for it to run: Circuit Python.

There's an apt-get install version of dfu-util for Ubuntu, but it does not work in WSL. It does not "see" the FOMU

$ which dfu-util
$ sudo dfu-util -l
[sudo] password for gojimmypi:
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to

There's another one that came with the FOMU Toolchain mentioned in my previous blog, but that one does not work either, giving instead this error message:
$ /opt/fomu-toolchain-linux_x86_64-v1.5.6/bin/dfu-util -l
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2019 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to

unable to initialize libusb: LIBUSB_ERROR_OTHER
Of course, I'm doing this in WSL (not WSL2).. and there are known problems with native USB drivers not working in WSL. Given the libusb error, I'm pretty sure neither of those linux versions of dfu-util will ever work. However, one of the amazing things about WSL: Native Windows and DOS apps can be launched from the command prompt! The DOS version does work!
git clone
$WORKSPACE/dfu-util/bin-win64/dfu-util.exe -l
This should identify the FOMU installed:
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to

Found DFU: [1209:5bf0] ver=0101, devnum=12, cfg=1, intf=0, path="1-1.3", alt=0, name="Fomu Hacker running DFU Bootloader v2.0.3", serial="UNKNOWN"
Note that I have DFU Bootloader v2.0.3 installed on the FOMU as described in my prior blog. In particular, see tinyusb issues #293 for some oddities that I encountered when using older versions of the bootloader. See also  WSL Issue 2185 and 3745 regarding native USB drivers in WSL.

If you need to make:
make BOARD=fomu clean
make BOARD=fomu
The send the firmware to the device:
cd $WORKSPACE/circuitpython/ports/litex
$WORKSPACE/dfu-util/bin-win64/dfu-util.exe  -D ./build-fomu/firmware.dfu
Note that this is a "soft" program of the FPGA. The firmware.dfu can't be sent to the FOMU again until power cycle. In fact, after a power cycle, it *needs* to be sent again. Normally I might say something about preventing corruption to be careful to to the USB eject. But after removing the device, it is no longer a Circuit Python.

For reference, to put foboot in place:

mkdir -p fomu
cd fomu

# for WSL, we need the DOS executable with usblib support:
$WORKSPACE/dfu-util/bin-win64/dfu-util.exe -D hacker-updater-v2.0.3.dfu

# for regular linux:
# dfu-util -D hacker-updater-v2.0.3.dfu

The thing is: we don't have a bootloader for the ULX3S. It does not show up as a device for dfu-util. Recall we use the ujprog to upload FPGA bitstreams to the FPGA, and the litex_term to upload the firwmware.bin file.

As noted in a prior blog, I have a soft CPU script that shows how this is done on the ULX3S:


cd $WORKSPACE/litex-boards/litex_boards/targets/soc_basesoc_ulx3s/gateware

$WORKSPACE/ulx3s-examples/bin/ujprog.exe top.bit

cd $WORKSPACE/circuitpython/ports/litex/build-ulx3s

litex_term --serial-boot --kernel firmware.bin /dev/ttyS15

Unfortunately, I've spent a bunch of time chasing toolchain and memory problems. After updating everything to solve a problem where Migen was not creating a top.v file (which as it turns out, was even not necessary to solve the problem I was seeing), LiteX is now complaining that memtest is failing.

My specific memory chip on my ULX3S is a AS4C32M16SB. I did at least learn how to do a memory check:

git clone
cd $WORKSPACE/ulx3s-bin/fpga/memtest/memtest-85k

# be sure to select the correct bit file 32MB or 64MB for your specific memory chip
$WORKSPACE/ulx3s-examples/bin/ujprog.exe ulx3s_85f_memtest_32MB_190MHz_300deg.bit 

 A good memory test looks like this on an HDMI monitor:

The top line is not used. The middle line is the number of memory tests completed. The red bottom line is the number of errors.

A bad memory test, say when a 64MB test is loaded for a 32MB chip, looks like this:\\

The 64MB test blinks onboard LEDs like this. The 32MB test does not.

In the meantime, there are some really quite talented folks that do this stuff rather easily. Perhaps I'll have more luck next time.

See also: Adafruit Circuit Python Issues 2604: Fomu port of CircuitPython

Saturday, April 11, 2020

Circuit Python on the FOMU in WSL (plus the pains of building your own RISC-V toolchain)

I started down the road of learning FPGA Circuit Python last month, with the (admittedly overly-ambitious) goal of getting Circuit Python working on the ULX3S. I was inspired to revisit this today when I saw Adafruit Blog - CircuitPython 5.2.0 Released - that specifically mentioned LiteX for Circuit Python!! In this case, for the FOMU.

TL;DR - WSL is by default NOT Case Sensitive. Use fsutil.exe in a DOS admin window to change this for each directory. To compile, riscv64-unknown-elf-gcc is needed, but the RISC-V GitHub GNU Repo does not work here to build Circuit Python. Use the FOMU toolchain. The make parameter should be lower case: make BOARD=fomu

If you are interested in Circuit Python, check out this CircuitBrains Deluxe on Crowd Supply.

See Adafruit instructions on building Circuit Python. All of the downloads for Circuit Python are available online. Well, all but of course the FOMU that I am most interested in. Hopefully it will be there soon, so for now we are doing this the hard way. (no fun if it is too easy, right?)

I could not find any documentation on the FOMU build, so I had to dig and search for keywords. The initial part of fetching from GitHub is pretty standard, so we'll start there:

git clone
cd circuitpython
git submodule sync
git submodule update --init
make -C mpy-cross
When doing the git submodule update --init in DOS (I sometimes do that, since my git clones are in C:\workspace - even though I compile in WSL from /mnt/c/workspace/)... I saw these errors:
git submodule update --init
Submodule 'extmod/ulab' ( registered for path 'extmod/ulab'
Submodule path 'lib/nrfutil': checked out '9e7dfb28a5c6f3d7a19340971b32e0c2b4128ecf'
Submodule path 'lib/tinyusb': checked out '1f95f439e11f519e69d75a4a8b7b9f28eaf5060e'
error: unable to create file tests/decomp-bad-inputs/00/id:000000,sig:11,src:000000,op:flip1,pos:10: Invalid argument
error: unable to create file tests/decomp-bad-inputs/00/id:000012,sig:11,src:000000,op:arith8,pos:11,val:+6: Invalid argument
error: unable to create file tests/decomp-bad-inputs/00/id:000013,sig:11,src:000000,op:arith8,pos:12,val:-9: Invalid argument
error: unable to create file tests/decomp-bad-inputs/00/id:000014,sig:11,src:000000,op:havoc,rep:16: Invalid argument
error: unable to create file tests/decomp-bad-inputs/00/id:000015,sig:11,src:000000,op:havoc,rep:2: Invalid argument
... many, many more similar errors
When doing the git submodule update --init from WSL just a few moments later, I did not see those errors. Perhaps there's some issue with Windows file names. (edit: I learned later this is likely a case sensitivity issue, see below).

For the FOMU, there's a Makefile in ./ports/litex
cd ./ports/litex
make BOARD=fomu
Edit: note that a case insensitive directory setting may allow BOARD=FOMU to work. ymmv. The safest one to use is a lower-case: BOARD=fomu.

If you see an error like this:
xargs: riscv64-unknown-elf-gcc: No such file or directory
../../py/ recipe for target 'build-FOMU/genhdr/qstr.i.last' failed
make: *** [build-FOMU/genhdr/qstr.i.last] Error 127
make: *** Deleting file 'build-FOMU/genhdr/qstr.i.last'
Then try riscv64-unknown-elf-gcc --version to see if this RISC-V compiler is installed (perhaps you need to install the compiler). sadly, this is a different version of the compiler than is used in my ULX3S toolchain builder, that uses rv32i installed to /opt/riscv32i. Of course it does. Sometimes I wonder if this is all a hard drive manufacturer conspiracy to use as much disk space as possible. ;)

If like me you don't have the right compiler installed, make sure you have plenty of disk space:
This process will start by downloading about 200 MiB of upstream sources, then will patch, build, and install the toolchain. If a local cache of the upstream sources exists in $(DISTDIR), it will be used; the default location is /var/cache/distfiles. Your computer will need about 8 GiB of disk space to complete the process.

Here's what I did in WSL:
sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev
git clone --recursive  
cd riscv-gnu-toolchain  
./configure --prefix=/opt/riscv
sudo mkdir /opt/riscv
sudo chown $USER /opt/riscv
if [ "$(echo $PATH | grep  /opt/riscv/bin)" == "" ]; then export PATH=$PATH:/opt/riscv/bin; fi
You may wish to put the export PATH=$PATH:/opt/riscv/bin in your ./bash.rc file.

Do NOT run make linux if you want riscv64-unknown-elf-gcc files! The linux option creates riscv64-unknown-linux-gnu files, not elf!.

My first attempt at install failed. After hours of downloading and building, the errors started here (and yes, I also incorrectly specified linux):

mv -f /mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d/elf/rtld-libc.aT /mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d/elf/rtld-libc.a
make[4]: Leaving directory '/mnt/c/workspace/riscv-gnu-toolchain/riscv-glibc/elf'
riscv64-unknown-linux-gnu-gcc    -nostdlib -nostartfiles -r -o /mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d/elf/librtld.os '-Wl,-(' /mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d/elf/dl-allobjs.os /mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d/elf/rtld-libc.a -lgcc '-Wl,-)' \
riscv64-unknown-linux-gnu-gcc    -nostdlib -nostartfiles -shared -o /mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d/elf/               \
          -Wl,-z,combreloc -Wl,-z,relro -Wl,--hash-style=both -Wl,-z,defs       \
          /mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d/elf/librtld.os -Wl,--version-script=/mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d/            \
          -Wl,                       \
/opt/riscv/lib/gcc/riscv64-unknown-linux-gnu/9.2.0/../../../../riscv64-unknown-linux-gnu/bin/ld: /mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d/elf/librtld.os: in function `process_envvars':
/mnt/c/workspace/riscv-gnu-toolchain/riscv-glibc/elf/rtld.c:2484: undefined reference to `__GI___open64_nocancel'
/opt/riscv/lib/gcc/riscv64-unknown-linux-gnu/9.2.0/../../../../riscv64-unknown-linux-gnu/bin/ld: /mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d/elf/librtld.os: in function `dl_main':
/mnt/c/workspace/riscv-gnu-toolchain/riscv-glibc/elf/rtld.c:1317: undefined reference to `__access'
/opt/riscv/lib/gcc/riscv64-unknown-linux-gnu/9.2.0/../../../../riscv64-unknown-linux-gnu/bin/ld: /mnt/c/workspace/riscv-gnu-toolchain/riscv-glibc/elf/rtld.c:2103: undefined reference to `__access'
/opt/riscv/lib/gcc/riscv64-unknown-linux-gnu/9.2.0/../../../../riscv64-unknown-linux-gnu/bin/ld: /mnt/c/workspace/riscv-gnu-toolchain/riscv-glibc/elf/rtld.c:1564: undefined reference to `__GI___close_nocancel'
and eventually culminated here:

/opt/riscv/lib/gcc/riscv64-unknown-linux-gnu/9.2.0/../../../../riscv64-unknown-linux-gnu/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
Makefile:496: recipe for target '/mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d/elf/' failed
make[3]: *** [/mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d/elf/] Error 1
make[3]: Leaving directory '/mnt/c/workspace/riscv-gnu-toolchain/riscv-glibc/elf'
Makefile:258: recipe for target 'elf/subdir_lib' failed
make[2]: *** [elf/subdir_lib] Error 2
make[2]: Leaving directory '/mnt/c/workspace/riscv-gnu-toolchain/riscv-glibc'
Makefile:9: recipe for target 'all' failed
make[1]: *** [all] Error 2
make[1]: Leaving directory '/mnt/c/workspace/riscv-gnu-toolchain/build-glibc-linux-rv64imafdc-lp64d'
Makefile:234: recipe for target 'stamps/build-glibc-linux-rv64imafdc-lp64d' failed
make: *** [stamps/build-glibc-linux-rv64imafdc-lp64d] Error 2
I was about to open a GitHub issue, and then thought - hm... perhaps I just read the rest of the README, eh? I know, I know, actually RTFM'ing takes away all the fun, but it is rather embarrassing when someone tells you to read the fine manual in response to asking for help. Sure enough, I found this:
If building a linux toolchain on a MacOS system, or on a Windows system using the Linux subsystem or cygwin, you must ensure that the filesystem is case-sensitive. A build on a case-insensitive filesystem will fail when building glibc because *.os and *.oS files will clobber each other during the build eventually resulting in confusing link errors. @tnt aka smunaut has a RISC-V USB project in the works.
In order to install RISC-V for WSL I found this article that noted after Windows 10 version 17093 there's a command fsutil.exe for setting case sensitivity:

fsutil.exe file setCaseSensitiveInfo riscv-gnu-toolchain enable

Note this needs to be run in a DOS Window, not WSL, and with Administrative permissions:

BUT! Note the command is only for the specified directory, and the attribute is NOT inherited  (and certainly does not get applied to each existing sub-directory). So we need to iterate through all sub-directories individually. Yes, I'm sure many readers are rolling their eyes at this point, asking why I am doing this in WSL and not a "real" Linux machine or even a VM; what am I doing in Windows? I ask myself that sometimes, too. Well, I just think WSL is just too cool! Plus, I suppose that I like the challenge. So anyway, here's what I did to set case sensitivity:

cd \workspace\riscv-gnu-toolchain\
for /f %f in ('dir /ad /s /b') do fsutil.exe file setCaseSensitiveInfo %f enable
There are many directories. Be patient...

As a reminder, that command is meant to be executed interactively. If placed into a batch file, the percent symbols need to be doubled up.

Now that everything in the riscv-gnu-toolchain directory is case sensitive, I ran make again:

cd /mnt/c/workspace/riscv-gnu-toolchain
This does a full rebuild, taking again a very long time. Did I mention being patient?

If you can run /opt/riscv/bin/riscv64-unknown-elf-gcc --version but see a lot of errors when doing a make BOARD=fomu like:
/opt/riscv/lib/gcc/riscv64-unknown-elf/9.2.0/include/stdint.h:9:16: fatal error: stdint.h: No such file or directory
That means the RISC-V make either failed... or you didn't wait until it finished. (for me, it was the latter; did I mention being patient?) Once the RISC-V make is complete, the FOMU code can be built:
cd /mnt/c/workspace/circuitpython/ports/litex

Which resulted in this output:

Use make V=1, make V=2 or set BUILD_VERBOSE similarly in your environment to increase build verbosity.
QSTR updated
make: msgfmt: Command not found
../../py/ recipe for target 'build-FOMU/genhdr/' failed
make: *** [build-FOMU/genhdr/] Error 127

so ok, a quick google yields something useful on stackoverflow

apt-get install gettext

and so even after than, I saw even more errors like this:
/opt/riscv/lib/gcc/riscv64-unknown-elf/9.2.0/../../../../riscv64-unknown-elf/bin/ld: build-FOMU/lib/libm/math.o: in function `floorf':
/mnt/c/workspace/circuitpython/ports/litex/../../lib/libm/math.c:790: undefined reference to `__addsf3'
/opt/riscv/lib/gcc/riscv64-unknown-elf/9.2.0/../../../../riscv64-unknown-elf/bin/ld: /mnt/c/workspace/circuitpython/ports/litex/../../lib/libm/math.c:795: undefined reference to `__addsf3'
/opt/riscv/lib/gcc/riscv64-unknown-elf/9.2.0/../../../../riscv64-unknown-elf/bin/ld: build-FOMU/lib/libm/math.o:/mnt/c/workspace/circuitpython/ports/litex/../../lib/libm/math.c:817: more undefined references to `__addsf3' follow
/opt/riscv/lib/gcc/riscv64-unknown-elf/9.2.0/../../../../riscv64-unknown-elf/bin/ld: build-FOMU/firmware.elf(.text): relocation ".L15+0x0 (type R_RISCV_RVC_JUMP)" goes out of range
/opt/riscv/lib/gcc/riscv64-unknown-elf/9.2.0/../../../../riscv64-unknown-elf/bin/ld: /opt/riscv/lib/gcc/riscv64-unknown-elf/9.2.0/libgcc.a(divsf3.o): file class ELFCLASS64 incompatible with ELFCLASS32
/opt/riscv/lib/gcc/riscv64-unknown-elf/9.2.0/../../../../riscv64-unknown-elf/bin/ld: final link failed: file in wrong format
collect2: error: ld returned 1 exit status
Makefile:177: recipe for target 'build-FOMU/firmware.elf' failed
make: *** [build-FOMU/firmware.elf] Error 1
So I did another one of these, this time for the circuitpython directory:

for /f %f in ('dir /ad /s /b') do fsutil.exe file setCaseSensitiveInfo %f enable

and things got even worse:
Makefile:30: *** Invalid BOARD specified.  Stop.
So I tried to clean it, same error:
$ make BOARD=FOMU clean
Makefile:30: *** Invalid BOARD specified.  Stop.
Turns out that was case sensitive, so then it is:
make BOARD=fomu clean
make BOARD=fomu
Ok, at the point, readers must really, really wonder why I use Windows. I know, I know. But I'm persistent.

It still failed. I gave up and asked for help.
I didn't get an answer to "should I use the FOMU toolchain instead of the RISC-V, so I thought I'd try it:

# fetch and extract
tar -xzf fomu-toolchain-linux_x86_64-v1.5.6.tar.gz
sudo mv fomu-toolchain-linux_x86_64-v1.5.6 /opt/fomu-toolchain-linux_x86_64-v1.5.6

# set the path
if [ "$(echo $PATH | grep fomu-toolchain-linux_x86_64-v1.5.6)" == "" ]; then export PATH=$PATH:/opt/fomu-toolchain-linux_x86_64-v1.5.6/bin; fi

# verify it is in the path:
which riscv64-unknown-elf-gcc
riscv64-unknown-elf-gcc --version

cd /mnt/c/workspace/circuitpython/ports/litex
make BOARD=fomu  clean

And... TADA! A successful Circuit Python build for the FPGA FOMU!! Whew.

$ make BOARD=fomu
Use make V=1, make V=2 or set BUILD_VERBOSE similarly in your environment to increase build verbosity.
/opt/fomu-toolchain-linux_x86_64-v1.5.6/bin/../lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: warning: section `.bss' type changed to PROGBITS

739752 bytes free in flash firmware space out of 1048576 bytes (1024.0kB).
116920 bytes free in ram for stack and heap out of 131072 bytes (128.0kB).

Create build-fomu/firmware.dfu
python3 ../../tools/ -b build-fomu/firmware.bin -D 0x1209:0x5bf0 "build-fomu/firmware.dfu"

Other notes (thanks @pdp7): Using Python for creating hardware

Migen Step by Step Tutorial

LiteX is a fork of MiSoC

MiSoc and LiteX are both based on Migen

Sunday, March 29, 2020

LiteX Soft CPU on the ULX3S - reloading firmware without reflashing the soft CPU

My next post (aka notes to self) on getting a RISC-V compiled app onto the ULX3S using LiteX.

TL;DR; press the reset button!

Quite a diversion from my day job with SQL and C# and web apps is this fascinating world of soft CPU's and embedded devices. Here's what I learned this weekend:

In my prior blogs, I considered getting Circuit Python running on the ULX3S. There are a lot of moving parts, so I got started with implementing the RISC-V soft CPU on the FPGA. Recall we cannot run Circuit Python on the ESP32 because of hardware limitations (missing USB OTG), however the ESP32-S2 will (in theory) work with Circuit Python. Next, I rambled on a bit regarding various features of LiteX that I was exploring in my prior blog, in the end creating a script with everything I learned.

Refresher:  Onboard the ULX3S is an ECP5 FPGA. We first need to create a soft CPU bitstream that is loaded onto the ECP5LiteX also creates a BIOS that gets loaded over the serial port. Ok, all fine and dandy, but I seem to only be able to load that BIOS once and then the terminal becomes unresponsive. This makes sense, as the processor stays in the while loop after liftoff. The bios does not appears to be an RTOS.

ULX3S shown with FPGA/BIOS/firmware programming USB cable

Supposedly that BIOS should be able to reload firmware apps. Well, there's this mystery boot_helper. What does this extern do? I suspect that's what loads the BIOS. Then what? There's this 4 line boot-helper-picorv32.S file. Not much help there. The "What is LiteX" introduction does seem to indicate that the development cycle includes reloading the soft CPU, as the "design flow in a nutshell" indicates going back to step 1. I'd like to go back to step 6, skipping the re-synthesis of the soft CPU every time I change the firmware.

The LiteX for the ULX3S has a serial port configured as Tx on Pin L4 (FTDI RxD) and Rx on Pin M1 (FTDI TxD). See the schematic. These pins are not available on either of the external ULX3S headers.

FTDI RxD/TxD USB Serial on ULX3S FPGA pins L4 and M1
I had thought perhaps the BIOS would be looking on a pair of pins implemented in the FPGA as a serial port. Nope. Those pins are definitely hard wired the the FTDI USB serial port.

So what else is there? Well, the BIOS is clearly not an RTOS. So we're definitely waiting forever and doing nothing in that while (1) statement. How else does a CPU begin again? Reset of course! Check out the rst implementation in LiteX. It is hooked to R1 of the FPGA. What's that?

R1 (aka BTN_F1) on the ULX3S
That's the F1 button!! (The "Fire 1" position when the ULX3S is in gamer mode! lol). This is also labeled as "B1" on the PCB, located near the SD card, right under the text "2.5V/3.3V"

It turns out the architecture is not [CPU] - [BIOS] - [firmware]. Instead, the simpler: [CPU (with tiny, baked in BIOS] - [BIOS (with external firmware)].  Now, one could certainly write something in the BIOS to, say load an OS. But that's not what LiteX is doing out of the box in this example.

The architecture naming is a bit misleading, as there is part of the CPU implemented as a BIOS as seen at processor boot time on the LiteX. Unfortunately the external "C" program is also called BIOS (firmware).

So just leave litex_term running and press the F1 (CPU reset) button to reload the BIOS firmware. See my bash script. Each time you update and compile the BIOS code, press the F1 button to reload it onto the soft CPU.

I've created LiteX Pull Request #445 that adds some comments to hopefully help others that may encounter these issues.

How many times can an FPGA be reprogrammed? Well, the folks at Numato claim "SRAM based FPGAs can be programmed as many times as necessary. There is no limit..."

There's also the possibility of using a logic analyzer internally to the FPGA. Also mentioned in the What is LiteX is something called litescope. See the Debugging with ChipScope for more information, as there's not much in the Wiki as of the data of this blog. The architecture image provides some insight. See also the

So now.. I wonder if I can single-step code soft CPU code with OpenOCD. And that litescope! That sounds super interesting...

Saturday, March 28, 2020

RISC-V on the ULX3S with LiteX - Part 2

First .. the exciting news: With 24 days still left in the Crowd Funding Campaign, the ULX3S is within a few dollars of reaching their $40K stretch goal!! I'm so happy to see their success. I've been super happy with mine. (Edit: now nearly 300% funded by the time I publish this!)

TL;DR: Check out this script used to create a soft RISC-V CPU on the ULX3S.

Back to my fomu! I revisited the Adafruit Feather M0 Express - A request for the USB device descriptor failed: Issue #293 on GitHub in the hathach/tinyusb repo. The suggestion was to simply update my fomu to see if the Feather M0 problems would go away:

The last few lines of the
dfu-suffix -v 1209 -p 70b1 -a $output/${platform}-updater-${release}.dfu
dfu-suffix -v 1209 -p 70b1 -a $output/${platform}-foboot-${release}.dfu
but I saw an error when trying to do that:
C:\Download\dfu-util>dfu-suffix -v 1209 -p 70b1 -a fomu\hacker-updater-v2.0.3.dfu
dfu-suffix (dfu-util) 0.9

Copyright 2011-2012 Stefan Schmidt, 2013-2014 Tormod Volden
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to

Please remove existing DFU suffix before adding a new one.
so I next tried using dfu-util, as noted here:
C:\Download\dfu-util>dfu-util -D fomu\hacker-updater-v2.0.3.dfu
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to

Match vendor ID from file: 1209
Match product ID from file: 70b1
Opening DFU capable USB device...
ID 1209:5bf0
Run-time device DFU version 0101
Claiming USB DFU Interface...
Setting Alternate Setting #0 ...
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 0101
Device returned transfer size 1024
Copying data from PC to DFU device
Download        [=========================] 100%       112828 bytes
Download done.
state(7) = dfuMANIFEST, status(0) = No error condition is present
state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present

Since that seems to have been successful, I will return to the ULX3S for now.

A quick check of the rxrbln/picorv32 ULX3S fork that is is included in my full toolchain install and I'm still not yet able to build:

gojimmypi@ubuntu:~/workspace/rxrbln-picorv32/picosoc$ git fetch
gojimmypi@ubuntu:~/workspace/rxrbln-picorv32/picosoc$ git pull
Already up to date.
gojimmypi@ubuntu:~/workspace/rxrbln-picorv32/picosoc$ make
iverilog -s testbench -o hx8kdemo_tb.vvp hx8kdemo_tb.v hx8kdemo.v spimemio.v simpleuart.v picosoc.v ../picorv32.v spiflash.v `yosys-config --datdir/ice40/cells_sim.v`
picosoc.v:70: error: NULL port declarations are not allowed.
Makefile:20: recipe for target 'hx8kdemo_tb.vvp' failed
make: *** [hx8kdemo_tb.vvp] Error 1

So ok, I'll give that one some more time.

Refresher on getting Micropython onto the fomu:
cd /mnt/c/workspace
mkdir -p fomu
cd fomu
dfu-util -D micropython-fomu.dfu
Should give an output like this:
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to

Match vendor ID from file: 1209
Match product ID from file: 5bf0
Opening DFU capable USB device...
ID 1209:5bf0
Run-time device DFU version 0101
Claiming USB DFU Interface...
Setting Alternate Setting #0 ...
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 0101
Device returned transfer size 4096
Copying data from PC to DFU device
Download        [=========================] 100%       136164 bytes
Download done.
state(7) = dfuMANIFEST, status(0) = No error condition is present
state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present
Mine showed up as COM8 and For more details on how a RISC-V soft CPU runs MicroPython, see the Fomu as a CPU section of the fomu workshop.

I've been following along with the development of picosoc for the ULX3S. This is included in the full toolchain build, or can be fetched from here:

git clone
To build:

# use the rxrbln firmwware
cd $WORKSPACE/rxrbln-picorv32/picosoc

# there have been some recent additions to the source code; some files not included in the repo
# so get an older, know-to-compile version:
git checkout b1cd395b

make ulx3s_fw.img
$WORKSPACE/ulx3s-examples/bin/ujprog.exe -j FLASH -f 0x200000 ulx3s_fw.img

Use the LiteX CPU
# make the soft CPU
cd $WORKSPACE/litex-boards/litex_boards/targets
./ --device LFE5U-85F --cpu-type picorv32

# show the files built
echo "ULX3S Gateware:"
ls $WORKSPACE/litex-boards/litex_boards/targets/soc_basesoc_ulx3s/gateware -al

echo "ULX3S BIOSL"
ls $WORKSPACE/litex-boards/litex_boards/targets/soc_basesoc_ulx3s/software/bios -al

# put the soft CPU on the ULX3S
cd $WORKSPACE/litex-boards/litex_boards/targets/soc_basesoc_ulx3s/gateware
$WORKSPACE/ulx3s-examples/bin/ujprog.exe top.bit

cd $WORKSPACE/litex-boards/litex_boards/targets/soc_basesoc_ulx3s/software/bios
litex_term --serial-boot --kernel bios.bin /dev/ttyS15

Press enter, and you should see a litex> prompt. Type reboot As a reminder, if you keep getting an error like this:

ULX2S / ULX3S JTAG programmer v 3.0.92 (built Feb 18 2019 10:55:47)
FT_Open() failed
Cannot find JTAG cable.
Check to make sure NOTHING is using the ULX3S, including perhaps a litex_term or putty session. (yes, I've bumped into that more than once).

A big Thank You to @GregDavill  for these tips on the twitter thread:

The LiteX bios is what you're seeing running.  
By default, LiteX builds this to execute from address 0x00000000. This is an address space inside the FPGA, using blockram. Litex embeds the code inside so it's baked into the bit-stream. 
uart_sync() just waits until internal uart FIFOs are cleared. (Which ensures that printf data  has been sent to the PC...) printf also relies on interrupts, so once you've disable interrupts printf no longer works.

The bios exists to initialise things like SDRAM, which you can see it doing here. It then tries to load a USER program from SD/FLASH/Serial/Ethernet.

According to the timvideos "what is litex" the flterm program is what is needed to interact with the bios. As of the date of this blog, I've included that in the full ULX3S toolchain install.

Beware there's an old implementation of traps on riscv32 that may cause code crashes. (e.g. soft debugging)

I found an example using flterm: This next section is an unsuccessful attempt to upload firmware with flterm. (it just sits there waiting for something)

cd $WORKSPACE/flterm
./flterm --port /dev/ttyS15 --kernel $WORKSPACE/rxrbln-picorv32/firmware/firmware.bin --kernel-adr 0x40000000

Searching for the term "liftoff" and I found two occurrences here and here:
# remote.origin.url=

# this is the one that gets compiled:

# plus this older file:

I created a script soon to be pushed to the ulx3s-toolchain setup to illustrate how I created a picorv32 soft CPU on the ULX3S using LiteX. See my next blog on updating the firmware.

Thursday, March 26, 2020

ESP32-S2 Arrival Day! WSL test drive

My ESP32-S2 Saola R1 arrived!!

What exactly is that? Well, I wondered the same thing. Per the Espressif Products Ordering Information (see page 21)

That means "ESP32-S2 general purpose development board, embeds ESP32-S2-WROVER, 4 MB flash, with pin header".  The "R" means it includes 2MB of PSRAM, (as opposed to the "M" that does not)... and the fact that it is an "R" and not an "RI" means my antenna is the "internal PCB onboard antenna" (as opposed to the "External IPEX antenna".

When mine starts up, it gives some basic info:

Make thanks to @unexpectedmaker for posting an informative video on the ESP32-S2 toolchain setup, including this tip on OTG pins:

ESP32-S2 USB OTG Pins   credit: @unexpectedmaker
I've adapted those notes to run my idf in WSL. There are some dependencies:

sudo apt-get install git wget flex bison gperf python python-pip python-setuptools cmake ninja-build ccache libffi-dev libssl-dev
sudo apt-get install python3 python3-pip python3-setuptools

# system-wide update to default to python3
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 10

See also the install documentation.

I also have this ESP32 install as part of my full ULX3S toolchain installer. (see upstream repo)

Thank you @i_grr for this:
One more thing, do export ESPPORT=/dev/ttyS16 once in the console session, and never have to pass -p argument to
# copy hello world
cp -r $IDF_PATH/examples/get-started/hello_world esp32-S2_hello_world

cd esp32-S2_hello_world set-target esp32s2 menuconfig
Apparently the menuconfig will assign settings only to this project (again, thank you @unexpectedmaker for the informative video!)

To build: build

To flash: -p /dev/ttyS16 -b 921600 flash

To monitor (the command-line equivalent of putty): -p /dev/ttyS16 -b monitor

Ctrl-[ to cancel

See An Introduction to Modern CMake

more to come...

Saturday, March 14, 2020

RISC-V on the ULX3S with LiteX

Today is ULX3S Campaign Launch Day on Crowd Supply!!

As I write this, funding is at 40% in just the first hour!

In pursuit of my ongoing quest to get Circuit Python working on my ULX3S.... I decided to try out LiteX. I wasn't able to get the rxrbln picorv32 picosoc for ULX3S working (yet) due to some missing files that have not yet been checked in. Part of the journey is simply figuring out which working components to use.

LiteX is included in my full toolchain build for the ULX3S (see my prior blog).

Full ULX3S toolchain directory list
Once everything is installed (OMG, it takes the better part of a day)... we can get started.

First: if you are considering getting your own ULX3S from the upcoming Crowd Supply campaign, be aware that only the larger 45F and 85F versions are available options (and capable?) of running the LiteX VexRiscv.

Some key terminology from timvideos to get started: Gateware (as in Field Programmable Gate Array) is the stuff that gets loaded onto the FPGA. Firmware is the application code that the soft CPU will execute. The BIOS is bootstrapping code baked into FPGA.

Note that I installed my development toolchain on WSL Ubuntu. I've also tested the install multiple times on VM's with real Ubuntu. But here, my blog is about using WSL, so all of my stuff is installed on my local C:\workspace directory, or from WSL's perspective: /mnt/c/workpace. On a real Ubuntu machine, simply replace that with your own ~/workspace/ directory.

Why didn't I just put my workspace in the WSL ~/workspace directory instead? Well for one, I can completely wipe out WSL and reinstall, and all my Windows workspace files are still there. I can also access those files easily from Windows and Visual Studio in particular. I'm still waiting on WSL2 (only available to Windows insider / preview at this time, which I chose not to sign up for) - and I believe I need to rip & replace for that version.

LiteX is a code generator. Not only does it create Verilog, but also a bash script to run yosys / nextpnr / ecppack to actually generate an ECP5 FPGA bit file. The fact that it can generate code to build a complete soft CPU is frankly astonishing.

Run the for the respective device:
cd /mnt/c/workspace/litex-boards/litex_boards/targets
# ./ --device LFE5U-45F
./ --device LFE5U-85F
It is not super intuitive where files end up. There's certainly not a lot of documentation for the litex-boards repo. I searched in powershell:
Get-ChildItem -Recurse | Where-Object { $_.LastWriteTime -ge "03/08/2020 4:00pm" }
the top.bit file ended up in:
So from WSL it can be loaded onto the ULX3S like this:
# make sure nothing is using the ULX3S, including VM's, terminal sessions in putty, etc!
cd /mnt/c/workspace/litex-boards/litex_boards/targets/soc_basesoc_ulx3s/gateware

/mnt/c/workspace/ulx3s-examples/bin/ujprog.exe top.bit
Note how Windows executables can be called from the WSL prompt. The same command can be used in a DOS window:
# make sure nothing is using the ULX3S, including VM's, terminal sessions in putty, etc!
cd \workspace\litex-boards\litex_boards\targets\soc_basesoc_ulx3s\gateware

c:\workspace\ulx3s-examples\bin\ujprog.exe top.bit
Stupid things to be aware of: the serial port is running at 11500 8N1. Don't ask me how much time I wasted when using a putty saved connection for the COM port preset at 19200 and kept wondering why there was no response when trying to connect. I don't think I'll ever make that mistake again. lol

There's also an interesting bios.bin file in
My script for synthesizing the CPU ended up in:
I had found that file prior to realizing accepted a device parameter. I  have two ULX3S devices, the 12F and the 85F. Guess which one is the defined default for the LiteX build? Yup, the 45F. Did I mention if things are too easy it's no fun? At first I manually edited the build file (note the above call to does everything, including synthesizing the FPGA VexRiscv core). The default looks like this:
# Autogenerated by LiteX / git: e801dc02
set -e
yosys -l top.rpt top.ys
nextpnr-ecp5 --json top.json --lpf top.lpf --textcfg top.config --45k --package CABGA381 --speed 6 --timing-allow-fail
ecppack top.config --svf top.svf --bit top.bit
Ok, so one of the parameters looks easy enough. Ooph, but what about the "CABGA381"? Well, a quick google search and it turns out that's just a package specification. See the prjtrellis devices.json for a list of all of them. I'll assume that I each of the ECP5 options on the ULX3S will use the same package, and simply change the "45k" to "85k".

There are some bios docs.

Constraint (pin-level) implementation details can be found in platforms/

As shown in the platform file, there's no Ethernet port configured and the serial port is configured for ECP5 pins L4 and M1:

    ("serial", 0,
        Subsignal("tx", Pins("L4"), IOStandard("LVCMOS33")),
        Subsignal("rx", Pins("M1"), IOStandard("LVCMOS33"))
To build the binaries:

cd $WORKSPACE/litex-boards/litex_boards/targets

./ --device LFE5U-85F --cpu-type picorv32

cd $WORKSPACE/litex-boards/litex_boards/targets/soc_basesoc_ulx3s/gateware

# to program the FPGA as a CPU:
$WORKSPACE/ulx3s-examples/bin/ujprog.exe top.bit

cd /mnt/c/workspace/litex-boards/litex_boards/targets/soc_basesoc_ulx3s/software/bios

litex_term --serial-boot --kernel bios.bin /dev/ttyS15

More to come... see my next blog: ULX3S RISC-V with LiteX - Part 2.

Visual Studio FPGA Tips and Traps

This weekend I went from  File-New-Project, Right-Click - Build... to a ULX3S bit file ! This was originally supposed to be my blog on usin...