Data Flow
Configuration Parsing
The emulator starts in main() inside temu.c. It parses CLI flags, sets defaults, loads a JSON configuration file, and then overrides parameters like RAM size or acceleration.
int main(int argc, char **argv)
{
VirtMachine *s;
VirtMachineParams p_s, *p = &p_s;
/* ... option parsing ... */
virt_machine_set_defaults(p);
virt_machine_load_config_file(p, path, NULL, NULL);
/* override parameters */
if (ram_size > 0) p->ram_size = (uint64_t)ram_size << 20;
/* open drives, filesystems, network */
s = virt_machine_init(p);
for(;;) { virt_machine_run(s); }
}JSON Config Loader
machine.c defines virt_machine_parse_config() which walks the JSON object and fills VirtMachineParams: machine name, RAM size, drives, filesystems, network interfaces, display, and input devices.
int virt_machine_parse_config(VirtMachineParams *p,
const char *buf, int buf_len)
{
/* parse JSON into VM parameters */
}Machine Class Dispatch
machine.h defines the VirtMachineClass vtable. Two classes are exported: riscv_machine_class and pc_machine_class. The config machine_name selects which class is used.
struct VirtMachineClass {
const char *machine_names;
void (*virt_machine_set_defaults)(VirtMachineParams *p);
VirtMachine *(*virt_machine_init)(const VirtMachineParams *p);
void (*virt_machine_end)(VirtMachine *s);
int (*virt_machine_get_sleep_duration)(VirtMachine *s, int delay);
void (*virt_machine_interp)(VirtMachine *s, int max_exec_cycle);
BOOL (*vm_mouse_is_absolute)(VirtMachine *s);
void (*vm_send_mouse_event)(VirtMachine *s1, int dx, int dy, int dz,
unsigned int buttons);
void (*vm_send_key_event)(VirtMachine *s1, BOOL is_down, uint16_t key_code);
};RISC-V Machine Initialization
riscv_machine_init() in riscv_machine.c is the heart of SoC setup. It creates the memory map, initializes the CPU, registers RAM, CLINT, PLIC, HTIF, and all VirtIO devices, then copies the BIOS/kernel into RAM and builds the Flattened Device Tree (FDT).
static VirtMachine *riscv_machine_init(const VirtMachineParams *p)
{
RISCVMachine *s;
/* select xlen from machine_name */
s->mem_map = phys_mem_map_init();
s->cpu_state = riscv_cpu_init(s->mem_map, max_xlen);
cpu_register_ram(s->mem_map, RAM_BASE_ADDR, p->ram_size, 0);
cpu_register_ram(s->mem_map, 0x00000000, LOW_RAM_SIZE, 0);
cpu_register_device(s->mem_map, CLINT_BASE_ADDR, CLINT_SIZE, s,
clint_read, clint_write, DEVIO_SIZE32);
cpu_register_device(s->mem_map, PLIC_BASE_ADDR, PLIC_SIZE, s,
plic_read, plic_write, DEVIO_SIZE32);
cpu_register_device(s->mem_map, HTIF_BASE_ADDR, 16,
s, htif_read, htif_write, DEVIO_SIZE32);
/* virtio devices */
virtio_console_init(vbus, p->console);
virtio_net_init(vbus, p->tab_eth[i].net);
virtio_block_init(vbus, p->tab_drive[i].block_dev);
virtio_9p_init(vbus, p->tab_fs[i].fs_dev, p->tab_fs[i].tag);
/* display & input */
simplefb_init(s->mem_map, FRAMEBUFFER_BASE_ADDR, fb_dev, p->width, p->height);
virtio_input_init(vbus, VIRTIO_INPUT_TYPE_KEYBOARD);
virtio_input_init(vbus, VIRTIO_INPUT_TYPE_TABLET);
/* copy bios/kernel/cmdline and build FDT */
copy_bios(s, ...);
return (VirtMachine *)s;
}Key Data Structures
VirtMachineParams— holds the full parsed configuration.VirtMachine— abstract base with console, net, fb_dev.RISCVMachine— extends VirtMachine with cpu_state, mem_map, plic_irq, htif, rtc, virtio_count.