You
The
present
the present
of the
present
of the present
and of the present
of the present
and of the present
from
the present
from the present
And if you're building a ramp, there's going to be a black line, because that's where the camera is pointing to.
Ah, okay, I see.
You can compare it to there.
It's in the black lines.
Okay.
Hello, everyone.
Silence.
Hello, everyone.
So, my talk about building FPGA bitstreams with open source tools.
The important part here is open source tools, because building bitstreams for FPGAs was quite a pain in the ass.
A while ago, you had vendor tools, which were large.
You had to install them.
Some of them were working on Linux.
Some were working on specific distributions.
If you have the right version, it wasn't fun.
And a few years ago, there were more developments on open source tool chains for FPGAs.
And since then, a colleague of mine, Stefan, and I, I'm fiddling around with these tools and trying them out and doing stuff with FPGAs.
And the experience of that I will be showing today.
About me, I'm Michael Treta.
I work at Pengotronics as an embedded Linux developer in the graphics team.
So, usually I'm doing software in Linux, sometimes user space, sometimes drivers.
So, that's my background.
Why am I doing FPGAs first?
Agenda first.
I will show you the open source FPGA tool chain.
Then I will show you an example FPGA-based system.
And in the end, I will show you the insights and pain points we had when we were developing this system and give you a conclusion and an outlook on the next steps that we are tackling.
Use cases for FPGAs.
You want to use them if you have real-time requirements and you need a high data throughput.
That's two things that you need in graphics as well.
You have high data throughput because you need to push all the image data from one point to another.
You have real-time requirements because you have 30 FPS, 60 FPS that you have to address.
So, you have a limited time span for each frame where the frame must be finished.
And another use case or you would also use them for prototyping such systems because you can fiddle around and start experimenting with different implementations.
The FPGA open source tool chain is basically these four steps.
You start with some HDL description of your bit stream.
Usually it's very low or VHDL.
Then you have users which synthesizes the code into a net list.
Next PNR routes and places the net list for your specific FPGA implementation.
So, next PNR needs to know about your FPGA architecture and which vendor you're using.
So, this is different for Xilinx for Altera which is Intel now or Lattice.
So, you need to know something about your FPGA internal working for that.
And in the end, you have a packer which takes the router bit stream with the configuration and writes an actual bit stream which consists of all the bits that configure the FPGA.
That was quick and I won't go deeper into this because, as I said, we were working on this for a while and had several talks on that.
One by Stefan, you find it on YouTube.
It's about who's in both of those FPGA tools.
There he will go deeper into how these tools work, how you can interact with them, how you can call them and how all of this stuff is working.
And a second talk of building open hardware with open software by me as well on YouTube.
And there I go into details on how we automated this and put the FPGA tool chain into a Yocto-based BSP so that we have reproducibility on the bit streams of the tools that are used,
our configuration and other providers of libraries that we are using so we can run a specific checkout of the Git repository of our BSP and be sure that we get the same build as the last time.
This is also now in our SCI so we have some CI running that takes the status of the bit stream and gives us a working bit stream again from the previous day.
So what's in the bit stream?
Usually if you come as a Linux developer you want to run a Linux on your bit stream.
That's where you take RISC-5, a soft core CPU.
Some of them are able to run Linux.
Most of them are able to synthesize for your FPGA.
So you have quite a few of these.
RISC-5 is one implemented in Spinal HDL, Boom implemented in Chisel, Rocket implemented in Chisel or CVA-6 implemented in System Very Low.
I said previously you take code for your FPGA in some hardware description language.
I said it's very low.
The four cores are implemented in three different languages so this is quite a few of different languages and each of these cores takes some periphery to make it actually work also implemented in the same language.
So once you decide for a core you're more or less decide for which hardware description language and tools you are using.
That's not something that's really flexible for us.
And this is a point where Litex comes in.
Litex is implemented in Megan which is another hardware description language which is based on Python.
And it supports Linux on Litex and gives various pre-configured FPGA bit streams that contain some RISC-5 core and support various FPGA boards that you can just run.
So here you see an example from the Litex Git web page, Git repository. It shows an Akron-based board with a multi-core Linux SOC.
You have some access to DDR. You have some access to SATA and UART.
So this is basically an SOC that's able to run Linux with enough periphery to actually make it work.
So there is an example for that available.
The question that arise was okay we have this example system but we want to fiddle around with the FPGA and want to run our own bit stream in there or at least be able to customize it to some point.
So our starting question for this was can we add our own custom cores that are written in Berrylook into the bit stream that falls out of Litex.
For that we decided to come up with a demo system.
So the requirements for that were we are using a lambda concept ECP IX-5 board. You saw it before with an ECP-5 FPGA by lettuce which is supported by users and the entire tool chain.
So support there is great.
We want to put WaxRisk-5 with Linux into the FPGA to run a Linux.
And because it's already there so the demo systems have it.
And we want to add to our system an LED ring because LEDs are flashy, LEDs attract people.
So it's something nice and we want to have interaction with the system.
That's why we put a hand wheel there as well so you can as a user do some inputs to the system and get some feedback from the system.
It didn't boot probably because it didn't have power.
So starting with WaxRisk-5 with Linux as said, Litex already supports this.
You can go to the Linux on Litex repository, look for this file and you'll see an implementation for WaxRisk-5 running on the lettuce ECP IX-5.
WaxRisk-5 is written in Spinal HDL. That's neither MyGun nor Veriloc.
In Litex or in preparation for using it in Litex, you generate the Veriloc code for this WaxRisk-5 core, wrap it in Python or MyGun.
And after that, Litex can just integrate the newly created core or generated core into the SOC.
It's an example target which supports Lite DRUM for memory access and Lite SD card for using an SD card.
The LED ring supports the WS2812 protocol which is a single wire protocol to control LEDs or more than one LED.
It's usually used in other fruit LED stripes but you can find various cheap clones on Alibaba and wherever.
There is already a core for controlling this protocol implemented in Litex so it's there coded in MyGun.
It works as an IOMAPT bus slave so from Linux you just write to the registers and LEDs flash and change the colors.
And on the bus you have four bytes per LED so that's the three colors plus whatever.
Input is done via a hand wheel which is from Amazon which is usually used for CNC stuff.
So it has 100 steps and you just can turn it around and it gives you a rotary encoder with two signals where you can find the direction of rotation.
We took some code of the internet for that.
It's implemented in very low.
There are various examples for that.
We wrapped it in Python so that we can use it in Litex and this one runs as a bus master and is able to control the LED core via this connection.
So it just sends right this color to this LED on the bus.
So if you put all of it together in the middle we have the FPGA on the right side.
We have the already existing system with the Vexrist 5 running Linux.
The Lite SD card which is connected to the SD card.
The Lite DRAM which is connected to our memory.
All of these are put together by a wishbone bus.
Details are not important.
It's a memory bus to communicate between cores.
On the left hand side, up here you see the encoder which is implemented in very low.
Which is connected to the hand wheel.
So this is one thing we added to the bit stream.
And we have the LED.py which is migran for the LED controller which is also added to the bit stream and controls the LED ring.
So how this is integrated into Litex?
We created a new Litex target.
Litex distinguishes between targets and platforms.
Platforms are the actual boards.
Targets are the SOC that you synthesize into your FPGA.
So we took the existing platform and added a new target for our own SOC.
Because it's Python we have inheritance.
We just inherited from the example base SOC with the Litex core and the Vexus 5 core and the other stuff.
We configured it, instantiated it, reconfigured the pins so that we can actually connect our own peripherals.
So the hand wheel and the LEDs to the connector of the board, added the LED core and added the rotary encoder.
In our case it's a decoder for interacting with the hand wheel and we are done.
All of this customization is about 200 lines of Python code.
So what we encountered and fixed during this process, after we added our custom cores,
suddenly Linux was booting but it was not able to access the SD card anymore.
We were suspecting various problems in the end like timing or that our bit stream generation failed or something.
In the end it turned out due to adding our new custom cores the memory map on the bus has changed
and the SD RAM controller has changed its base address and Linux didn't know about that
because we were using just the device tree that we took from the example.
So we changed our yachter build to use or to take the configuration for the Linux core,
generate a device tree from that and give it to Linux and that way Linux took the correct base address
and uses the correct base address and is able to use the SD card again.
So that's something that will come up later as well because if you reconfigure your base system
and device tree changes you have to make sure that your device tree matches your system that you're using.
And one other thing is there is some boot loader in the FPGA or in the bit stream for early bring up
which corresponds to the ROM code or the ROM boot loader that Marco mentioned previously.
So it's in the bit stream and it usually required so we compiled the boot loader
and then it started to recentize the bit stream run place and route again.
So this is quite fast but it's still in our case six to eight minutes.
That's not something you want to have if you're just compiling a really small binary.
So we changed our yachter build to synthesize and keep enough space in the area
and compile the ROM boot loader and just put it together afterwards.
This works a lot faster if you're fiddling around there.
Pain points.
Meaghan is not really maintained anymore.
There is a successor for it.
It's Amaranth.
Lightix is currently still using Meaghan migrating it to Amaranth is not really feasible.
There are ideas to change it to a new hard description language.
I'm not sure what's happening there but we saw especially for simulation
we saw that Meaghan generates invalid very low code or code you wouldn't want to simulate.
That's something.
Currently we have to live with it.
Then another observation was that the yachter environment wasn't as reproducible as we expected.
We're not sure what's the cause for that.
If we are missing it somewhere that there is some seed for compiling or for a place and route which we haven't fixed.
We saw that there is sometimes failing bitstream falling out of the yachter build that should be reproducible.
We wanted to use JTAG to debug the early boot of the WaxRisk 5 and look into it.
We are already flashing our bitstream via JTAG on the FPGA.
We have JTAG connected to the board but we are not able to connect it to the WaxRisk 5 JTAG connector
so that we could add the WaxRisk 5 core to our JTAG chain.
That's something we can work around.
We can just use different pins but we have to use a second JTAG for that.
That's something that's not that great and we haven't figured out yet.
Coming to the conclusion, adding and customizing Litex targets is really convenient.
It's something you have to figure out.
You have to work into it.
Once you're in there, I said it's 200 lines for configuring.
That is nice.
The step from Blinky to just get an LED flashing to an SOC is really large.
It's not really surprising because it's much more.
But also from things that you have to configure, things where you misconfigured something and it's just not working,
you have really many knobs that you can turn and your system will surprise you.
With all this tool chain, Litex, there are different modules in Litex.
All of them have to be in sync.
Sometimes it happens that if you just update one component, you will run into surprises.
It's really important to make sure that you have something around this entire tool chain
that keeps all your tools fixed on a specific version error
that you know which version you are using also for reporting bugs.
That's Yopto doing for us or is the plan to have.
The next steps are maybe we want to run a kernel CI on the Linux on Litex system
so that we can just take Linux kernel and run it against the system.
There comes the problem that kernel CI expects a device feed that's upstream
with kind of a conflict with the generation of the device feed that has to match your target.
Then we see that Linux takes ages to boot on the WexRisk5 about two minutes.
Not sure if that's because the core is just slow
or if there is something we are waiting for in user space that can be fixed.
The WexRisk5 actually supports multi-core systems.
We weren't able to boot this yet.
Maybe we want to look into using the same system on the concept with different WexRisk5 cores.
As I said before, there are four different cores in different languages.
All of them usually generate very low code
so it should be possible to integrate it into Litex.
Show me the source.
It's on GitHub.
This is a Yocto meta layer where you can find the code for the editing
or the entire SOC configuration, the code for the hand wheel
and a few other fixes that we did.
You can add this to a Yocto workspace and should be able to reproduce the bitstream that we built.
Thank you for your attention.
That's me. That's my colleague, Stefan.
You can send us an email if you have questions
or just ask me and find me somewhere.
Thank you.
We have time for literally one question.
This person here was the first one.
Thank you for your talk.
I had one question about the address changing in the device tree.
In microcontroller world, you can have a lot of microcontrollers
with the same addresses for the common devices like for STM32.
Do all the STM32 have the same base address for RAM?