Software··2 min de lectura

RISC‑V interpreter listo para producción con Rust const y sin panics

Un nuevo intérprete RISC‑V, totalmente modular y compatible con la certificación, se ejecuta a tiempo de compilación y no usa memoria dinámica.

El intérprete RISC‑V que anunciamos hace unas semanas ya está en un estado que puede usar cualquier persona. Se trata de un proyecto abierto, en Rust, que cumple con la especificación de RISC‑V y pasa las pruebas de certificación arquitectónica.

Características clave

  • Modularidad. La arquitectura se divide en base ISA y extensiones, y cada una se implementa como un módulo independiente. Los registros, la memoria y los tipos de registro son genéricos, por lo que se pueden combinar sin restricciones.
  • Sin panics, no_std y sin asignaciones. Todo el código está escrito con no_std y no provoca errores de tiempo de ejecución. Tampoco se hacen llamadas a alloc, lo que lo hace apto para entornos embebidos y blockchain.
  • Const‑fn. El intérprete se ejecuta a tiempo de compilación, lo que permite usarlo en constantes y generar código estático.
  • Rápido. A pesar de todas estas restricciones, el rendimiento es competitivo con intérpretes tradicionales.
  • Compatibilidad. El intérprete pasa los tests de certificación RISC‑V y sigue la especificación al pie de la letra.

Implementación

El núcleo se compone de dos crates: ab-riscv-interpreter y ab-riscv-primitives. El primero contiene la lógica de ejecución, el segundo se encarga de la definición y decodificación de instrucciones.

#[instruction]
#[derive(Debug, Clone, Copy)]
#[derive_const(PartialEq, Eq)]
pub enum ZicondInstruction<Reg> {
    CzeroEqz { rd: Reg, rs1: Reg, rs2: Reg },
    CzeroNez { rd: Reg, rs1: Reg, rs2: Reg },
}

El macro #[instruction] genera automáticamente el método try_decode y asegura que solo se devuelvan instrucciones válidas. Las dependencias entre extensiones se expresan con #[instruction(inherit = [...])] o #[instruction(if = [...])], lo que permite componer instrucciones de manera segura.

Para evitar que una instrucción sea decodificada, basta con ignorarla:

#[instruction(ignore = [Ecall], inherit = [Rv64ZcaInstruction, ...])]
pub enum ContractInstruction<Reg = ContractRegister> {}

El proyecto todavía no soporta conflictos de instrucciones, pero eso se añadirá cuando aparezcan extensiones que lo requieran.

Cómo funciona la generación

Dado que Rust no soporta macros de estado, se utiliza un script de construcción que escanea los archivos y genera las implementaciones de decodificación. Un proc‑macro sencillo se encarga de reemplazar los marcadores en tiempo de compilación.

Próximos pasos

Se están afinando los detalles de las pruebas y se espera que la mayoría de las características usadas, como generics const avanzados y llamadas tail, se estabilicen en la próxima versión estable de Rust. Si el proyecto gana tracción, se podrá usar en proyectos de blockchain o en sistemas embebidos que requieran un intérprete ligero y seguro.

El intérprete ya está disponible en los repositorios de ab-riscv-interpreter y ab-riscv-primitives. Los interesados pueden probarlo con los ejemplos de cargo test y aportar mejoras a través de pull requests.

##Relacionado