La computación moderna, especialmente en sistemas embebidos y de tiempo real, enfrenta el desafío fundamental de garantizar respuestas deterministas a eventos externos, a menudo a expensas de la flexibilidad o la eficiencia de recursos. Los CPUs de propósito general, con sus sistemas operativos multitarea, introducen latencia y jitter inaceptables para muchas aplicaciones de E/S de bajo nivel. Los coprocesadores de E/S dedicados abordan esto, pero su diseño arquitectónico —particularmente la elección entre CISC y RISC— tiene profundas implicaciones en el uso de recursos de hardware, la velocidad de reloj y la facilidad de programación.
El artículo explora esta dicotomía a través del análisis del PIO (Programmable I/O) de Raspberry Pi, una arquitectura CISC, y propone el BIO (Bao I/O Coprocessor), una alternativa basada en RISC-V. La tesis es que una arquitectura RISC, aunque requiera más instrucciones por operación, puede lograr una mayor eficiencia en el uso de área de silicio y velocidad de reloj, manteniendo la flexibilidad y el determinismo, especialmente cuando se complementa con extensiones de ISA bien diseñadas para E/S y comunicación inter-core. Esto se vuelve crucial en el contexto de SoCs modernos donde la optimización de recursos es clave.
Arquitectura del Sistema
El BIO se basa en un núcleo PicoRV32 configurado como RV32E, una variante de RISC-V con un conjunto de 16 registros de propósito general (r0-r15). La innovación clave reside en la extensión de este conjunto de registros para incluir 'register queues' (x16-x19), acceso a GPIO (x21-x26), y primitivas de sincronización (x20, x27-x30). Estos registros de 'high-bank' implementan semánticas de bloqueo: las lecturas de FIFOs se detienen si están vacías, y las escrituras si están llenas. Esto permite una comunicación inter-core eficiente y un control de flujo determinista sin polling activo.
El registro x20 ('halt to quantum') permite que el CPU se detenga hasta que ocurra un pulso de un divisor de reloj interno o un evento GPIO externo, facilitando la sincronización de eventos a intervalos precisos. El registro x30 ('halt to event') detiene la ejecución hasta que se cumpla una condición de evento, como un nivel de llenado de FIFO. El acceso a GPIO se optimiza para 'bit-banging' rápido, con una semántica especial de 'clear-on-0' para la limpieza de bits. La extensión BDMA (Bao DMA) opcional permite a los núcleos BIO acceder al bus del SoC para transferencias DMA, con un resolutor de prioridad simple. Cada núcleo BIO tiene su propia memoria de instrucciones de 4 KiB, implementada con macros de RAM de un solo puerto, lo que contrasta con la memoria compartida y pequeña del PIO.
Flujo de Transferencia DMA con BIO (2 Cores)
- 1 Core 2 (Generador de Direcciones) Espera parámetros DMA (dir. origen, #bytes) desde FIFO2 (x18).
- 2 Core 2 (Generador de Direcciones) Genera direcciones de origen y las escribe en FIFO0 (x16). Se bloquea si FIFO...
- 3 Core 3 (Generador de Direcciones) Espera dirección de destino desde FIFO3 y genera direcciones de escritura en ...
- 4 Core 1 (Fetch/Store) Lee dirección de origen de FIFO0 (x16) y dirección de destino de FIFO1 (x17).
- 5 Core 1 (Fetch/Store) Carga dato de memoria de origen (lw) y lo almacena en memoria de destino (sw).
- 6 Core 1 (Fetch/Store) Repite hasta que se complete la transferencia o FIFOs se vacíen/llenen.
Flujo de Bit-Banging SPI con BIO (2 Cores)
- 1 Core TX (Máquina 2) Configura máscaras y pines GPIO (salida, reloj, chip select).
- 2 Core TX (Máquina 2) Espera un 'quantum' para asegurar el tiempo de retención de Chip Select.
- 3 Core TX (Máquina 2) Carga dato a transmitir de FIFO0 (x16). Se bloquea hasta que haya datos.
- 4 Core TX (Máquina 2) Itera por cada bit: establece/limpia pin de datos, espera 'quantum', sube rel...
- 5 Core RX (Máquina 3) Espera a que Chip Select caiga (lectura de x21).
- 6 Core RX (Máquina 3) Itera por cada bit: espera 'quantum' (sincronizado con flanco de reloj TX), l...
| Capa | Tecnología | Justificación |
|---|---|---|
| compute | PicoRV32 (RV32E) | Núcleo de CPU RISC-V de bajo consumo de área para cada coprocesador BIO. Proporciona un conjunto de instrucciones estándar y acceso a herramientas de software existentes. vs Arquitectura CISC (ej. PIO de Raspberry Pi) Configurado como RV32E (16 registros), con extensiones de registros para FIFOs, GPIO y sincronización. |
| storage | RAM macro de un solo puerto (1024x32 bits, 4 KiB) | Memoria de instrucciones dedicada para cada núcleo BIO. Permite programas más grandes y complejos que el PIO. vs Memoria de instrucciones compartida y pequeña (ej. 32 entradas en PIO), Implementación de memoria con flip-flops 4 KiB por núcleo, tamaño optimizado para eficiencia de área en procesos ASIC. |
| networking | GPIO | Interfaz física para el control de pines de entrada/salida. El BIO optimiza el 'bit-banging' con semánticas de acceso especiales. Semántica 'clear-on-0' para limpieza de bits en operaciones de salida. |
| messaging | Register Queues (FIFOs) | Mecanismo de comunicación inter-core y con el host, implementado como registros con semántica de bloqueo (full/empty). vs Polling de registros de estado, Interrupciones 8-deep FIFOs (x16-x19), con priorización de acceso (host > cores de menor número). |
| orchestration | Quantum Register (x20) | Mecanismo de sincronización que detiene la ejecución del CPU hasta un pulso de reloj o evento GPIO externo, garantizando tiempos precisos. vs Conteo de ciclos manual en software |
| data-processing | BDMA Extension | Extensión opcional para permitir a los núcleos BIO actuar como motores DMA inteligentes, moviendo datos entre memoria principal y FIFOs. vs DMA dedicado de hardware, Transferencias de datos por CPU principal Acceso a memoria principal restringido por 'whitelist' para seguridad. |
Trade-offs
Ganancias
- ▲ Eficiencia de área lógica
- ▲ Velocidad de reloj máxima
- ▲ Flexibilidad de programación (ISA completa, C toolchain)
- ▲▲ Memoria de código por core
Costes
- ▲ Instrucciones por ciclo (IPC)
- △ Velocidad pico para 'bit-banging' simple
- △ Complejidad de la cadena de herramientas (para C)
bio_code!(dma_mc_copy_code, DMA_MC_COPY_START, DMA_MC_COPY_END,
"20:",
"lw a0, 0(x16)", // unrolled for more performance
"sw a0, 0(x17)",
"lw a0, 0(x16)",
"sw a0, 0(x17)",
"lw a0, 0(x16)",
"sw a0, 0(x17)",
"lw a0, 0(x16)",
"sw a0, 0(x17)",
"j 20b"
);// pin is provided as the GPIO number to drive
// strip is an array of u32's that contain GRB data
// len is the length of the strip
void ws2812c(uint32_t pin, uint32_t *strip, uint32_t len) {
uint32_t led;
// sanity check the pin value
if (pin > 31) {
return;
}
uint32_t mask = 1 << pin;
uint32_t antimask = ~mask;
set_gpio_mask(mask);
set_output_pins(mask);
// ensure timing with a nil quantum here
clear_gpio_pins_n(antimask);
wait_quantum();
// main loop
for (uint32_t i = 0; i < len; i++) {
led = strip[i];
for (uint32_t bit = 0; bit < 24; bit++) {
if ((led & 0x800000) == 0) {
// 2 hi
set_gpio_pins(mask);
wait_quantum();
wait_quantum();
// 5 lo
clear_gpio_pins_n(antimask);
wait_quantum();
wait_quantum();
wait_quantum();
wait_quantum();
wait_quantum();
} else {
// 5 hi
set_gpio_pins(mask);
wait_quantum();
wait_quantum();
wait_quantum();
wait_quantum();
wait_quantum();
// 5 lo
clear_gpio_pins_n(antimask);
wait_quantum();
wait_quantum();
wait_quantum();
wait_quantum();
wait_quantum();
}
led <<= 1;
}
}
}Fundamentos Teóricos
La discusión sobre CISC vs. RISC es un debate fundamental en la arquitectura de computadoras, que se remonta a los años 80. El artículo de David Patterson y Carlo H. Sequin, "A Perspective on VLSI RISC" (1982), fue seminal en la promoción de la filosofía RISC, argumentando que conjuntos de instrucciones más simples permiten implementaciones de hardware más rápidas y eficientes en términos de área, incluso si requieren más instrucciones por tarea. El PIO, con sus instrucciones complejas y multifuncionales, es un ejemplo de la filosofía CISC, mientras que el BIO, basado en RISC-V, encarna el enfoque RISC.
La idea de registros con semántica de bloqueo o colas integradas en el archivo de registros tiene precedentes en arquitecturas de computadoras para paralelismo a nivel de instrucción y comunicación inter-procesador. El concepto de 'queues' como primitivas de comunicación es un pilar en sistemas concurrentes, y su integración a nivel de ISA, como en la arquitectura ADAM mencionada por el autor, es una aplicación directa de principios de concurrencia para simplificar la programación de hardware y garantizar el determinismo en entornos de E/S.