rubbler 0.1.1

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.
# 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 <CTRL-d> 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 <CTRL-d> once finished)
jal t0, hello
> Rubbling...
[Line 1] Generator error: Cannot resolve symbol: `hello`.
```

```
$ rubble
> Input RISC-V assembly line(s): (Press <CTRL-d> once finished)
hello
> Rubbling...
[Line 1] Syntax error: Unknown opcode or directive `hello`.
```

### Supports labels

```
$ rubble
> Input RISC-V assembly line(s): (Press <CTRL-d> 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 <CTRL-d> 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.