Device virtualization - retrotruestory/M1DEV GitHub Wiki
Here's how to implement device virtualization for Magic-1:
.cseg
.global _init_virtual_devices
.global _register_virtual_device
.global _device_trap_handler
// Initialize virtual device system
_init_virtual_devices:
enter 8
push a
push b
// Setup device trap vector
ld.16 b,#DEVICE_TRAP_VECTOR
ld.16 a,#_device_trap_handler
st.16 (b),a
// Clear device table
ld.16 b,#MAX_VIRTUAL_DEVICES
ld.16 a,#device_table
.clear:
st.16 (a),#0 ; Clear entry
add.16 a,#4 ; Next entry
sub.16 b,#1
br.ne .clear
pop b
pop a
leave
ret
Create the virtual device interface:
#ifndef VIRTUAL_DEVICES_H
#define VIRTUAL_DEVICES_H
#include <stdint.h>
#define MAX_VIRTUAL_DEVICES 16
// Virtual device types
#define VDEV_UART 1
#define VDEV_DISK 2
#define VDEV_CONSOLE 3
// Device operations structure
typedef struct {
int (*init)(void* dev);
int (*read)(void* dev, uint16_t port);
void (*write)(void* dev, uint16_t port, uint8_t value);
void (*interrupt)(void* dev);
} device_ops_t;
// Virtual device structure
typedef struct {
uint16_t base_addr; // Virtual I/O base address
uint16_t size; // I/O space size
uint8_t type; // Device type
void* priv; // Private device data
device_ops_t ops; // Device operations
} virtual_device_t;
// Function declarations
extern void init_virtual_devices(void);
extern int register_virtual_device(virtual_device_t* dev);
extern void unregister_virtual_device(uint16_t base_addr);
#endif
Implement virtual UART device:
#include "virtual_devices.h"
#define UART_RX_BUF_SIZE 16
typedef struct {
uint8_t data_reg; // Data register
uint8_t status_reg; // Status register
uint8_t control_reg; // Control register
uint8_t rx_buffer[UART_RX_BUF_SIZE];
uint8_t rx_head;
uint8_t rx_tail;
uint8_t int_enable; // Interrupt enable flags
} virtual_uart_t;
// UART device operations
static int uart_init(void* dev) {
virtual_uart_t* uart = (virtual_uart_t*)dev;
uart->status_reg = 0x20; // TX empty
uart->rx_head = uart->rx_tail = 0;
return 0;
}
static int uart_read(void* dev, uint16_t port) {
virtual_uart_t* uart = (virtual_uart_t*)dev;
uint8_t offset = port & 0x07;
switch(offset) {
case 0: // Data register
if(uart->rx_head != uart->rx_tail) {
uint8_t data = uart->rx_buffer[uart->rx_tail++];
uart->rx_tail %= UART_RX_BUF_SIZE;
if(uart->rx_head == uart->rx_tail)
uart->status_reg &= ~0x01; // Clear data ready
return data;
}
break;
case 5: // Status register
return uart->status_reg;
}
return 0;
}
static void uart_write(void* dev, uint16_t port, uint8_t value) {
virtual_uart_t* uart = (virtual_uart_t*)dev;
uint8_t offset = port & 0x07;
switch(offset) {
case 0: // Data register
// Forward to real UART
hw_write(UART0_BASE, value);
break;
case 3: // Control register
uart->control_reg = value;
uart->int_enable = (value & 0x08) ? 1 : 0;
break;
}
}
Create virtual device manager:
#include "virtual_devices.h"
static virtual_device_t* devices[MAX_VIRTUAL_DEVICES];
static int num_devices = 0;
// Find device by address
static virtual_device_t* find_device(uint16_t addr) {
for(int i = 0; i < num_devices; i++) {
virtual_device_t* dev = devices[i];
if(addr >= dev->base_addr &&
addr < dev->base_addr + dev->size) {
return dev;
}
}
return NULL;
}
// Handle device access trap
void device_trap_handler(uint16_t addr, uint8_t is_write, uint8_t value) {
virtual_device_t* dev = find_device(addr);
if(!dev) {
printf("Invalid device access: 0x%04x\n", addr);
return;
}
if(is_write)
dev->ops.write(dev->priv, addr, value);
else
return dev->ops.read(dev->priv, addr);
}
Example usage:
#include <stdio.h>
#include "virtual_devices.h"
int main() {
// Initialize virtual device system
init_virtual_devices();
// Create virtual UART
virtual_uart_t uart1;
virtual_device_t vdev = {
.base_addr = 0xE000,
.size = 8,
.type = VDEV_UART,
.priv = &uart1,
.ops = {
.init = uart_init,
.read = uart_read,
.write = uart_write,
.interrupt = NULL
}
};
// Register device
register_virtual_device(&vdev);
// Test virtual UART
// Write to console through virtual device
const char* msg = "Hello from virtual UART\r\n";
for(const char* p = msg; *p; p++) {
device_trap_handler(0xE000, 1, *p);
}
return 0;
}
Update Makefile:
CC = clcc
AS = m1_as
CFLAGS = -O2
OBJECTS = virtual_devices.o virtual_uart.o device_manager.o test_vdev.o
test_vdev: $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $(OBJECTS)
%.o: %.s
$(AS) -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) -c $<
clean:
rm -f test_vdev *.o
Key features:
-
Device Abstraction
- Virtual device interfaces
- Device operation mapping
- I/O port virtualization
-
Device Management
- Dynamic device registration
- Address space management
- Interrupt handling
-
Resource Control
- Device access validation
- Port access restrictions
- Interrupt virtualization
-
Hardware Emulation
- Register emulation
- Status tracking
- Buffer management
This implementation allows:
- Multiple virtual devices
- Device isolation
- Resource sharing
- Hardware abstraction
- Safe device access