From db846103a79f82e126a3fadd8184f89b9f712ecb Mon Sep 17 00:00:00 2001 From: Jade Lovelace Date: Thu, 20 Apr 2023 23:05:36 -0700 Subject: [PATCH] quartus miserypost --- content/posts/quartus-elf2hex-and-misery.md | 197 +++++++++++++++++++- 1 file changed, 189 insertions(+), 8 deletions(-) diff --git a/content/posts/quartus-elf2hex-and-misery.md b/content/posts/quartus-elf2hex-and-misery.md index 860dbb8..ee2662d 100644 --- a/content/posts/quartus-elf2hex-and-misery.md +++ b/content/posts/quartus-elf2hex-and-misery.md @@ -1,9 +1,9 @@ +++ -date = "2023-03-14" -draft = true +date = "2023-04-20" +draft = false path = "/blog/quartus-elf2hex-and-misery" tags = ["quartus", "fpga"] -title = "Quartus, elf2hex, bugs, and misery" +title = "Quartus, elf2hex, Nios II, bugs, and misery" +++ I have been working on a school project, which uses Intel FPGAs and the @@ -14,11 +14,18 @@ finally made a RISC-V core that integrates similarly, but we don't have that. There are also obviously third-party soft cores, but in the interest of not doing a massive hardware project, we chose not to do that, and just used the -Nios with C (it's GCC 10, it could be so much worse). +Nios with C/C++ (it's GCC 10, it could be so much worse). + + The implementation of a soft core on an FPGA involves creating memory blocks in the FPGA for the memory of the device, which the processor then executes out -of. You thus need to get your program into there. +of. You thus need to get your program into there, and that means dealing with +Quartus pretty damn hard. ## Memory initialization @@ -27,7 +34,14 @@ of getting a program in, however, it's kind of a pain: for Nios, you have to use the `mem_init_generate` Makefile target (which is ... variable amounts of documented [in the "Embedded Design Handbook"][edh] buried pretty deeply), then add the resulting `.qip` file to your Quartus project. Once you've added that, -recompile the project hopefully for the last time. +you might think you would now recompile the project hopefully for the last time. + +But no! That's not all! You actually have to turn on "Use smart compilation" in +Assignments>Settings>Compilation Settings, which will make Quartus consider the +actual changes when deciding which compilation stages to run. For some reason +this is off by default and it will just rerun everything from the beginning if +any input is changed. This setting corresponds to `set_global_assignment -name +SMART_RECOMPILE ON` in the `.qsf` file. When you need to update the program but not the Quartus design, assuming that your timestamps aren't all jacked up to make Quartus think you need a full @@ -36,6 +50,10 @@ File or `quartus_cdb YOUR_TOPLEVEL_ENTITY --update-mif`][ram-init-hack] then rerun the "Assembler" step to reuse the FPGA bits and write a new `.sof` with the new software. +You can also assemble from the command line with `quartus_asm +--read_settings_files=on --write_settings_files=off YOUR_TOPLEVEL_ENTITY -c +YOUR_TOPLEVEL_ENTITY`. + [ram-init-hack]: https://tomverbeure.github.io/2021/04/25/Intel-FPGA-RAM-Bitstream-Patching.html [edh]: https://www.intel.com/content/www/us/en/docs/programmable/683689/current/introduction-28202.html @@ -63,7 +81,170 @@ future. [intel-jtag]: https://tomverbeure.github.io/2021/10/30/Intel-JTAG-Primitive.html [vexriscv-jtag]: https://github.com/SpinalHDL/VexRiscv/pull/276 -## Problems, 9 year old bugs in Quartus, and misery +## Nios II JTAG tools as a Kaizo game -https://community.intel.com/t5/Intel-Quartus-Prime-Software/warning-with-on-chip-memory-data-items-width/m-p/57088 +It's true that you can upload a program with JTAG to a Nios II, but there is +precisely one way that actually works to do so, and it sucks. + +You have to do a fun dance to successfully upload a program: + +1. `make` +2. `nios2-download --stop main.elf` +3. `nios2-gdb-server --stop --tcpport 9002` +4. `gdb -ex 'target extended-remote :9002' ./main.elf` +5. Type `cont` in gdb. + +Aaaand why would that be? Surely you can just run `nios2-download --go +main.elf`? Nope, that seems to leave memory blank and not actually start +the thing sometimes. *Surely* you could do `nios2-download --stop main.elf` and +then `nios2-download --go`? Nope that also didn't work and again seemed to +corrupt memory. The only way to get it to start is with the debugger. + + + +Ah, but that's not all! Unfortunately, in my version of Quartus, the developers +of nios2-gdb-server (closed source) done did a mistake. Quoth `man 7 ip`: + +> A TCP local socket address that has been bound is unavailable for some +> time after closing, unless the SO_REUSEADDR flag has been set. Care +> should be taken when using this flag as it makes TCP less reliable. + +Well, that sure is an interesting quotation, because `nios2-gdb-server` states +"address in use" if you have just stopped it last less than 30 seconds ago on +the same port. Looks like someone forgot to `setsockopt(sock, SO_REUSEADDR)`. +So you have to play port musical-chairs when doing quick iterations. Fun! + +## Nios II Eclipse + +No. + +(I have tried *surprisingly* hard, especially given that it is Vendor Eclipse, +but it does not work on my machine (segfault; hard to get the right Eclipse +release; templates don't show up; etc etc), and it is Vendor Eclipse. More +vendor software in my critical path is not my idea of fun, I have too much +already) + +## A surprising non-bug appears! + +``` +Warning (113015): Width of data items in "soc_system_nios_memory.hex" is greater than the memory width. Wrapping data items to subsequent addresses. Found 4096 warnings, reporting 10 +``` + +This message is what you get when you attempt to load a hex file generated by +Intel's own Nios toolchain using the `make mem_init_generate` target. + +Now, why would that be? The [Intel HEX file][hex] that Intel's toolchain +generates looks like the following (I added some spaces to distinguish the +fields): + +[hex]: https://en.wikipedia.org/wiki/Intel_HEX + +```hex +:02 0000 02 0000 FC +:20 0000 00 00400074084062140800683A0000000000000000000000000000000000000000 C4 +:20 0008 00 DEFFED04DFC00015D8400215D8800315D8C00415D9000515D9400615D9800715 6A +:20 0010 00 D9C00815000B307ADA000915DA400A15DA800B15DAC00C15DB000D15DB400E15 C4 +:20 0018 00 DB800F15DBC01015D9401115EBFFFF04DBC012150009313A2880004C10000326 FA +:20 0020 00 2000022600100FC000000706DF401215E8BFFF17E93FFF04001016401000021E C8 +``` + +What *is* this thing? Well, as may be visible by looking briefly at it, it +contains more than 8 bytes of hex per line, so something is fishy, since HEX +files are typically byte addressed, yet addresses here are only going up by 8! +It turns out this is a *word addressed* Intel HEX file with 32 bit words, and +they stuffed eight of em on a line. Wat. + +More excitingly, `srec_cat` and similar tools don't understand that this strange +thing exists: it seems a parallel invention of the same cursed idea [has +occurred at TI and baffled some forum posters there as well][ti-lol]. + +Alright, so then why is it complaining about this? I guess, it is because it is +overwriting words 1 through 7 with line 2, but that's actually not a problem +since each location only receives one value in practice. + +All of this said, this warning is actually fine. I had thought that this was +broken, but I must have stepped on a different rake and thought it was this: +I've generated programming files with both versions and confirmed that both +loaded correct code. + +Someone [reported this on the Intel forum 9 years ago][intel-lol]. I found that +you can create hex files that don't irritate Quartus by doing something like +`make elf2hex_extra_args=--record=4 mem_init/soc_system_nios_memory.hex`, which +generates 4-byte records, but much more of them. + +[ti-lol]: https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/268539/f28069-hex2000-memwidth-and-hex-parser +[intel-lol]: https://community.intel.com/t5/Intel-Quartus-Prime-Software/warning-with-on-chip-memory-data-items-width/m-p/57088 + +## Sticking it on a device + +Of course, you can use the Quartus programmer to load the file via JTAG but +this isn't suitable for devices that need to be put out and then just work +thereafter: it's tethered to a computer. + +I intend to write more about this later, since there is much more to say, but +briefly, software on the hard processor on the FPGA such as U-Boot and also +Linux (with the right device tree) can program the FPGA fabric. This is quite +useful since it lets you deploy the gateware together with the software. + +Alternatively, this can be sequenced the other way: the FPGA fabric loads a raw +bitstream image off of SPI flash, then the hard processor, if used, boots off +the FPGA fabric. This is a much stranger mode, and is outside the scope of this +post. + +To do this, you need to generate a `.rbf` (raw binary file) file from the `.sof` +programming file. Quartus has a (somewhat confusing) "Convert programming files" button in the File +menu, but it can be done at the command line with `quartus_cpf -c +output_files/youroutputfile.sof youroutputfile.rbf`. + +Then in U-Boot, for example, you would use something like `ext4load mmc 0:2 +${loadaddr} /boot/yourfile.rbf` then `fpga load 0 ${loadaddr} ${filesize}`. + +It is actually possible to generate a `.rbf` file with Quartus automatically, +but it doesn't actually work on my machine. Whatever it was generating did not +work, whereas the one from `quartus_cpf` did. On different versions of Quartus +than mine (different editions??), there is a setting in the +Assignments>Settings>Assembler which enables this, but I had to uhhhh run +`strings` on random Intel binaries until I found the setting: +`set_global_assignment -name GENERATE_RBF_FILE ON`. If your Quartus doesn't +have the GUI toggle it may well be for a reason. + +## Conclusion + +Most of the difficulty in the hardware parts of this project were all of the +ways to step on a rake due to a number of Intel bugs, which seem to reproduce +in unclear conditions. + +This combines really infuriatingly with fragile recompilation +checking in Quartus and 6 minute compiles. Worse, 8 minutes if you also have to +regenerate Platform Designer files! Don't add your `.qsys` file to your Quartus +project if you don't like eating this every compile. That, and the Makefile for +the Nios II board support package will check the modification time of the +`.sopcinfo` file against something else and make you regenerate the BSP, +possibly for no reason, as bonus broken recompilation checking. + +I don't think that this is a case of Intel being uniquely bad (although having +their JTAG stuff being closed source makes it so so much worse since I can't +fix it myself) as much as this is how embedded tools tend to be like.