Compilers and optimizers are great tools for some use cases, but not all.
Just to name a few limitations:
- Many rely heavily on the CPython runtime, meaning garbage collection, interoperability, and object semantics are still governed by CPython’s model.
- They’re rarely designed with embedded or real-time use cases in mind: large binaries, non-deterministic execution (due to the underlying architecture or GC behavior), and limited control over timing.
If these solutions were truly turnkey and broadly capable, CPython wouldn't still dominate—and there’d be no reason for MicroPython to exist either.
PyXL deliberately avoids tying itself to Python’s high-level syntax or rapid surface changes.
The system compiles Python source to CPython ByteCode, and then from ByteCode to a hardware-friendly instruction set. Since it builds on ByteCode—not raw syntax—it’s largely insulated from most language-level changes. The ByteCode spec evolves slowly, and updates typically mean handling a few new opcodes in the compiler, not reworking the hardware.
Long-term, the hardware ISA is designed to remain fixed, with most future updates handled entirely in the toolchain. That separation ensures PyXL can evolve with Python without needing silicon changes.
Fair point if you're looking at it through a strict compiler-theory lens, but just to clarify—when I say "runs Python directly," I mean there is no virtual machine or interpreter loop involved. The processor executes logic derived from Python ByteCode instructions.
What gets executed is a direct mapping of Python semantics to hardware. In that sense, this is more “direct” than most systems running Python.
This phrasing is about conveying the architectural distinction: Python logic executed natively in hardware, not interpreted in software.
It's still early days and there’s a lot more work ahead, but I'm very excited about the possibilities.
I definitely see areas like embedded ML and TinyML as a natural fit — Python execution on low-power devices opens up a lot of doors that weren't practical before.
You're right that it can definitely be faster — there's real room for optimization.
When I have time, I may write a blog post that will explain where the cycles go, why it's different from raw assembler toggling, and how it could be improved.
Also, just to keep things in perspective — don't forget to compare apples to apples:
On a Pyboard running MicroPython, a simple GPIO roundtrip takes about 14 microseconds.
PyXL is already achieving 480 nanoseconds, so it’s a very different baseline.
No, I'm not paying for ModelSim.
I've been using free tools like Icarus Verilog — it was good enough for my needs so far.
If I need more performance later, I might migrate to Verilator.
I could also use Vivado’s built-in XSim, but coming from a software background, I generally prefer more Unix-style tools rather than heavier hardware IDEs.
Good question — I’m not 100% sure.
I'm not an expert on Ruby or JS internals, and I haven’t studied their execution models deeply.
But in theory, if the language is stack-based (or can be mapped cleanly onto a stack machine), and if the ISA is broad enough to cover their needs, it could be possible.
Right now, PyXL’s ISA is tuned around Python’s patterns — but generalizing it for other languages would definitely be an interesting challenge.
Python’s execution model is already very stack-oriented — CPython bytecode operates by pushing and popping values almost constantly.
Building PyXL as a stack machine made it much more natural to map Python semantics directly onto hardware, without forcing an unnatural register-based structure on it.
It also avoids a lot of register allocation overhead (renaming and such).
You're right that dynamic typing makes high-frequency execution tricky, and modern OoO cores are incredibly good at hiding latencies.
But PyXL isn't trying to replace general-purpose CPUs — it's designed for efficient, predictable execution in embedded and real-time systems, where simplicity and determinism matter more than absolute throughput.
Most embedded cores (like ARM Cortex-M and simple RISC-V) are in-order too — and deliver huge value by focusing on predictability and power efficiency.
That said, there’s room for smart optimizations even in a simple core — like limited lookahead on types, hazard detection, and other techniques to smooth execution paths.
I think embedded and real-time represent the purest core of the architecture — and once that's solid, there's a lot of room to iterate upward for higher-end acceleration later.
Good question.
In theory, you can compile anything Turing-complete to anything else — ARM and Python are both Turing-complete.
But practically, Python's model (dynamic typing, deep use of the stack) doesn't map cleanly onto ARM's register-based, statically-typed instruction set.
PySM is designed to match Python’s structure much more naturally — it keeps the system efficient, simpler to pipeline, and avoids needing lots of extra translation layers.
I'm a software engineer by background, mostly in high-frequency trading (HFT), HPC, systems programming, and networking — so a lot of focus on efficiency and low-level behavior.
I had played a bit with FPGAs before, but nothing close to this scale — most of the hardware and Python internals work I had to figure out along the way.
Right now, the plan is to present it at PyCon first (next month) and then publish more about the internals afterward.
Long-term, I'm keeping an open mind, not sure yet.
My background is in high-frequency trading (HFT), high-performance computing (HPC), systems programming, and networking.
I didn't come from HW background — or at least, I wasn't when I started — but coming from the software side gave me a different perspective on how dynamic languages could be made much more efficient at the hardware level.
Difficult - adapting the Python execution model to my needs in a way that keeps it self-coherent if it makes sense. This is still fluid and not finalized...
Easy - Not sure if categorize as easy, but more surprising: The current implementation is rather simple and elegant (at least I think so :-) ), so still no special advanced CPU design stuff (branch prediction, super-scalar, etc).
So even now, I'm getting a huge improvement over CPython or MicroPython VMs in the known python bottlenecks (branchings, function calls, etc)
Not yet — I'm currently testing on a Zynq-7000 platform (embedded-class FPGA), mainly because it has an ARM CPU tightly integrated (and it's rather cheap).
I use the ARM side to handle IO and orchestration, which let me focus the FPGA fabric purely on the Python execution core, without having to build all the peripherals from scratch at this stage.
To run PyXL on a server-class FPGA (like Azure instances), some adaptations would be needed — the system would need to repurpose the host CPU to act as the orchestrator, handling memory, IO, etc.
The question is: what's the actual use case of running on a server? Besides testing max frequency -- for which I could just run Vivado on a different target (would need license for it though)
For now, I'm focusing on validating the core architecture, not just chasing raw clock speeds.
You're absolutely right that CPython bytecode changes over time and isn’t perfectly documented — I’ve also had to read the CPython source directly at times because of unclear docs.
That said, I intentionally chose to target bytecode instead of AST at this stage.
Adhering to the AST would actually make me more vulnerable to changes in the Python language itself (new syntax, new constructs), whereas bytecode changes are usually contained to VM-level behavior.
It also made it much easier early on, because the PyXL compiler behaves more like a simple transpiler — taking known bytecode and mapping it directly to PySM instructions — which made validation and iteration faster.
Either way, some adaptation will always be needed when Python evolves — but my goal is to eventually get to a point where only the compiler (the software part of PyXL) needs updates, while keeping the hardware stable.
Right now, PyXL runs fully in-order with no speculative execution.
This is intentional for a couple of reasons:
First, determinism is really important for real-time and embedded systems — avoiding speculative behavior makes timing predictable and eliminates a whole class of side-channel vulnerabilities.
Second, PyXL is still at an early stage — the focus right now is on building a clean, efficient architecture that makes sense structurally, without adding complex optimizations like speculation just for the sake of performance.
In the future, if there's a clear real-world need, limited forms of prediction could be considered — but always very carefully to avoid breaking predictability or simplicity.
Just to name a few limitations:
- Many rely heavily on the CPython runtime, meaning garbage collection, interoperability, and object semantics are still governed by CPython’s model.
- They’re rarely designed with embedded or real-time use cases in mind: large binaries, non-deterministic execution (due to the underlying architecture or GC behavior), and limited control over timing.
If these solutions were truly turnkey and broadly capable, CPython wouldn't still dominate—and there’d be no reason for MicroPython to exist either.