A core talks to instruction memory, data memory, and MMIO through addresses, not through named ports. The fabric decodes addr into chip-selects.
flowchart LR cpu[RV32I] --> bus[AXI-Lite / mux] bus --> imem[I-mem] bus --> dmem[D-mem] bus --> gpio[GPIO] bus --> uart[UART]
Pick aligned power-of-two windows so decode is a handful of bits:
localparam logic [31:0] DMEM_BASE = 32'h8000_0000;
localparam logic [31:0] GPIO_BASE = 32'h9000_0000;
wire sel_dmem = (addr[31:16] == DMEM_BASE[31:16]);
wire sel_gpio = (addr[31:16] == GPIO_BASE[31:16]);
Keep instruction fetch on a separate port or a fetch-only window so a peripheral write cannot corrupt the I-stream.
Wrong vs right
Wrong — overlapping windows, or decode that depends on the full 32-bit compare with holes.
Right — non-overlapping bases documented in one package; default slave that returns a decode error (or zeros) for unmapped space.