Skip to content

Kyuvi/lrv-asm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

(Common) Lisp RISC-V assembler (lrv-asm)

The main repository is on Codeberg. if you are viewing this anywhere else, it is just a mirror. Please use the Codeberg repository for pull requests and issues. Thank you.

Description

A crude but functional implementation of a dynamic RISC-V assembler in Common Lisp, Still in a pre-alpha state, pretty much everything is liable to change. Written and tested in Embeddable Common Lisp and output code has only been created for and tested on the Longan nano development board. I have tried to make it portable but I have not tested it properly on other Common Lisp implementations.

It currently supports only the 32-bit I and M modules plus the base instructions from the C module and the CSR module including the (proposed?) 32-bit CSR memory map, but has been designed to be extended to support other modules and both 64-bit and 128-bit instruction sets as well.

These are actually the basic modules/packages to be used to build up an assembler for the instruction set of a processor when needed.

It is not optimized for using compressed instructions, and when using the “I-C-32-RV” module, unless compressed instructions are explicitly used, the compressed instructions are only used for resolved immediates (labels), i.e. compressed instructions will only be used for backward branches if possible.

Syntax and Notation

Assembly Related

It includes some changes to the standard assembly notation and syntax namely….

  • pait - 4-bit (nibble)
  • byte - 8-bit (byte)
  • jait - 16-bit (half word)
  • vait - 32-bit (word)
  • zait - 64-bit (double word)
  • yait - 128-bit (quad word)

Though I will probably use Double and Quad for the floating point module names as the module letters are derived from those.

also sv/lv (store vait/load vait) are of the form….

  • (sv rs rb imm) ;; sv source-reg base-reg immediate
  • (lv rd rb imm) ;; lv dest-reg base-reg immediate

as are all the other loads and stores (sb,lb, sj/lj, sz/lz).

I personally find it easier to think like this about (modern) assembly code.

Common Lisp Related

I shadowed “and”, “or”, (in the I-C-32-lrv module), “not” (in the rvi-derived module) and rem (in the Multiplication module) so one can either shadow them when importing or use cl:and, cl:or etc in code.

Two new reader macros have been added namely, “#h” and “#y” for Twos complement hexadecimal and binary numbers respectively. They (should) act like hexadecimal and binary notations in other assemblers using the most significant bit of the register-length (i.e. bits 31 or 63) as the sign bit and can also be negated (i.e. #h-num = (- num), so #h-ffffffff = 1). This should avoid some issues with register-length immediate loads, i.e load immediate (li rd imm32), load address (la rd imm32) etc, and also help with optimisation.

While in Common Lisp the notation +constant+ is sometimes used for constants, I just added a phi symbol to the end to represent constants i.e. constantΦ, it turns out there are a lot of constants in the RISC-V ISA (see ./lrv-ins/csr-lrv.cl).

Installation and Use

This depends on having (Embeddable) Common lisp installed on the computer already.

Due to time, personal and design reasons (the design is nowhere near complete as only a fraction of the modules have been finished and I am still learning about the RISC-V ISA and how it is used in implementations), this has not been packaged with ASDF, so the files need to be loaded into a lisp environment in order and a new package made using the right modules to target a particular processor.

A simple example targeting the longan development board from a file in the top level i.e. the same level as this README.org. A position adjusted version of this example can be found in the examples folder.


(in-package cl-user)

(load "./lrv-korr/packages.lisp")
(load "./lrv-korr/env-lrv.cl")
(load "./lrv-korr/kone-lrv.cl")
(load "./lrv-korr/fmt-lrv.cl")
(load "./lrv-korr/files-lrv.cl")
(load "./lrv-korr/lrv-utils/clrv-utils.cl")

(load "./lrv-ins/I-lrv.cl")
(load "./lrv-ins/C-lrv.cl")
(load "./lrv-ins/I-C-lrv.cl")
(load "./lrv-ins/rvi-derived.cl")
(load "./lrv-ins/M-lrv.cl")
(load "./lrv-ins/csr-lrv.cl")


(defpackage "LONGAN"
  (:use :cl :rvasm :clrv :c32 :i32 :ic32 :rdv :m32 :csr :csr32)
  ;; beqz, bnez inc and dec  also defined in rvdrv.
  (:shadowing-import-from :ic32 and or beqz bnez inc dec )
  (:shadowing-import-from :m32 rem )
  (:shadowing-import-from :rdv not ))

(in-package :longan)

;; set up processor specific environment with code starting at address 0

(defparameter *env* (make-instance 'basic-env :address 0))

(defparameter *max-address* (* 128 1024)) ;; longan internal flash is 128kb


;; This can then be used as the actual assembler
;; for the bumblebee core in the GD32V-IMAC SOC on the longan development board.

;; =code starts here=
(addi 'x1 'x0 #h20)  ;; load 20 into register x1


;; set output file
(setf (bin-file "path/to/output-file.bin") (link *env*))

Plans and Goals

Goals

  • Simple clear code using the expressiveness of (common) lisp.
  • Modular code to mirror the modularity of the RISC-V instruction set Architecture.
  • Concise and fast machine code output.
  • Upload output file to development board from lisp environment(REPL) on Linux, iOS and Windows.
  • Simplified/Minimalised assembly syntax (no parenthesis or quotes)
  • Include remaining finalized RISC-V instruction modules.
  • 64-bit.
  • Automate building an assembler for a specific processor based on specified modules

Long term Goals

  • 128-bit.
  • ASDF build system and quicklisp (after design stabilization).
  • All RISC-V instruction modules including those not yet finalized

Non Goals

  • Speed of assembly/compiling process.
  • Targeting Multiple Instruction Set Architectures (though env-lrv.cl could be used for this with some expansion).

  • [ ] Edit/Add readtable to accept assembly syntax without parenthesis, quotes, set-label and label (while still allowing parenthesis for complex expressions?).
  • [ ] Add built in DFU (Device Firmware Upgrade) utility (using libusb?) that can be called from the REPL.
  • [ ] Optimize compiler (env-lrv.cl) for optional compressed instruction set use automatically (and clearly).
  • [ ] Include in and Optimize for optional floating point instruction sets automatically (and clearly) in Engine (kone-lrv.cl) or separate file.
  • [ ] Include all finalized RISC-V modules.
  • [ ] Include 64-bit instruction set in modules.
  • [ ] Automate building an assembler for a specific processor based on specified modules.
  • [ ] Include 128-bit instruction set in modules.

Acknowledgments

This assembler is based on

Also thanks to