uLisp on the RP2350 Hazard3/iCEBreaker (FPGA)


#1

Hello,

I hope you are doing well.

I was reading about the Pi Pico 2, specifically the Hazard3 RISC-V core developed by Luke Wren, which essentially provided all the FPGA code for running it on at least two different hardware platforms.

My question is, let’s say you are able to magically replicate it on an iCEBreaker and run the RP2350 RISC-V core there, would it be possible to run uLisp on it and interact with a REPL directly on the FPGA? If so, what would be the compilation process? I dont see any mention to arduino there.

Checking the PDF documentation from the official repository, I found this:

Example C macro (using GCC statement expressions):
// nbits must be a constant expression
#define __h3_bextm(nbits, rs1, rs2) ({
uint32_t __h3_bextm_rd;
asm (".insn r 0x0b, 0, %3, %0, %1, %2"
: “=r” (__h3_bextm_rd)
42
: “r” (rs1), “r” (rs2), “i” ((((nbits) - 1) & 0x7) << 1)
);
__h3_bextm_rd;
})

Example assembly macro:
// rd = (rs1 >> rs2[4:0]) & ~(-1 << nbits)
.macro h3.bextm rd rs1 rs2 nbits
.if (\nbits < 1) || (\nbits > 8)
.err
.endif
#if NO_HAZARD3_CUSTOM
srl \rd, \rs1, \rs2
andi \rd, \rd, ((1 << \nbits) - 1)
#else
.insn r 0x0b, 0x0, (((\nbits - 1) & 0x7 ) << 1), \rd, \rs1, \rs2
#endif
.endm

Best Regards!


#2

You would need a UART either attached to the Hazard core (it might have one built-in, haven;t looked closely) or attached as an IO device somehow as part of the FPGA definition, and then run out the UART connections to external pins on the FPGA (so that you can connect to them, and thereby interact with SW running on the Hazard core).

Of course, that also presumes the Hazard core has memory (ROM & RAM) for booting and execution, either as FPGA-instantiated memory interfaces, or using “PROM” & RAM instantiated directly in the FPGA. WIthout ROM to handle booting and where ULISP can either execute from or load from, and RAM for ULISP to live in and use for data storage, having the Hazard core by itself isn’t worth much, even with a UART attached.

You need to think of what’s needed in the FPGA as more of a SoC than as just a CPU core. Go look on opencores.org and you should be able to find the IP blocks you need to connect to the Hazard.

Not trying to discourage you, given a big enough FPGA you absolutely can instantiate everything needed and I’ve done so many times. It’s just that the CPU core IP is only the beginning of what you need, and you also need to think about all the rest of the connectivity CPUs need to do anything useful. That may all be included already, and if so, you’re set – but if not, you’ll need to solve that too.

Hope that helps!

-John W


#3

Hello John,

Thank you so much for your detailed explanations. It looks like a challenging one-semester project, assuming quite good know-how of digital logic and RISC-V!

Just in case, I’ve also pinged the Arduino-Pico core developer about PlatformIO compiling tools for the RP2350. However, I’m afraid that’s the last step, as you mentioned.

Best Regards


#4

I should also mention that having the same Hazard RISCV core in an IceBreaker FPGA isn’t quite the same thing as having an RP2350 present: The PlatformIO tools for RP2350 make numerous assumptions about where and how much RAM & ROM memory is present, all based on the RP2350 architecture specs. Unless you’re replicating an entire RP2350 (as opposed to the Hazard RISCV core from an RP2350), most of those assumptions will be incorrect for whatever hardware architecture you emulate using the FPGA.

At the very least, you’ll also need to come up with your own BSP/platform definition headers that indicate to the PlatformIO toolset where the RAM and ROM manifest in the physical address space of the processor core, along with where any memory-mapped periphs are attached, to whatever level of “completeness” you need in order to achieve whatever you set as goals.

All in all, this sounds extremely aggressive for a single-semester project, particularly once you add in the functionality testing needed to ensure everything works as expected. If I were you, I’d focus more on just getting the core instantiated in the FPGA, and then using whatever provisions the FPGA design package offers for directly testing the hardware to functionally validate the instantiated core. That in and of itself is right at the edge of what I’d recommend for a single-semester, leaving time for setbacks and rethinks, as well as writing up the final paper.

BTW, as you have the design of the Hazard3 core, have you confirmed the IceBreaker’s FPGA has enough logical elements to instantiate it, and still have enough left over to do interface hardware? Interfacing can easily consume another 30-50% of the core’s element requirements, esp. if you need to instantiate everything (where you cannot take advantage of existing RAM blocks, existing UART connections and so forth).

Luckily, the approach I recommended above should have significantly lower requirements in terms of FPGA logical elements (slices/LUTs/whatever) compared to a full SoC-like instantiation. You’ll still need some Interfacing, but it should be greatly reduced if you’re directly testing the emulated hw as opposed to trying to boot and execute code on the core.

Anyway, just stuff to think about, hope this helps!

-John W


#5

Hello John,

Thank you very much for your detailed and helpful explanation. The Arduino-Pico developer also provided some clarification that aligns with what you explained. The Hazard RISC-V core is just the first step. Even if the also supported ULX3S should be sufficient for the interfaces. You can easily package that entire end-to-end process (from FPGA to running code) into a two-year EU master’s program!

Focusing on simply instantiating the core in the FPGA and directly testing the hardware to functionally validate the instantiated core sounds entirely reasonable.

As a side comment, it looks like you are now able to build your own CPU via the SKY130 Open-Source PDK: https://tinytapeout.com/

Best Regards