AntBASIC Inline RISC-V Assembler
AntBASIC's second inline assembler. Where
[ … ]assembles ARM64 that runs on DeMon (the supervisor),{ … }assembles RISC-V for the machine's own soft core on the FPGA — the assembled code is placed in the RAM the FPGA can access and runs there, on the soft core. A retro BASIC that cross-assembles native code for the machine's own FPGA soft core.
Status: design. Nothing here is built. This page fixes what is different from the ARM64 assembler — the RV64 soft core (the EE), the narrow/wide encoding axis, and where the code runs. The shared model (the block, the accumulating cursor, labels-are-variables, two passes) lives on antbasic_asm and is not repeated here.
Back to AntBASIC · the ARM64 companion: antbasic_asm.
Shared with the ARM64 assembler
Everything structural is the same as antbasic_asm, just with { } instead of [ ]:
{ … }delimits assembly, multi-line or single-line ({ mul a0, a0, a0 }).- Assembly accumulates into the current execution area; the cursor (
P%) advances on its own; directives (P%,O%,ALIGN,OPT,SAVE) override. ASAVE "file"directive writes the area to.ee/.ezx/.bin— see antbasic_asm → Saving assembled code. - Labels and variables are one namespace — a
.labelis a BASIC variable set to the current address; a BASIC variable used as an operand supplies its value. The BASIC variable space is the symbol table. - Two passes resolve forward references automatically.
Mnemonics and register names follow RISC-V convention and fold case-insensitively: x0…x31 and their ABI names (zero, ra, sp, a0…a7, t0…t6, s0…s11).
One core, one encoding axis
{ } targets the machine's soft core — and there is now one core: the EE (ee_cpu), the RV64 Execution Engine, the same silicon inside the Ant64's FireStorm and the eZX Spectrum's eZX. Both machines run it; the eZX is a system built around the EE, not a different CPU. So a { } block assembles enhanced RV64 — RV64GC plus the custom extensions (Xcrisp, Xmath, Xstack, Xlate, Xctx, Xcond, Xwide, and Xez) — for either machine, identically.
The one axis that remains is encoding width, set by where the code lives in memory — not by the core:
| Encoding | Slot | Gains | Memory tiers |
|---|---|---|---|
| Narrow | standard 32-bit RISC-V | the baseline | HyperRAM, FPGA flash |
| Wide | 36-bit = 32-bit instruction + a 4-bit Xwide nibble | 64 GPRs + 64 FPRs, wider immediates (imm12→14, imm20→23), per-instruction predication (gates Xcond) |
DDR3 (72-bit, two slots/word), SRAM |
A 36-bit slot is a 32-bit instruction plus a 4-bit nibble, and all-zero-nibble wide code is bit-identical to narrow code — so narrow is the baseline and wide is a strict superset reached by placing code in wide memory. Note this is about the width of the encoding, never the width of the core: XLEN is always 64. "Narrow vs wide" is chosen by the target memory (DDR3 / SRAM wide, HyperRAM / FPGA flash narrow); the assembler picks it from the target memory, or a NARROW / WIDE directive.
(A per-machine note, not a core difference: the eZX takes its DDR3 as an optional SODIMM, so wide memory — and therefore wide-mode assembly — is only available on an eZX that has it fitted. The EE itself is identical either way.)
What is and isn't universal
Because there is one core, all { } source is one ISA — there is no cross-core portability problem, no "does this opcode exist on the other chip." The RV64GC base and every custom family, including Xez (now a settled EE extension, not eZX-only), assemble the same on both machines.
What still varies is encoding width:
- Wide-mode features — the extended 64-register file, wider immediates, and
Xcondpredication — need the area to be wide (36-bit memory). In narrow memory they are unavailable, and the assembler errors if you name, say,x40or use an out-of-range immediate in a narrow area.
Because it is all one BASIC program, a width-specific path needs no special mechanism — a normal IF, keyed off what the assembler reports for the active area:
10 IF basic_wide THEN
20 { add a0, x40, x41 } \ wide area — extended registers available
30 ELSE
40 { add a0, a4, a5 } \ narrow area — base 32 registers
50 ENDIF
The only additions over the shared assembler model are the width query and the NARROW / WIDE directives, to force a width when building for a memory region other than the current one.
Where the code runs
This is the real difference from the ARM64 assembler, which runs code on the same chip that assembled it. Here, AntBASIC assembles on DeMon (ARM64), but the RISC-V code runs on a different processor — the FPGA soft core:
- The block is assembled and its binary sent to the correct FPGA memory location in the
RUNpre-pass — a narrow area to HyperRAM, a wide area to DDR3 or SRAM — so it is staged on the soft core before the first line runs. Nothing runs on DeMon; the code runs on the FPGA side, in FPGA-accessible memory. - At run time,
CALL addr/USR addrstart the already-staged routine on the soft core and marshal values across the DeMon ↔ FireStorm link — BASIC integer variables in, a result back. Starting the core is an engine/FireStorm concern; from BASIC it looks like any otherCALL. - Because it is a cross-processor hop, a
{ }CALLcarries more latency than an[ ]one — it is for routines (a hot inner loop, a chipset poke), not per-instruction ping-pong.
The point is the reach: from a Ready. prompt you can hand-assemble a routine for the machine's own CPU — the EE that drives the Tempest/Blaze chipset — the same core the eZX Spectrum runs on — and call it. This is where the RISC-V assembler pairs with the future hardware-verb bridge: an assembled EE routine that touches the chipset directly.
Isolation
{ } code runs on the FPGA-side core, in its own memory, on a different chip from DeMon — so a wild store or a bad jump faults there, not in the AntOS process. Recovery is a core-level reset (restart the EE, or the personality), not a DeMon crash. This is a cleaner blast radius than the ARM64 assembler, whose faults land in the calling context on DeMon itself.
The v1 instruction subset
- Base integer ISA — RV64I: arithmetic, logic, shifts,
lui/auipc, loads/stores (including the RV64*w/ld/sd/lwuforms), branches,jal/jalr; theMextension (mul,div,rem). - Custom families —
Xcrisp(auto-increment, indexed, memory-fused, block ops),Xmath(fused MAC, saturating, transcendentals, BAM trig, vector / quaternion bundles),Xstack,Xlate,Xctx, andXez(the Z80-ergonomics family — now a settled EE extension, not eZX-only). See ee_cpu and the per-extension pages for the full sets. - Wide-mode — the extended register file, wider immediates, and
Xcondpredication, available when the area is assembled into wide memory.
Compressed (C) and single/double floating-point (F / D) come with the core — the EE is RV64GC. The assembler is a native-core component of the basic library, so widening the mnemonic set is engine work behind a stable { } surface.