# Rubbler `rubbler` is a RISC-V assembler written in Rust 🦀. This library was written with the main purpose of embedding a simple RISC-V assembler inside of a RISC-V CPU test bench code written with [verilator](https://github.com/verilator/verilator). In addition, a command line program called `rubble` can also be installed. `rubble` reads lines from standard input and outputs a string of '1's and '0's representing the assembled code to standard output. ## Features ### Verbose error explanation ``` $ rubble > Input RISC-V assembly line(s): (Press once finished) add t0, t1, 5 > Rubbling... [Line 1] Generator error: `add` instruction expects the following arguments: [RegDest, RegSrc1, RegSrc2]. ``` ``` $ rubble > Input RISC-V assembly line(s): (Press once finished) jal t0, hello > Rubbling... [Line 1] Generator error: Cannot resolve symbol: `hello`. ``` ``` $ rubble > Input RISC-V assembly line(s): (Press once finished) hello > Rubbling... [Line 1] Syntax error: Unknown opcode or directive `hello`. ``` ### Supports labels ``` $ rubble > Input RISC-V assembly line(s): (Press once finished) fibonacci: addi t0, zero, 0 # t0 addi t1, zero, 1 # t1 addi t2, zero, 0 # i loop: bge t2, a0, end add t3, t0, t1 # temp addi t0, t1, 0 addi t1, t3, 0 addi t2, t2, 1 jal t4, loop end: addi a0, t0, 0 > Rubbling... > Here's your bytes: 10010011000000100000000000000000 00010011000000110001000000000000 10010011000000110000000000000000 01100011110111001010001100000000 00110011100011100110001000000000 10010011000000100000001100000000 00010011000000110000111000000000 10010011100000110001001100000000 11101111111111101101111111111110 00010011100001010000001000000000 ``` ### Supports directives ``` $ rubble > Input RISC-V assembly line(s): (Press once finished) .section .data .byte 1, 2, 3 > Rubbling... > Here's your bytes: 000000010000001000000011 ``` See [Supported directives](#supported-directives) for all supported directives. ## Supported instructions Right now, only a subset of RV32I are supported: - Register‒Immediate arithmetic operations - ADDI, ANDI, ORI, XORI, SLTI, SLTIU, SLLI, SRLI, LUI, AUIPC - Register‒Register arithmetic operation - ADD, AND, OR, XOR, SLT, SLTU, SLL, SRL, SRA, SUB - Jump instructions - JAL, JALR - Branch instructions - BEQ, BNE, BLT, BLTU, BGE, BGEU - Load operations - LW, LH, LHU, LB, LBU - Store operations - SW, SH, SB ## Supported assembly directives Right now, only the following directives are available for use: - .align - .p2align - .comm - .common - .section - .equ - .byte See [RISC-V Assembly Programmer's Manual](https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md) for the syntax of each directives. ## Building from source ### Requirements Rust (see [installing Rust](https://www.rust-lang.org/tools/install)) ### Build instructions ```sh git clone https://github.com/fuad1502/rubbler.git cd rubbler cargo build --release ``` These commands outputs `rubbler/target/release/rubble` binary, `rubbler/target/rubbler.h` header and `rubbler/target/release/librubbler.a` static library. ## Usage example ### Rust ```rust let source = "lui t2, -3"; let expected_res = vec![0b10110111,0b11110011,0b11111111,0b11111111]; let res = rubbler::rubble(source).unwrap(); assert_eq!(res, expected_res); ``` For more examples in Rust, see [docs.rs/rubbler](https://docs.rs/rubbler). ### C/C++ This example is a snippet taken from [rubbler-verilator-example](). ```c++ #include "rubbler.h" ... auto source = "add t0, t1, t2"; auto bytes = (uint8_t *)malloc(sizeof(uint8_t) * MAX_SIZE); uintptr_t size = MAX_SIZE; assert(rubble(source, bytes, &size)); ... ``` See [docs.rs/rubbler](https://docs.rs/rubbler) `rubbler::ffi` module for a complete explanation on how to use each function, or simply look at the documentation string of each function in `rubbler.h`. ## Integrating with Verilator In the following discussion, we assume you have installed `verilator`, and the `verilator` command is available. See the [verilator doccumentation](https://veripool.org/guide/latest/index.html) for instructions on doing so. Both of the following example is taken from [rubbler-verilator-example](). ### Using Makefile Assuming the following project directory structure: ``` - project - main.cpp - top.sv - Makefile ``` The following `Makefile` will build `main` from `main.cpp` and `top.sv` that can use both `verilator` and `rubbler` library from `main.cpp`. ```makefile VERILATOR_ROOT := /usr/local/share/verilator VM_SC := 0 VM_TRACE := 0 VERILATOR_OBJS := verilated.o verilated_threads.o verilated_dpi.o main:main.o obj_dir/Vtop__ALL.a librubbler.a $(VERILATOR_OBJS) $(CXX) $^ -o $@ main.o: main.cpp obj_dir/Vtop.h rubbler.h $(CXX) \ -Iobj_dir \ -I$(VERILATOR_ROOT)/include \ -I$(VERILATOR_ROOT)/include/vltstd \ -c main.cpp -o $@ obj_dir/Vtop__ALL.a obj_dir/Vtop.h: top.sv verilator -cc --build -j top.sv rubbler.h librubbler.a: rubbler cd rubbler && cargo build --release cp rubbler/target/rubbler.h rubbler/target/release/librubbler.a . rubbler: git clone https://github.com/fuad1502/rubbler.git include $(VERILATOR_ROOT)/include/verilated.mk .PHONY:clean clean: rm -rf obj_dir rm -rf rubbler rm librubbler.a rubbler.h rm *.o *.d rm main ``` See [rubbler-verilator-example](https://github.com/fuad1502/rubbler-verilator-example). for the complete example. ### Using CMake `ExternalProject` Assuming the following project directory structure: ``` - project - main.cpp - top.sv - CMakeLists.txt ``` The following `CMakeLists.txt` file will build `main` from `main.cpp` and `top.sv` that can use both `verilator` and `rubbler` library from `main.cpp`. ```cmake cmake_minimum_required(VERSION 3.14) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project(rubbler-verilator-example) find_package(verilator REQUIRED) include(ExternalProject) ExternalProject_Add( rubbler GIT_REPOSITORY https://github.com/fuad1502/rubbler.git DOWNLOAD_DIR ${CMAKE_BINARY_DIR} SOURCE_DIR ${CMAKE_BINARY_DIR}/rubbler BINARY_DIR ${CMAKE_BINARY_DIR}/rubbler CONFIGURE_COMMAND "" INSTALL_COMMAND "" BUILD_COMMAND cargo build --release ) set(RUBBLER_LIB ${CMAKE_BINARY_DIR}/rubbler/target/release/librubbler.a) add_executable(main main.cpp) target_include_directories(main PRIVATE ${CMAKE_BINARY_DIR}/rubbler/target) target_link_libraries(main PRIVATE ${RUBBLER_LIB}) verilate(main SOURCES top.sv) ``` See [rubbler-verilator-example](https://github.com/fuad1502/rubbler-verilator-example). for the complete example. ## Binary installation To use the `rubble` binary system wide, install it with the following command: ```sh cargo install rubbler ``` ## Issues - Using symbols inside memory addressing expressions is not yet supported. ## Planned features - Report multiple errors instead of terminating on the first detected error. - Increase error reporting verbosity by adding column information and show the offending line together with the report. - Support pseudo instructions.