├── LICENSE ├── README.md ├── RISC-V Assembler FP.lisp └── RISC-V Assembler.lisp /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 David Johnson-Davies 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lisp RISC-V Assembler 2 | A RISC-V assembler written in Lisp. It will run under Common Lisp or my uLisp interpreter for microcontroller boards. 3 | 4 | For more information see http://www.ulisp.com/show?310Z. 5 | 6 | For a list of the RISC-V instructions supported by the assembler see: http://www.ulisp.com/show?30Z4. 7 | 8 | For assembler examples see: http://www.ulisp.com/show?30ZU. 9 | 10 | The file **RISC-V Assembler FP.lisp** contains optional floating-point extensions; for an example of their use see: http://forum.ulisp.com/t/mandelbrot-set-using-risc-v-assembler/522. 11 | -------------------------------------------------------------------------------- /RISC-V Assembler FP.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; RISC-V Assembler - Floating-Point Extensions - 1st April 2020 3 | ; see http://forum.ulisp.com/t/mandelbrot-set-using-risc-v-assembler/522 4 | ; 5 | 6 | ; Extract register number 7 | (defun regno (sym) 8 | (case sym (zero 0) (ra 1) (sp 2) (gp 3) (tp 4) (s0 8) (fp 8) (s1 9) 9 | (t (let* ((s (string sym)) 10 | (c (char s 0))) 11 | (case c 12 | (#\f 13 | (let ((c (char s 1)) 14 | (n (read-from-string (subseq s 2)))) 15 | (case c (#\t (if (<= n 7) n (+ n 20))) 16 | (#\s (if (<= n 1) (+ n 8) (+ n 16))) (#\a (+ n 10))))) 17 | (t 18 | (let ((n (read-from-string (subseq s 1)))) 19 | (case c (#\x n) (#\a (+ n 10)) (#\s (+ n 16)) 20 | (#\t (if (<= n 2) (+ n 5) (+ n 25))))))))))) 21 | 22 | 23 | (defun fmuldiv (op rs2 rs1 funct3 rd funct7) 24 | (emit* '(7 5 5 3 5 7) op (regno rs2) (regno rs1) funct3 (regno rd) funct7)) 25 | 26 | (defun fstore (imm src base op funct7) 27 | (emit* '(7 5 5 3 5 7) (bits imm 11 5) (regno src) (regno base) op (bits imm 4 0) funct7)) 28 | 29 | (defun $fadd.s (rd rs1 rs2) 30 | (fmuldiv #x00 rs2 rs1 7 rd #x53)) 31 | 32 | (defun $fcvt.s.w (rd rs1) 33 | (fmuldiv #x68 'x0 rs1 7 rd #x53)) 34 | 35 | (defun $fcvt.w.s (rd rs1) 36 | (fmuldiv #x60 'x0 rs1 7 rd #x53)) 37 | 38 | (defun $fdiv.s (rd rs1 rs2) 39 | (fmuldiv #x0c rs2 rs1 7 rd #x53)) 40 | 41 | (defun $flw (rd imm lst) 42 | (cond 43 | ((listp lst) 44 | (immed imm (car lst) 2 rd #x07)))) 45 | 46 | (defun $fmul.s (rd rs1 rs2) 47 | (fmuldiv #x08 rs2 rs1 7 rd #x53)) 48 | 49 | (defun $fsub.s (rd rs1 rs2) 50 | (fmuldiv #x04 rs2 rs1 7 rd #x53)) 51 | 52 | (defun $fsw (src imm lst) 53 | (cond 54 | ((listp lst) 55 | (fstore imm src (car lst) 2 #x27)))) 56 | 57 | (defun $fsgnj.s (rd rs1 rs2) 58 | (fmuldiv #x10 rs2 rs1 0 rd #x53)) 59 | 60 | (defun $fsgnjn.s (rd rs1 rs2) 61 | (fmuldiv #x10 rs2 rs1 1 rd #x53)) 62 | 63 | (defun $fsgnjx.s (rd rs1 rs2) 64 | (fmuldiv #x10 rs2 rs1 2 rd #x53)) 65 | 66 | (defun $fmv.s (rd rs) 67 | ($fsgnj.s rd rs rs)) 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /RISC-V Assembler.lisp: -------------------------------------------------------------------------------- 1 | ; RISC-V Assembler - Version 4 - 18th October 2024 2 | ; see http://www.ulisp.com/show?310Z 3 | ; 4 | 5 | ; Extract register number 6 | (defun regno (sym) 7 | (case sym (zero 0) (ra 1) (sp 2) (gp 3) (tp 4) ((s0 fp) 8) (s1 9) 8 | (t (let* ((s (string sym)) 9 | (c (char s 0)) 10 | (n (read-from-string (subseq s 1)))) 11 | (case c (#\x n) (#\a (+ n 10)) (#\s (+ n 16)) (#\t (if (<= n 2) (+ n 5) (+ n 25)))))))) 12 | 13 | ; Short 3-bit register s0, s1, a0 to a5 14 | (defun cregp (rd) (<= 8 (regno rd) 15)) 15 | 16 | (defun cregno (sym) (logand (regno sym) #x7)) 17 | 18 | ; Pack arguments into bit fields 19 | (defun emit (bits &rest args) 20 | (let ((word 0)) 21 | (mapc #'(lambda (width value) 22 | (unless (zerop (ash value (- width))) (error* "Won't fit")) 23 | (setq word (logior (ash word width) value))) 24 | bits args) 25 | word)) 26 | 27 | ; 32-bit emit 28 | (defun emit32 (bits &rest args) 29 | (let ((word (apply #'emit bits args))) 30 | (list (logand word #xffff) (logand (ash word -16) #xffff)))) 31 | 32 | ; Errors 33 | (defun error* (txt) (format t "(pc=#x~x) ~a~%" *pc* txt)) 34 | 35 | ; Test range of immediate signed values 36 | (defun immp (x b) 37 | (<= (- (ash 1 (1- b))) x (1- (ash 1 (1- b))))) 38 | 39 | ; Extract bitfield 40 | (defun bits (x a &optional b) 41 | (if b (logand (ash x (- b)) (1- (ash 1 (- a b -1)))) 42 | (logand (ash x (- a)) 1))) 43 | 44 | (defun offset (label) (- label *pc*)) 45 | 46 | ; Instruction formats 47 | 48 | (defun reg (funct7 rs2 rs1 funct3 rd op) 49 | (emit32 '(7 5 5 3 5 7) funct7 (regno rs2) (regno rs1) funct3 (regno rd) op)) 50 | 51 | (defun creg (op3 op1 op2 rd op2b rs2) 52 | (cond 53 | ((and (cregp rd) (cregp rs2)) 54 | (emit '(3 1 2 3 2 3 2) op3 op1 op2 (cregno rd) op2b (cregno rs2) 1)) 55 | (t (error* "C won't fit")))) 56 | 57 | (defun immed (imm12 rs1 funct3 rd op) 58 | (cond 59 | ((immp imm12 12) 60 | (emit32 '(12 5 3 5 7) (logand imm12 #xfff) (regno rs1) funct3 (regno rd) op)) 61 | (t 62 | (error* "Immediate value out of range")))) 63 | 64 | (defun cimmed (imm12 rs1 funct3 rd op) 65 | (emit32 '(12 5 3 5 7) imm12 (regno rs1) funct3 (regno rd) op)) 66 | 67 | (defun branch (imm12 rs2 rs1 funct3 funct7) 68 | (let ((off (offset imm12))) 69 | (emit32 '(1 6 5 5 3 4 1 7) 70 | (bits off 12) (bits off 10 5) (regno rs2) 71 | (regno rs1) funct3 (bits off 4 1) (bits off 11) funct7))) 72 | 73 | (defun jump (imm20 imm10-1 imm11 imm19-12 rd op) 74 | (emit32 '(1 10 1 8 5 7) imm20 imm10-1 imm11 imm19-12 rd op)) 75 | 76 | (defun muldiv (rs2 rs1 funct3 rd funct7) 77 | (emit32 '(7 5 5 3 5 7) 1 (regno rs2) (regno rs1) funct3 (regno rd) funct7)) 78 | 79 | (defun store (imm src base op) 80 | (emit32 '(7 5 5 3 5 7) (bits imm 11 5) (regno src) (regno base) op (bits imm 4 0) #x23)) 81 | 82 | (defun cimm6 (rd imm op1 op2) 83 | (emit '(3 1 5 5 2) op1 (bits imm 5) (regno rd) (bits imm 4 0) op2)) 84 | 85 | (defun cimm6* (rd imm op1 op2 op3) 86 | (emit '(3 1 2 3 5 2) op1 (bits imm 5) op2 (cregno rd) (bits imm 4 0) op3)) 87 | 88 | ; 89 | ; Alphabetical list of mnemonics 90 | ; 91 | 92 | (defun $add (rd rs1 rs2) 93 | (cond 94 | ((eq rd rs1) 95 | (emit '(3 1 5 5 2) 4 1 (regno rd) (regno rs2) 2)) 96 | (t (reg 0 rs2 rs1 0 rd #x33)))) 97 | 98 | (defun $addi (rd rs1 imm) 99 | (cond 100 | ((and (eq rd rs1) (immp imm 6)) 101 | (cimm6 rd imm 0 1)) 102 | ((and (= (regno rd) 2) (= (regno rs1) 2) (immp imm 10)) 103 | (emit '(3 1 5 1 1 2 1 2) 3 (bits imm 9) 2 (bits imm 4) (bits imm 6) (bits imm 8 7) (bits imm 5) 1)) 104 | (t (immed imm rs1 0 rd #x13)))) 105 | 106 | (defun $and (rd rs1 rs2) 107 | (cond 108 | ((and (eq rd rs1) (cregp rd) (cregp rs2)) 109 | (creg 4 0 3 rd 3 rs2)) 110 | (t (reg 0 rs2 rs1 7 rd #x33)))) 111 | 112 | (defun $andi (rd rs1 imm) 113 | (cond 114 | ((and (eq rd rs1) (cregp rd) (immp imm 5)) 115 | (cimm6* rd imm 4 2 1)) 116 | (t (immed imm rs1 7 rd #x13)))) 117 | 118 | (defun $auipc (rd imm) 119 | (cond 120 | ((zerop (logand imm #xfff)) 121 | (emit32 '(20 5 7) (bits imm 31 12) (regno rd) #x17)) 122 | (t (error* "auipc no good")))) 123 | 124 | (defun $beq (rs1 rs2 imm12) 125 | (branch imm12 rs2 rs1 0 #x63)) 126 | 127 | (defun $beqz (rs imm) 128 | (let ((off (offset imm))) 129 | (cond 130 | ((and (immp off 8) (cregp rs)) 131 | (emit '(3 1 2 3 2 2 1 2) 6 (bits off 8) (bits off 4 3) 132 | (cregno rs) (bits off 7 6) (bits off 2 1) (bits off 5) 1)) 133 | (t ($beq rs 'x0 imm))))) 134 | 135 | (defun $bge (rs1 rs2 imm12) 136 | (branch imm12 rs2 rs1 5 #x63)) 137 | 138 | (defun $bgeu (rs1 rs2 imm12) 139 | (branch imm12 rs2 rs1 7 #x63)) 140 | 141 | (defun $bgez (rs1 imm12) 142 | ($bge rs1 'x0 imm12)) 143 | 144 | (defun $bgt (rs1 rs2 imm12) 145 | ($blt rs2 rs1 imm12)) 146 | 147 | (defun $bgtu (rs1 rs2 imm12) 148 | ($bltu rs2 rs1 imm12)) 149 | 150 | (defun $bgtz (rs1 imm12) 151 | ($blt 'x0 rs1 imm12)) 152 | 153 | (defun $ble (rs1 rs2 imm12) 154 | ($bge rs2 rs1 imm12)) 155 | 156 | (defun $bleu (rs1 rs2 imm12) 157 | ($bgeu rs2 rs1 imm12)) 158 | 159 | (defun $blez (rs2 imm12) 160 | ($bge 'x0 rs2 imm12)) 161 | 162 | (defun $blt (rs1 rs2 imm12) 163 | (branch imm12 rs2 rs1 4 #x63)) 164 | 165 | (defun $bltu (rs1 rs2 imm12) 166 | (branch imm12 rs2 rs1 6 #x63)) 167 | 168 | (defun $bltz (rs1 imm12) 169 | ($blt rs1 'x0 imm12)) 170 | 171 | (defun $bne (rs1 rs2 imm12) 172 | (branch imm12 rs2 rs1 1 #x63)) 173 | 174 | (defun $bnez (rs imm) 175 | (let ((off (offset imm))) 176 | (cond 177 | ((and (immp off 8) (cregp rs)) 178 | (emit '(3 1 2 3 2 2 1 2) 7 (bits off 8) (bits off 4 3) 179 | (cregno rs) (bits off 7 6) (bits off 2 1) (bits off 5) 1)) 180 | (t ($bne rs 'x0 imm))))) 181 | 182 | (defun $div (rd rs1 rs2) 183 | (muldiv rs2 rs1 4 rd #x33)) 184 | 185 | (defun $divu (rd rs1 rs2) 186 | (muldiv rs2 rs1 5 rd #x33)) 187 | 188 | (defun $divw (rd rs1 rs2) 189 | (muldiv rs2 rs1 4 rd #x3b)) 190 | 191 | (defun $divuw (rd rs1 rs2) 192 | (muldiv rs2 rs1 5 rd #x3b)) 193 | 194 | (defun $fence () (emit32 '(16 16) #x0ff0 #x000f)) 195 | 196 | (defun $j (label) 197 | (let ((off (offset label))) 198 | (emit '(3 1 1 2 1 1 1 3 1 2) 5 (bits off 11) (bits off 4) (bits off 9 8) 199 | (bits off 10) (bits off 6) (bits off 7) (bits off 3 1) (bits off 5) 1))) 200 | 201 | ; C.JAL is RV32 only 202 | (defun $jal (rd &optional label) 203 | (when (null label) (setq label rd rd 'ra)) 204 | (let ((off (offset label))) 205 | (emit32 '(1 10 1 8 5 7) (bits off 20) (bits off 10 1) (bits off 11) (bits off 19 12) (regno rd) #x6f))) 206 | 207 | (defun $jalr (label lst) 208 | (let ((off (+ (offset label) 4))) 209 | (emit32 '(12 5 3 5 7) (bits off 11 0) (regno (car lst)) 0 (regno (car lst)) #x67))) 210 | 211 | (defun $jr (rs1) 212 | (emit '(3 1 5 5 2) 4 0 (regno rs1) 0 2)) 213 | 214 | ; In next four, imm can be omitted and defaults to 0 215 | (defun $lb (rd imm &optional lst) 216 | (unless lst (setq lst imm imm 0)) 217 | (immed imm (car lst) 0 rd 3)) 218 | 219 | (defun $lbu (rd imm &optional lst) 220 | (unless lst (setq lst imm imm 0)) 221 | (immed imm (car lst) 4 rd 3)) 222 | 223 | (defun $lh (rd imm &optional lst) 224 | (unless lst (setq lst imm imm 0)) 225 | (immed imm (car lst) 1 rd 3)) 226 | 227 | (defun $lhu (rd imm &optional lst) 228 | (unless lst (setq lst imm imm 0)) 229 | (immed imm (car lst) 5 rd 3)) 230 | 231 | ; li pseudoinstruction - will load 32-bit immediates 232 | (defun $li (rd imm) 233 | (cond 234 | ((immp imm 6) ; 16 bit 235 | (cimm6 rd imm 2 1)) 236 | ((immp imm 12) ; 32 bit 237 | ($addi rd 'x0 imm)) 238 | (t (let ((imm12 (logand imm #x00000fff)) ; 64 bit 239 | (imm20 (logand (ash imm -12) #xfffff))) 240 | (append 241 | ($lui rd (if (= (logand imm12 #x800) #x800) (+ imm20 #x1000) imm20)) 242 | ; $addi 243 | (emit32 '(12 5 3 5 7) imm12 (regno rd) 0 (regno rd) #x13)))))) 244 | 245 | (defun $lui (rd imm) 246 | (cond 247 | ((and (immp imm 6) (/= imm 0) (/= (regno rd) 0) (/= (regno rd) 2)) ; 16 bit 248 | (cimm6 rd imm 3 1)) 249 | (t 250 | (emit32 '(20 5 7) imm (regno rd) #x37)) 251 | (t (error* "lui no good")))) 252 | 253 | (defun $lw (rd imm lst) 254 | (cond 255 | ((listp lst) 256 | (let ((base (car lst))) 257 | (cond 258 | ; rs1 = sp 259 | ((and (= (regno base) 2)) 260 | (emit '(3 1 5 3 2 2) 2 (bits imm 5) (regno rd) (bits imm 4 2) (bits imm 7 6) 2)) 261 | ; rs1 = general 262 | ((and (cregp rd) (cregp base)) 263 | (emit '(3 3 3 1 1 3 2) 2 (bits imm 5 3) (cregno base) (bits imm 2) (bits imm 6) (cregno rd) 0)) 264 | (t (immed imm base 2 rd 3))))) 265 | (t (error* "Illegal 3rd arg")))) 266 | 267 | (defun $mul (rd rs1 rs2) 268 | (muldiv rs2 rs1 0 rd #x33)) 269 | 270 | (defun $mulh (rd rs1 rs2) 271 | (muldiv rs2 rs1 1 rd #x33)) 272 | 273 | (defun $mulhsu (rd rs1 rs2) 274 | (muldiv rs2 rs1 2 rd #x33)) 275 | 276 | (defun $mulhu (rd rs1 rs2) 277 | (muldiv rs2 rs1 3 rd #x33)) 278 | 279 | (defun $mv (rd rs1) 280 | (emit '(3 1 5 5 2) 4 0 (regno rd) (regno rs1) 2)) 281 | 282 | (defun $neg (rd rs2) 283 | ($sub rd 'x0 rs2)) 284 | 285 | (defun $nop () 286 | ($addi 'x0 'x0 0)) 287 | 288 | (defun $not (rd rs1) 289 | ($xori rd rs1 -1)) 290 | 291 | (defun $or (rd rs1 rs2) 292 | (cond 293 | ((and (eq rd rs1) (cregp rd) (cregp rs2)) 294 | (creg 4 0 3 rd 2 rs2)) 295 | (t (reg 0 rs2 rs1 6 rd #x33)))) 296 | 297 | (defun $ori (rd rs1 imm) 298 | (immed imm rs1 6 rd #x13)) 299 | 300 | (defun $rem (rd rs1 rs2) 301 | (muldiv rs2 rs1 6 rd #x33)) 302 | 303 | (defun $remu (rd rs1 rs2) 304 | (muldiv rs2 rs1 7 rd #x33)) 305 | 306 | (defun $ret () 307 | ($jr 'ra)) 308 | 309 | ; In $sb, $sh, and $sw, imm can be omitted and defaults to 0 310 | (defun $sb (src imm &optional lst) 311 | (unless lst (setq lst imm imm 0)) 312 | (store imm src (car lst) 0)) 313 | 314 | (defun $seqz (rd rs1) 315 | ($sltiu rd rs1 1)) 316 | 317 | (defun $sgtz (rd rs2) 318 | ($slt rd 'x0 rs2)) 319 | 320 | (defun $sh (src imm &optional lst) 321 | (unless lst (setq lst imm imm 0)) 322 | (store imm src (car lst) 1)) 323 | 324 | (defun $sll (rd rs1 rs2) 325 | (reg 0 rs2 rs1 1 rd #x33)) 326 | 327 | (defun $slli (rd rs1 imm) 328 | (cond 329 | ((and (eq rd rs1)) 330 | (cimm6 rd imm 0 2)) 331 | (t (emit32 '(6 6 5 3 5 7) 0 imm (regno rs1) 1 (regno rd) #x13)))) 332 | 333 | (defun $slt (rd rs1 rs2) 334 | (reg 0 rs2 rs1 2 rd #x33)) 335 | 336 | (defun $slti (rd rs1 imm) 337 | (immed imm rs1 2 rd #x13)) 338 | 339 | (defun $sltiu (rd rs1 imm) 340 | (immed imm rs1 3 rd #x13)) 341 | 342 | (defun $sltu (rd rs1 rs2) 343 | (reg 0 rs2 rs1 3 rd #x33)) 344 | 345 | (defun $sltz (rd rs1) 346 | ($slt rd rs1 'x0)) 347 | 348 | (defun $snez (rd rs2) 349 | ($sltu rd 'x0 rs2)) 350 | 351 | (defun $sra (rd rs1 rs2) 352 | (reg #x20 rs2 rs1 2 rd #x33)) 353 | 354 | (defun $srai (rd rs1 imm) 355 | (cond 356 | ((and (eq rd rs1) (cregp rd)) 357 | (cimm6* rd imm 4 1 1)) 358 | (t (emit32 '(6 6 5 3 5 7) #x10 imm (regno rs1) 5 (regno rd) #x13)))) 359 | 360 | (defun $srl (rd rs1 rs2) 361 | (reg 0 rs2 rs1 5 rd #x33)) 362 | 363 | (defun $srli (rd rs1 imm) 364 | (cond 365 | ((and (eq rd rs1) (cregp rd)) 366 | (cimm6* rd imm 4 0 1)) 367 | (t (emit32 '(6 6 5 3 5 7) 0 imm (regno rs1) 5 (regno rd) #x13)))) 368 | 369 | (defun $sub (rd rs1 rs2) 370 | (cond 371 | ((and (eq rd rs1) (cregp rd) (cregp rs2)) 372 | (creg 4 0 3 rd 0 rs2)) 373 | (t (reg #x20 rs2 rs1 0 rd #x33)))) 374 | 375 | (defun $sw (src imm &optional lst) 376 | (unless lst (setq lst imm imm 0)) 377 | (let ((base (car lst))) 378 | (cond 379 | ; base = sp 380 | ((and (= (regno base) 2)) 381 | (emit '(3 4 2 5 2) 6 (bits imm 5 2) (bits imm 7 6) (regno src) 2)) 382 | ; base = general 383 | ((and (cregp src) (cregp base)) 384 | (emit '(3 3 3 1 1 3 2) 6 (bits imm 5 3) (cregno base) (bits imm 2) (bits imm 6) (cregno src) 0)) 385 | (t (store imm src base 2))))) 386 | 387 | (defun $xor (rd rs1 rs2) 388 | (cond 389 | ((and (eq rd rs1) (cregp rd) (cregp rs2)) 390 | (creg 4 0 3 rd 1 rs2)) 391 | (t (reg 0 rs2 rs1 4 rd #x33)))) 392 | 393 | (defun $xori (rd rs1 imm) 394 | (immed imm rs1 4 rd #x13)) 395 | 396 | 397 | 398 | --------------------------------------------------------------------------------