TinyEMU Data FlowRISC-V machine

RISC-V machine assembly

The RISC-V initializer converts `VirtMachineParams` into a concrete SoC: RAM at fixed physical addresses, CLINT/PLIC/HTIF devices, a sequence of VirtIO MMIO devices, optional framebuffer/input, and a boot image plus FDT.

Machine topology is fixed and explicitEach RISC-V machine name chooses XLEN, then registers RAM and devices into one `PhysMemoryMap`.
riscv32/riscv64/riscv128
  -> max_xlen
  -> phys_mem_map_init()
  -> riscv_cpu_init(mem_map, max_xlen)
  -> cpu_register_ram(0x80000000, ram_size)
  -> cpu_register_ram(0x00000000, 64 KiB)
  -> cpu_register_device(CLINT)
  -> cpu_register_device(PLIC)
  -> cpu_register_device(HTIF)
CLINT and PLIC feed CPU interrupt stateTimer and external interrupt data flows converge on RISC-V `mip` bits.

CLINT reads expose emulated time and `timecmp`; writes clear timer interrupt state. PLIC IRQ signals set or clear pending bits, and `plic_update_mip()` projects pending external interrupts into machine and supervisor interrupt-pending bits.

device raises IRQ
  -> set_irq(IRQSignal)
  -> plic_set_irq(irq_num, state)
  -> plic_pending_irq changes
  -> plic_update_mip()
  -> riscv_cpu_set_mip(MIP_MEIP | MIP_SEIP)
VirtIO devices are placed in a linear MMIO bankEvery configured device advances `vbus->addr` by `VIRTIO_SIZE` and gets the next PLIC IRQ.
VIRTIO_BASE_ADDR = 0x40010000
VIRTIO_SIZE      = 0x1000
VIRTIO_IRQ       = 1

console -> net -> block drives -> 9P fs -> keyboard -> tablet
each device:
  vbus->irq = &plic_irq[next_irq]
  virtio_*_init(vbus, backend)
  vbus->addr += VIRTIO_SIZE
  next_irq++
Boot payloads are copied into guest RAMBIOS, optional kernel/initrd, FDT, and a low-RAM trampoline form the initial guest view.

`copy_bios()` copies the BIOS at RAM base, aligns and copies the kernel, places initrd near the lower half of RAM, builds an FDT in low RAM, and writes a small trampoline at `0x1000` to jump to `0x80000000` with `a0=hartid` and `a1=dtb`.

RAM_BASE_ADDR + 0:
  BIOS bytes
  aligned kernel bytes
  optional initrd bytes

low RAM:
  0x1000          boot trampoline
  0x1000 + 64     flattened device tree
Machine class hooks drive schedulingThe generic run loop asks the machine for sleep time and CPU execution.

`riscv_machine_get_sleep_duration()` shortens host sleep when the CLINT timer should fire or the CPU is not powered down. `riscv_machine_interp()` delegates the execution slice to the CPU interpreter.

virt_machine_run()
  -> virt_machine_get_sleep_duration()
       RISC-V: consult timer compare and power-down state
  -> select(...)
  -> virt_machine_interp(MAX_EXEC_CYCLE)
       RISC-V: riscv_cpu_interp(cpu_state, n)