mirror of
https://github.com/im-tomu/foboot.git
synced 2024-09-20 10:50:10 +00:00
92bf1ff546
Signed-off-by: Sean Cross <sean@xobs.io>
93 lines
4.0 KiB
Markdown
93 lines
4.0 KiB
Markdown
# Hacking on Foboot
|
|
|
|
Foboot lives inside an FPGA bitstream. This bitstream is fragile and can take a lot of time to build. Because of this, rapid changes to the code can be difficult to make.
|
|
|
|
There are two ways around this: Either store Foboot on a SPI flash and use XIP, or swap out the program ROM before loading the bitstream.
|
|
|
|
The bitstream generation program supports both approaches, however for development with an EVT board and `fomu-flash`, it is recommended to use the program-swap method.
|
|
|
|
## Replacing the boot ROM
|
|
|
|
When synthesizing a bitstream, a program ROM is loaded with the `$readmemh()` instruction. Synthesis is inherently random, and so the mapping of bits within the bitstream file is very different from the mapping as seen by the softcore.
|
|
|
|
There is, however, some pattern to the mapping, and with some heuristics it is possible to create a mapping and swap bits out. It is better to fill the ROM with random data, so that this process can ensure that it's replacing the correct bits -- if the ROM is entirely filled with zeroes, then it's impossible to know if the bit you're replacing is the correct one.
|
|
|
|
One program to do this is `icebram`, which is part of *Project Icestorm*. The `fomu-flash` utility also has an option to patch the rom as it uploads the bitstream. Currently, `fomu-flash` relies on a predefined "random" pattern, and requires the ROM to be 8192 bytes. This limitation can be adjusted if a usecase is found. The `fomu-flash` patching process is very fast.
|
|
|
|
### Building Foboot with a random ROM
|
|
|
|
To build Foboot with a random rom, add `--boot-source rand` to the build command:
|
|
|
|
```
|
|
$ python3 ./foboot-bitstream.py --boot-source rand --revision evt
|
|
```
|
|
|
|
This will synthesize a bitstream and store the result in `build/gateware/top.bin`. This is a fully-working bitstream, however it has no ROM, and so doesn't do anything useful. To actually do something with it, we need to build a ROM and patch it in.
|
|
|
|
### Building Foboot software
|
|
|
|
Normally, Foboot is built as part of the HW build process. You can build it separately by going to the `sw/` directory and typing `make`. This will generate several files. Of interest is `foboot.bin`.
|
|
|
|
Note that if you change major components from the HW part, you will need to regenerate the CSR header files. Copy them from `hw/build/software/include/generated/` into `sw/include/generated/`.
|
|
|
|
### Patching the ROM
|
|
|
|
To patch the ROM and load a new bitstream using `fomu-flash`, run:
|
|
|
|
```
|
|
$ fomu-flash -f hw/build/gateware/top.bin -l sw/foboot.bin`
|
|
```
|
|
|
|
This will reset the Fomu, patch the bitstream, and load the new bitstream into the FPGA.
|
|
|
|
### Patching the ROM with icebram
|
|
|
|
The `icebram` command also has the ability to patch the bitstream, however it requires files to be in a specific format.
|
|
|
|
To begin with, you need the following Python program to convert `foboot.bin` to a suitable `foboot.hex` file:
|
|
|
|
```python
|
|
#!/usr/bin/env python3
|
|
def swap32(d):
|
|
d = list(d)
|
|
while len(d) < 4:
|
|
d.append(0)
|
|
t = d[0]
|
|
d[0] = d[3]
|
|
d[3] = t
|
|
|
|
t = d[1]
|
|
d[1] = d[2]
|
|
d[2] = t
|
|
return bytes(d)
|
|
|
|
with open("foboot.bin", "rb") as inp:
|
|
with open("foboot.hex", "w", newline="\n") as outp:
|
|
while True:
|
|
d = inp.read(4)
|
|
if len(d) == 0:
|
|
break
|
|
print(swap32(d).hex(), file=outp)
|
|
```
|
|
|
|
Then, you need to generate a padded `random.hex` file from the foboot bitstream (the actual `--revision` doesn't matter, but must be something valid):
|
|
|
|
```
|
|
$ python3 ./foboot-bitstream.py --export-random-rom-file random.hex --revision evt
|
|
```
|
|
|
|
Then, you can use a script to patch the ROM:
|
|
|
|
```sh
|
|
$ icepack -u ~/top.bin | icebram random.hex foboot.hex | icepack - top-patched.bin
|
|
```
|
|
|
|
This will result in a file called `top-patched.bin` that can be written.
|
|
|
|
## Running Tests
|
|
|
|
You can run tests by using the `unittest` command:
|
|
|
|
`python3 lxbuildenv.py -r -m unittest -v valentyusb.usbcore.cpu.epfifo_test.TestPerEndpointFifoInterface`
|
|
|
|
Note that many tests are not working at this time, due to issues in how CSRs and events are handled in litex simulation. |