See also: Tomato works beautifully! · Falling back to 32b · ISA as a Wire

It was only right to start Tomato with the conventional 32 general-purpose registers. But there was an obvious waste: the discrete register file was already going to use parallel asynchronous SRAMs with thousands of available addresses.

From 32 GPR to 32,768 GPR

  1. 32 GPRregister:5
  2. 256 GPR+ bank:3
  3. 32,768 GPR+ superbank:7
  1. 32 GPRregister:5
  2. 256 GPR — add the existing bank:3
  3. 32,768 GPR — add a latched superbank:7

Final SRAM address:

7superbank
3bank
5register
7 + 3 + 5 = 15 bits → 32,768 × 32-bit locations

The 7-bit secondary bank is not carried inside every ordinary instruction. It is architectural state. A dedicated custom op changes it:

SETBANK2 0x03          →  superbank_latch ← 0x03
physical_address       =  { superbank_latch, bank, register }

One operation changes the entire visible 256-register window — no copying, no spill to RAM, no widening normal instructions. Ordinary encoding stays:

9opcode
5A
5B
5C/D
3bank
Ordinary instruction word — upper address bits live in the latch

while the upper seven address bits live in the latch until the next SETBANK2.

Why plain SRAM gives Tomato 3R1W

Tomato's ALU needs three independent register operands, so the file needs three reads and one write. Ordinary async SRAM does not provide that, so the file is mirrored three times.

Four ×8 SRAMs make one 32-bit mirror (4 × (32K × 8) = 32K × 32). Three identical mirrors give the three read ports:

Three mirrored SRAM banks — broadcast write, independent readswriteaddr + dataMirror A4 × AS6C62256 · 32K × 32READ AMirror B4 × AS6C62256 · 32K × 32READ BMirror C4 × AS6C62256 · 32K × 32READ C
Three mirrored SRAM banks — broadcast write, independent reads

Writes broadcast address and data to all three; reads present independent addresses. Effective 3R1W from 12 ordinary SRAM chips — no exotic multiported part.

The waste that started this

On an 8K-deep device, 32 architectural registers used 0.39% of the address depth. Tomato's existing 3-bit bank field grew that to 256 GPR — still only 3.125%. The SRAMs, PCB area, 32-bit buses, and three mirrors were already paid for. The unused depth was just sitting there.

SRAM upgrade: AS6C6264 → AS6C62256

AS6C6264AS6C62256-55PCN
Organization8K × 832K × 8
Capacity64 Kbit256 Kbit
Address bits1315
32-bit addresses per mirror8,19232,768
Access time55 ns55 ns
Supply2.7–5.5 V2.7–5.5 V
InterfaceAsync parallelAsync parallel
Chips needed for 3R1W1212
Approx. 12-chip cost*~USD 114~USD 122

*Pricing observed during this comparison; distributor and quantity pricing will move.

For roughly USD 7 more across the whole register file: 4× the depth, same chip count, same 55 ns class. So instead of leaving two address lines unused, expose the full device:

128 superbanks  ×  8 primary banks  ×  32 registers  =  32,768 GPR

And yes — that number is absurd.

How absurd?

ArchitectureInteger / register space
x86-6416
ARM AArch6431
RISC-V RV32I32
NVIDIA Blackwell255 / thread · 65,536 / SM
Tomato32,768

So: 2,048× x86-64, 1,024× RV32I, half a Blackwell SM — 32,768, period. The AS6C62256 presents fifteen address bits; once twelve of those chips are in the BOM for 3R1W, wiring them fully is the only move that isn't waste.

A flat 32K-register ISA would still be terrible: fifteen bits per operand × four → 60 bits just naming registers. Banking keeps the common 5-bit fields and amortizes the upper bits:

SETBANK2 0x57

ADD r4, r7, r12
MUL r2, r9, r20
…

All of those ops stay inside the window selected by 0x57 until another bank op changes it. Huge file; ordinary instruction width unchanged.

Final organization

Superbank latch prefixes every ordinary register accesssuperbank latch7 bits · SETBANK2instruction fieldsbank:3 · register:515-bit SRAM addr{ superbank, bank, reg }1 of32,768
Superbank latch prefixes every ordinary register access
read_A = { superbank, bank, reg_A }
read_B = { superbank, bank, reg_B }
read_C = { superbank, bank, reg_C }
write  = { superbank, bank, reg_D }   # broadcast to all mirrors

Next

  1. Add the 7-bit secondary-bank latch and custom SETBANK2
  2. Simulate and test in Hneemann's Digital
  3. Update KiCad register-file / control schematics and SRAM routing
  4. Update the hand-written Verilog / SystemVerilog FPGA core
  5. Test bank switching, isolation, mirrored writes, independent 3R reads, and preservation across superbanks
  6. Run architectural / program regressions
  7. Yosys and the rest of the open-source FPGA flow for hardware bring-up

This started as trying not to waste an SRAM. Now Tomato has 32,768 GPR — because the chips come with 15 address bits, and using any less is a waste.