Memory Map
The system has an internal 32-bit address space. This space is carved up as follows:
| 31-24 | 23-20 | 19-00 |
|---|---|---|
| Segment | Function | Data |
The reason is, this system being a baremetal retro machine is likely to never have a crazy amount of RAM where we would want 2GB or more of contiguous space. So the address space can be carved up to make things a little more logical and easier for the developer. This includes remapping things like physical memory cards on the Turbo Bus to a specific segment. This makes future expansion (hopefully) more elegant.
Layout
The list below is a bit of a hodgepodge of full allocation and current hardware allocation, but gives hopefully an idea of how this is intended to work.
Note that Turbo Bus is a 24-bit bus, so the addresses include the Device and Data and maps nicely to physically devices.
Segments:
Main Memory (Segment 00):
Base Memory:
Low RAM (SRAM), 112K: 00 0 00000..00 0 1BFFF
(Reserved) 00 0 1C000..00 0 7FFFF
Kernel ROM Mirror (512k): 00 0 80000..00 0 FFFFF
Extended (Bus) RAM (Device 0 Mirror) 00 1 00000..00 1 FFFFF
System RAM (Segment 01):
Kernel Vars, Traps & Vectors (DPRAM), 2K:
Kernel Vars: (DPRAM), 1K: 01 0 00000..01 0 003FF
System Traps & Vectors (DPRAM), 1K: 01 0 00400..01 0 007FF
User Vars (DPRAM), 1K 01 2 00000..00 2 003FF
Stack RAM (SRAM), 16K: 01 F FC000..01 F FFFFF
Banked RAM (Segment 02):
Bank RAM 0 (Device 2 Mirror), 256k 02 0 00000..02 0 3FFFF
Bank RAM 1..14 (Reserved) 02 1 00000..02 E FFFFF
Page Registers: 02 F 00000..02 F FFFFF
Bank 0 Page Register (Device 2 Mirror): 02 F 00000..02 F 00001
Bank 0 Num Pages (Device 2 Mirror): 02 F 00002..02 F 00003
Bank 0 Page Size (Device 2 Mirror): 02 F 00005..02 F 00008
ROM (Segment 03):
Kernel ROM (Device 1 Mirror): 03 0 00000..03 0 FFFFF
(Reserved, Option ROMs)
Game Cart ROM (Device 15 Mirror): 03 F 00000..03 F FFFFF
8-bit Turbo Bus (Segment F0):
Device 0 (Bus RAM, Up to 1MB w/ A19): F0 0 00000..F0 0 FFFFF
Device 1 (Kernel ROM, Up to 1MB, w/ A19): F0 1 00000..F0 1 FFFFF
Device 2 (MCU): F0 2 00000..F0 2 FFFFF
Banked Smart RAM (256k): F0 2 00000..F0 2 3FFFF
System Registers (128k): F0 2 40000..F0 2 5FFFF
Smart RAM Registers (128k) F0 2 60000..F0 2 7FFFF
Device 3 (Video/VERA/User): F0 3 00000..F0 3 FFFFF
Device 4 (User): F0 4 00000..F0 4 FFFFF
...
Device 7 (Cartridge ROM): F0 7 00000..F0 7 FFFFF
Device 8-15 (Not Exposed On Bus): F0 8 00000..F0 F FFFFF
Internal FPGA System Bus (Segment FE):
FemtoRV USB UART Data, 4B: FE 0 00000..FE 0 00003
FemtoRV USB UART Control, 4B: FE 0 00004..FE 0 00007
Global System Registers (Segment FF):
System Setup (DFFs): FF 0 00000..FF 0 003FF
CPU Clock Divisor: FF 0 00000..FF 0 00000
Bus Clock Divisor: FF 0 00001..FF 0 00001
Turbo Bus Wait States, 8 bytes: FF 0 00010..FF 0 00017
Turbo Bus Read-Cache Enable, 1 byte: FF 0 TBD
Turbo Bus Read-Cache Invalidate, 1 byte: FF 0 TBD
MCU System Registers (Device 2 Mirror), 128K: FF 1 00000..FF 1 1FFFF
In the current hardware proposal, SRAM, DPRAM and LUTs run at CPU speed which means the remapped devices, of course, run at the speed of the Turbo Bus.
System Setup Registers
These are DFFs (flip-flops) attached to LUTs and are desired over EBRs since they can be async. This is important for things like the bus wait-states. The bus controller needs to access these without artificial delay.
Note also that the setup registers are not meant to be used dynamically (like for dynamic frequency clocking on a modern system). The CPU divisor may cause a stall on a change though is otherwise generally safe.
The bus divisor and wait states should only be changed while the bus is not being used. Meaning code that changes these values should be running in Low RAM.
The cache invalidation and enable registers can be triggered at any time from anywhere since it just controls the cache flush. This will still obviously cause a delay in immediate cache misses of course.
The cache enable register may either be a non-zero value or might be a device bitmask. The latter allows for per device caching so the user has control over how to use the cache.
Wait States
At present, wait states are a single value per device and indicate how many cycles to wait whenever a wait is required for a bus transaction (e.g. settling time, SRAM recovery/hold, etc.). Future improvements could be wait states for specific steps. SRAM, for instance, has different wait states for different parts of a read or write transaction.
Wait states are based on the bus clock (not the CPU clock).
It is wise not to change wait states while the bus is active or at least do not change the wait-state for the active device on the bus.
DPRAM/EBR
EBR blocks are optionally dual port memory blocks which total up to 15kb. Proposed allocation is:
- User Vars (1K, 2 EBRs): Roughly equivalent to the "zero page" on a 6502
- Kernel Vars (1K, 2 EBRs): Roughly equivalent to the "zero page" on a 6502, dedicated to the kernel
- System Traps / Vectors (1K, 2 EBRs): IRQ jump table and default IRQ handler code
- Bus Cache (22 EBRs): 4-way 8kb instruction cache for bus (specifically RAM and ROM)
- 16 Entry Victim Cache (880 Flip-Flops) helps handle cache contention (assumes available FFs/LUTs)
Total EBR Usage: 28 / 30 (1k remaining)
Device Remapping
To make it easier for the user/developer and allow for at least attempting future expansion and upgrades, some things are remapped. Notably in the minimal config, the MCU has a window of banked Smart RAM. If a user wants to add a bigger RAM card, they could place it at Bank RAM 0. This will come from the system config which will be stored in MCU flash or on the MCU SD Card.
How this works with the current FPGA (Upduino) in terms of LUT usage remains TBD.
Game Cartridge
Game Cartridge ROM is available in the ROM segment. At present it is remapped from special Device 7 on the
TurboBus. This is so future cartridges on other busses could be used though in practice the Game Cart ROM
area is special. If a cartridge is available here, it will cause the system to boot direct to the cartridge
(though this can be disabled via boot settings in the MCU). This can be automagic given cartridges will need
to provide a "CART" header as the first 4 bytes of the memory area. If the system finds this, and is set to
auto-boot to carts, it will boot into the cart by jumping to the remapped address (0x03F00000).