code wiki / _hdl_build / rv64im_min_nvme.nx
rv64im_min_nvme.nx
buildroot/runtime/_hdl_build/rv64im_min_nvme.nx
about
rv64im_min_nvme.nx -- a SOVEREIGN NVMe-class PCI/MMIO controller device model (X-DRV-W1
stage B, the 2nd device class). This is the TWIN of rv64im_min_virtio.nx but for a
genuinely DIFFERENT bring-up protocol: where virtio is a straight-line OR-write status
ladder, NVMe is a write-then-POLL enable handshake (CC.EN -> poll CSTS.RDY) plus an
admin Submission/Completion queue pair bound by 64-bit BASE-ADDRESS registers (ASQ/ACQ,
NOT a single PFN<<12), a 64-byte SQE the driver lays in guest RAM, ring advance by
TAIL/HEAD DOORBELL writes, and a 16-byte CQE with a PHASE-TAG bit the driver polls.
The device models ONE controller window [0x10003000, 0x10003000+0x2000). The KEY
behaviour: on a SQ-Tail-doorbell write (off_sq0tdbl) the device runs the doorbell DMA --
it fetches the 64-byte SQE from ASQ_base (STRUCT_WALK over guest RAM: reads opcode + CID),
executes a trivial admin command, POSTS a 16-byte CQE into ACQ_base (writes SQHD/CID/status
with the phase bit set), and latches a NvmeCqPeek RO word = (CID<<16)|status|phase. CSTS.RDY
is a latched flop set when CC.EN was written 1 (cleared on CC.EN=0 reset), so the driver's
poll-until-RDY loop terminates. The virtio + net device models are untouched (additive,
separate instance) so PROOF-1's SECTGATE stays GREEN.
NVMe/PCI here is a last-mile interop PROBE + a measuring stick to EXCEED -- the emitted
driver and the shapes are Nishi-native (the device identity lives ENTIRELY in the spec; the
shape library that emits the driver knows zero NVMe).
Status: SEED. 2026-06-13. Enable handshake + admin SQ/CQ doorbell DMA + phase-tagged CQE.
license_tier: ORIGINAL
dependencies 2 imports · 5 importers
imports: nx_syscalls.nxnishi_hdl_primitives.nx
imported by: _gpu_run.nx_nvme_diag.nxnx_bootcap.nxnx_nishios_window.nxrv64im_min_sim.nx
structs
| 108 | struct NxNvmeCtrl |
consts
| 30 | const NX_NVME_BASE: i64 = 0x10003000 |
| 31 | const NX_NVME_END: i64 = 0x10005000 |
| 45 | const NX_NVME_OFF_CAP: i64 = 0x00 |
| 46 | const NX_NVME_OFF_VS: i64 = 0x08 |
| 47 | const NX_NVME_OFF_CC: i64 = 0x14 |
| 48 | const NX_NVME_OFF_CSTS: i64 = 0x1C |
| 49 | const NX_NVME_OFF_AQA: i64 = 0x24 |
| 50 | const NX_NVME_OFF_ASQ_LO: i64 = 0x28 |
| 51 | const NX_NVME_OFF_ASQ_HI: i64 = 0x2C |
| 52 | const NX_NVME_OFF_ACQ_LO: i64 = 0x30 |
| 53 | const NX_NVME_OFF_ACQ_HI: i64 = 0x34 |
| 54 | const NX_NVME_OFF_SQ0TDBL: i64 = 0x1000 |
| 55 | const NX_NVME_OFF_CQ0HDBL: i64 = 0x1004 |
| 56 | const NX_NVME_OFF_CQPEEK: i64 = 0x1008 |
| 60 | const NX_NVME_OFF_CQPEEK_LO: i64 = 0x40 |
| 63 | const NX_NVME_CAP: i64 = 0x0000000000200001 // MQES=32 (0x1F+1), DSTRD=0 (low bits); RO const |
| 64 | const NX_NVME_VS: i64 = 0x00010400 // NVMe 1.4.0 |
| 65 | const NX_NVME_CC_EN: i64 = 1 // CC.EN = bit0 |
| 66 | const NX_NVME_CSTS_RDY: i64 = 1 // CSTS.RDY = bit0 |
| 75 | const NX_NVME_SQE_OFF_OPCODE: i64 = 0 |
| 76 | const NX_NVME_SQE_OFF_CID: i64 = 2 |
| 77 | const NX_NVME_CQE_OFF_CID: i64 = 12 |
| 78 | const NX_NVME_CQE_OFF_STATUS: i64 = 14 |
| 79 | const NX_NVME_PHASE_BIT: i64 = 1 // CQE status bit0 -- the driver polls it |
| 82 | const NX_NVME_OK: i64 = 0 |
| 83 | const NX_NVME_ADDR_OUT_OF_RANGE: i64 = 1 |
| 96 | const NX_NVME_SLOT_CC: i64 = 0 |
| 97 | const NX_NVME_SLOT_CSTS: i64 = 1 |
| 98 | const NX_NVME_SLOT_AQA: i64 = 2 |
| 99 | const NX_NVME_SLOT_ASQ_LO: i64 = 3 |
| 100 | const NX_NVME_SLOT_ASQ_HI: i64 = 4 |
| 101 | const NX_NVME_SLOT_ACQ_LO: i64 = 5 |
| 102 | const NX_NVME_SLOT_ACQ_HI: i64 = 6 |
| 103 | const NX_NVME_SLOT_SQTAIL: i64 = 7 |
| 104 | const NX_NVME_SLOT_CQHEAD: i64 = 8 |
| 105 | const NX_NVME_SLOT_CQPEEK: i64 = 9 |
| 106 | const NX_NVME_SLOT_N: i64 = 10 |
functions
| 115 | func nx_nvme_reset_storage(storage: *i64) -> i64 |
| 129 | func nx_nvme_init(c: *NxNvmeCtrl, storage: *i64) -> i64 |
| 140 | func nx_nvme_addr_in_range(c: *NxNvmeCtrl, addr: i64) -> i64 |
| 148 | func nx_nvme_dma_rd16(mem_buf: *u8, off: i64) -> i64 called by 1: nx_nvme_doorbell_dma |
| 153 | func nx_nvme_dma_rd32(mem_buf: *u8, off: i64) -> i64 |
| 160 | func nx_nvme_dma_wr16(mem_buf: *u8, off: i64, val: i64) -> i64 called by 1: nx_nvme_doorbell_dma |
| 165 | func nx_nvme_dma_wr32(mem_buf: *u8, off: i64, val: i64) -> i64 |
| 172 | func nx_nvme_dma_inrange(off: i64, w: i64, mem_size: i64) -> i64 called by 1: nx_nvme_doorbell_dma |
| 182 | func nx_nvme_read32(c: *NxNvmeCtrl, addr: i64, value_out: *i64) -> i64 |
| 248 | func nx_nvme_doorbell_dma(c: *NxNvmeCtrl, mem_buf: *u8, mem_base: i64, mem_size: i64) -> i64 |
| 283 | func nx_nvme_write32(c: *NxNvmeCtrl, addr: i64, value: i64) -> i64 |
| 329 | func nx_nvme_csts(c: *NxNvmeCtrl) -> i64 |