diff options
author | Siddarth Suresh <155843085+SiddarthSuresh98@users.noreply.github.com> | 2025-04-12 13:06:51 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-12 13:06:51 -0400 |
commit | fc20e7e7276b712f1e8db773b9215f900e877169 (patch) | |
tree | caecdd1499d2e391cd5bd2dcde3aebfade002a09 | |
parent | 5dbf0b63988b42c112ca0087cbbbb090566df5c1 (diff) | |
parent | 639098b1ea82be82bd18a4af415458fcbaf5e20b (diff) |
Merge pull request #8 from bdunahu/bdunahu
Add write raw bytes stage
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | input/adjacent-adder-manual.asm (renamed from input/add-loop.asm) | 7 | ||||
-rw-r--r-- | input/adjacent-adder.asm (renamed from input/add-loop-directive.asm) | 12 | ||||
-rw-r--r-- | input/dominative-functions.asm | 55 | ||||
-rw-r--r-- | input/identity.asm | 59 | ||||
-rw-r--r-- | input/rabbits.asm | 17 | ||||
-rw-r--r-- | input/simple.asm | 5 | ||||
-rw-r--r-- | rva.asd | 2 | ||||
-rw-r--r-- | src/emit.lisp | 17 | ||||
-rw-r--r-- | src/main.lisp | 44 | ||||
-rw-r--r-- | src/package.lisp | 27 | ||||
-rw-r--r-- | src/parse.lisp | 86 | ||||
-rw-r--r-- | src/util.lisp | 15 | ||||
-rw-r--r-- | t/parse.lisp | 68 |
14 files changed, 311 insertions, 104 deletions
@@ -4,3 +4,4 @@ manifest.scm # generated bin/ +output/ diff --git a/input/add-loop.asm b/input/adjacent-adder-manual.asm index f8d97a1..b575959 100644 --- a/input/add-loop.asm +++ b/input/adjacent-adder-manual.asm @@ -1,3 +1,10 @@ +;;;;;;;; +;;; adds adjacent elements of a 4-element vector together, +;;; storing the result in place. +;;; Does not make use of variables. + +.data + ;; empty .text addi $2 $0 0x200 addi $5 $0 0x1 diff --git a/input/add-loop-directive.asm b/input/adjacent-adder.asm index 5bccff3..35704d2 100644 --- a/input/add-loop-directive.asm +++ b/input/adjacent-adder.asm @@ -1,12 +1,16 @@ +;;;;;;;; +;;; adds adjacent elements of a 4-element vector together, +;;; storing the result in place. + .data arr 1 2 3 4 s 3 i 0 .text - load $5 s - load $10 arr - load $6 i + addi $5 $5 s + addi $10 $10 arr + addi $6 $6 i jrl CMP L: add $9 $10 $6 @@ -17,5 +21,5 @@ L: store $7 0($9) addi $6 $6 0x1 CMP: - cmp $6 $5 + cmp $5 $6 bgt L diff --git a/input/dominative-functions.asm b/input/dominative-functions.asm new file mode 100644 index 0000000..530717d --- /dev/null +++ b/input/dominative-functions.asm @@ -0,0 +1,55 @@ +;;;;;;;; +;;; makes use of a designated function to add two numbers together +;;; uses a stack-based paradigm with a base pointer to manage argument passing +;;; TODO this file is incomplete due to remaining ISA subroutine design issues + +.data + answer 0 + +.text +MAIN: + addi $5 $2 0x0 ; establish frame pointer + + addi $6 $0 -11 + + push $6 + ;; jal SUB23 + pop $6 + store $6 answer($0) +SUB23: + push $5 ; push old frame pointer + addi $5 $2 0x0 + subi $2 $2 0x4 + + addi $6 $0 -23 + store $6 -4($5) + + load $7 +4($5) ; access argument + load $6 -4($5) + + add $6 $6 $7 + push $6 + ;; jal ADD76 + pop $6 ; retrieve and pass along + store $6 +4($5) + + addi $2 $5 0x0 ; restore stack pointer + pop $5 ; restore frame pointer + ret +ADD76: + push $5 + addi $5 $2 0x0 + subi $2 $2 0x4 + + addi $6 $0 +76 + store $6 -4($5) + + load $7 +4($5) ; access argument + load $6 -4($5) + + add $6 $6 $7 + store $6 +4($5) + + addi $2 $5 0x0 + pop $5 + ret diff --git a/input/identity.asm b/input/identity.asm new file mode 100644 index 0000000..e6d9260 --- /dev/null +++ b/input/identity.asm @@ -0,0 +1,59 @@ +;;;;;;;; +;;; performs a matrix multiply on the 4x4 square matrices +;;; m1 and m2, +;;; the result of which is placed into +;;; r, +;;; in this case, the result is the identity +;;; does not use designated vector instructions + +.data + m1 01 00 -1 00 00 01 00 -1 00 00 01 00 00 00 00 01 + m2 01 00 01 00 00 01 00 01 00 00 01 00 00 00 00 01 + r 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +.text + addi $8 $0 0x4 ; dimensions + addi $9 $0 0x0 ; tracks the rows + addi $10 $0 0x0 ; tracks the columns + jrl ROWCOND + +ROW: + jrl COLCOND +COL: + addi $11 $0 0x0 ; tracks the element being added + addi $12 $0 0x0 ; the accumulated result to place into $9,$10 + + mul $7 $9 $8 ; setup the index into m1 + addi $5 $7 m1 + + addi $6 $0 m2 ; setup the index into m2 + add $6 $6 $10 + + jrl ELECOND +ELE: + add $5 $5 $11 ; increment m1 + + mul $13 $11 $8 ; increment m2 + add $6 $6 $13 + + load $13 0($5) ; retrieve and accumulate + load $14 0($6) + add $12 $14 $13 + + addi $11 $11 0x1 +ELECOND: + cmp $8 $11 + bgt ELE + addi $10 $10 0x1 +COLCOND: + cmp $8 $10 + bgt COL + + add $7 $7 $10 ; setup the index into r + addi $7 $7 r + + store $12 0($7) + + addi $9 $9 0x1 +ROWCOND: + cmp $8 $9 + bgt ROW diff --git a/input/rabbits.asm b/input/rabbits.asm new file mode 100644 index 0000000..c848116 --- /dev/null +++ b/input/rabbits.asm @@ -0,0 +1,17 @@ +;;;;;;;; +;;; multiplies numbers until an overflow occurs + +.data + rabbits 2 + rate 300 + +.text + load $5 rabbits($0) + load $6 rate($0) + +BREED: + mul $5 $5 $6 + store $5 rabbits($0) + bof DONE + jrl BREED +DONE: diff --git a/input/simple.asm b/input/simple.asm deleted file mode 100644 index 3e60ee8..0000000 --- a/input/simple.asm +++ /dev/null @@ -1,5 +0,0 @@ - addi $sp $0 512 - addi $5 $0 1 - store $5 0($sp) - addi $5 $0 2 - store $5 1($sp) @@ -4,7 +4,7 @@ (asdf:defsystem #:rva ;; :author "" ;; :license "" - :version "0.3" + :version "1.0" :homepage "https://github.com/bdunahu/rva" :description "Assembler for the RISC-V[ECTOR] mini-ISA." :source-control (:git "git@github.com:bdunahu/rva.git") diff --git a/src/emit.lisp b/src/emit.lisp index acc2772..213eb1a 100644 --- a/src/emit.lisp +++ b/src/emit.lisp @@ -2,7 +2,7 @@ (defun fits-in-X-bits (n) "Returns the number of bits required to represent N" - (ceiling (/ (log (ceiling n (log 2))) (log 2)))) + (ceiling (/ (log n) (log 2)))) (defmacro generate-type-map (ops) "Generates an alist where the key corresponds to an element in @@ -11,8 +11,7 @@ number of bits required to represent all concatenated with TYPE." `(let ((i 0) (opsize (fits-in-X-bits (length ,ops)))) - (mapcar (lambda (x) - (incf i) + (mapcar (lambda (x) (incf i) (cons x (util:format-as-binary i opsize))) ,ops))) @@ -32,7 +31,9 @@ concatenated with TYPE." (mapcar (lambda (x) (util:format-as-binary x 32)) lst)) (defun x (&rest lst) - lst) + (append lst + ;; add a halt to the end of the instructions list + (list (r "QUOT" (rr 0) (rr 0) (rr 0))))) (defun r (mnemonic s1 s2 d) (concatenate @@ -51,16 +52,16 @@ concatenated with TYPE." (util:format-as-binary val 5) (error (format nil "~a is not a valid register id!~%" val)))) -(defun imm (val) val) - (defun l (l s) (let ((d (util:get-label l))) (- d s))) (defun var (s) (let ((pos (util:get-variable s))) - (+ pos parse:line-number))) + (+ pos parse:line-number 1))) (defun emit (p) - (format t "~a~%" p) (eval p)) + +(defun ast->str (p) + (format nil "~a" p)) diff --git a/src/main.lisp b/src/main.lisp index f20b022..f1f3021 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -23,27 +23,51 @@ _/_/ _/_/ " :long-name "parse" :short-name #\p :required nil - :key :parse))) + :key :parse) + (clingon:make-option + :flag + :description "run the emitter, but stop before writing" + :long-name "emit" + :short-name #\e + :required nil + :key :emit))) + +(defun postprocess (out file) + "Given OUT, a list of words, writes the raw bytes to FILE." + (let ((file (util:generate-file-name file)) + (bytes (alexandria:flatten + (mapcar (lambda (x) + (util:word-to-bytes (parse-integer x :radix 2))) + out)))) + (with-open-file (stream file + :direction :output + :if-exists :supersede + :if-does-not-exist :create + :element-type '(unsigned-byte 8)) + (loop for byte in bytes do (write-byte byte stream))) + (format t "File written! Check ~a~%" file))) (defun driver (cmd) "Reads in a file and directs lexing, parsing, and binary emission." (print-splash) (let* ((args (clingon:command-arguments cmd)) (file (car args)) - (emit? (not (clingon:getopt cmd :parse)))) + (emit? (not (clingon:getopt cmd :parse))) + (write? (not (clingon:getopt cmd :emit)))) (cond - ;; complain about num arguments ((/= (length args) 1) (error "Wrong number of arguments.~%")) ((not (util:asm-extension? file)) (error "The file is not an asm source code file.~%")) (t (let ((str (uiop:read-file-string file))) (if str - (let ((ast (esrap:parse 'parse::str->ast (string-upcase str)))) - (when emit? - (format t "~a~%" (emit::emit ast)))) - (error "The file does not exist, or it could not be opened.~%")) - (format t "Nitimur in Vetitum~%")))))) - + (let ((ast (esrap:parse 'parse::str->ast (string-upcase str)))) + (if emit? + (let ((words (emit:emit ast))) + (if write? + (postprocess words file) + (format t "Emission successful, got: ~%~a~%" words))) + (format t "Parse successful, got:~%~a~%" (emit:ast->str ast)))) + (error "The file does not exist, or it could not be opened.~%"))))))) (defun cli/command () "Returns a clingon command." @@ -51,7 +75,7 @@ _/_/ _/_/ " :name "rva" :description "generates a binary compatible with the RISC V[ECTOR] simulator" :usage "[options] file" - :version(asdf:component-version + :version (asdf:component-version (asdf:find-system "rva" nil)) :options (cli/options) :handler #'driver)) diff --git a/src/package.lisp b/src/package.lisp index bbb45a3..d016501 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -6,22 +6,25 @@ (:use #:cl) (:export #:asm-extension? #:format-as-binary - #:insert-in-middle - #:iota - #:riffle - #:add-variable - #:add-label - #:get-variable - #:get-label - #:r-type - #:i-type - #:j-type)) + #:generate-file-name + #:word-to-bytes + #:insert-in-middle + #:iota + #:riffle + #:add-variable + #:add-label + #:get-variable + #:get-label + #:r-type + #:i-type + #:j-type)) (defpackage #:parse (:use #:cl) (:export #:str->ast - #:line-number)) + #:line-number)) (defpackage #:emit (:use #:cl) - (:export #:emit)) + (:export #:emit + #:ast->str)) diff --git a/src/parse.lisp b/src/parse.lisp index d971444..0ea6c0d 100644 --- a/src/parse.lisp +++ b/src/parse.lisp @@ -9,60 +9,62 @@ (+ (or #\space #\tab)) (:constant nil)) -(esrap:defrule nl (+ #\newline) +(esrap:defrule eol (and (esrap:? space) (esrap:? (and #\; (* (not #\newline)))) #\newline) (:constant nil)) -(esrap:defrule nl-inc (+ #\newline) - (:lambda (n) - (declare (ignore n)) - (incf line-number) - nil)) +(esrap:defrule newline (+ eol) + (:constant nil)) -(esrap:defrule alpha (+ (alphanumericp character)) +(esrap:defrule sign (or #\+ #\-)) + +(esrap:defrule alphanumeric (+ (alphanumericp character)) (:text t)) ;;; defines rules to parse an integer in various bases (defmacro define-number-rule ()) -(esrap:defrule binary (and #\0 #\B (+ (or "0" "1"))) +(esrap:defrule binary-number (and #\0 #\B (+ (or "0" "1"))) (:lambda (e) (parse-integer (esrap:text (cddr e)) :radix 2))) -(esrap:defrule octal (and #\0 #\O (+ (or (esrap:character-ranges (#\0 #\7))))) +(esrap:defrule octal-number (and #\0 #\O (+ (or (esrap:character-ranges (#\0 #\7))))) (:lambda (e) (parse-integer (esrap:text (cddr e)) :radix 8))) -(esrap:defrule decimal (+ (or (esrap:character-ranges (#\0 #\9)))) +(esrap:defrule decimal-number (+ (or (esrap:character-ranges (#\0 #\9)))) (:lambda (e) (parse-integer (esrap:text e) :radix 10))) -(esrap:defrule hex (and #\0 #\X (+ (or (esrap:character-ranges (#\0 #\9)) +(esrap:defrule hexadecimal-number (and #\0 #\X (+ (or (esrap:character-ranges (#\0 #\9)) "A" "B" "C" "D" "E" "F"))) (:lambda (e) (parse-integer (esrap:text (cddr e)) :radix 16))) -(esrap:defrule int (or binary octal hex decimal)) +(esrap:defrule integer (and (esrap:? sign) (or binary-number octal-number + hexadecimal-number decimal-number)) + (:destructure (s i) + (if (and s (string= s "-")) (- i) i))) ;;; defines rules to parse an operand -(esrap:defrule register (and #\$ int) +(esrap:defrule register (and #\$ integer) (:function cadr) (:lambda (e) (list 'emit::rr e))) -(esrap:defrule var alpha - (:lambda (e) (list (list 'emit::rr 0) (list 'emit::var e)))) +(esrap:defrule variable alphanumeric + (:lambda (e) (list 'emit::var e))) -(esrap:defrule dereference (and (esrap:? (or #\+ #\-)) int #\( register #\)) - (:destructure (s i1 w1 r w2) - (declare (ignore w1 w2)) - (list r (list 'emit::imm (if (and s (string= s "-")) (- i1) i1))))) +(esrap:defrule immediate (or integer variable) + (:lambda (e) e)) -(esrap:defrule immediate int - (:lambda (e) (list 'emit::imm e))) +(esrap:defrule dereference (and immediate #\( register #\)) + (:destructure (i1 w1 r w2) + (declare (ignore w1 w2)) + (list r i1))) ;;; defines rules to parse labels -(esrap:defrule label alpha +(esrap:defrule label alphanumeric (:lambda (e) (list 'emit::l e line-number))) -(esrap:defrule label-decl (and alpha #\:) +(esrap:defrule label-declaration (and alphanumeric #\:) (:function car) (:lambda (e) (util:add-label e line-number) @@ -82,11 +84,12 @@ (generate-mnemonic 'i-type-2-m '("STOREV" "STORE")) (generate-mnemonic 'j-type-1-m '("JMP" "JAL")) (generate-mnemonic 'j-type-2-m '("PUSH" "POP")) +(generate-mnemonic 'j-type-3-m '("RET" "NOP")) ;; we need to reverse to ensure rules like "ADDV" are matched before "ADD" (generate-mnemonic 'r-type-3-m (reverse util:r-type)) (generate-mnemonic 'i-type-3-m (reverse util:i-type)) -(generate-mnemonic 'j-type-3-m (reverse util:j-type)) +(generate-mnemonic 'j-type-4-m (reverse util:j-type)) ;; TODO this is pretty gross (defmacro defrule-instr (name type-id order &rest destructure-pattern) @@ -107,15 +110,15 @@ DESTRUCTURE-PATTERN is the list of non-terminals on the right side of the gramma (defrule-instr r-type-1 'emit::r (1 2 0) register register) (defrule-instr r-type-2 'emit::r (0 1 2) register register) (defrule-instr r-type-3 'emit::r (1 2 0) register register register) -(defrule-instr i-type-3 'emit::i (0 1 2) register register immediate) -(defrule-instr j-type-3 'emit::j (1 0) label) +(defrule-instr i-type-3 'emit::i (1 0 2) register register immediate) +(defrule-instr j-type-4 'emit::j (1 0) label) -(esrap:defrule i-type-1 (and i-type-1-m space register space (or dereference var)) +(esrap:defrule i-type-1 (and i-type-1-m space register space dereference) (:destructure (m w1 s w2 di) (declare (ignore w1 w2)) `(emit::i ,m ,s ,@di))) -(esrap:defrule i-type-2 (and i-type-2-m space register space (or dereference var)) +(esrap:defrule i-type-2 (and i-type-2-m space register space dereference) (:destructure (m w1 s w2 di) (declare (ignore w1 w2)) `(emit::i ,m ,@(util:insert-in-middle di s)))) @@ -128,47 +131,52 @@ DESTRUCTURE-PATTERN is the list of non-terminals on the right side of the gramma (esrap:defrule j-type-2 (and j-type-2-m space register) (:destructure (m w r) (declare (ignore w)) - `(emit::j ,m ,r (emit::imm 0)))) + `(emit::j ,m ,r 0))) + +(esrap:defrule j-type-3 j-type-3-m + (:lambda (m) + `(emit::j ,m (emit::rr 0) 0))) (esrap:defrule instr (or r-type-1 r-type-2 r-type-3 i-type-1 i-type-2 - i-type-3 j-type-1 j-type-2 j-type-3)) + i-type-3 j-type-1 j-type-2 j-type-3 j-type-4)) ;;; defines rules to parse the .text segment -(esrap:defrule instr-clean (and (esrap:? space) instr (esrap:? space) nl-inc) - (:function cadr)) +(esrap:defrule instr-clean (and (esrap:? space) instr newline) + (:function cadr) + (:lambda (i) (incf line-number) i)) -(esrap:defrule label-clean (and label-decl (esrap:? space) nl) +(esrap:defrule label-clean (and label-declaration newline) (:function car)) (esrap:defrule text-line (or instr-clean label-clean)) -(esrap:defrule text (and ".TEXT" (esrap:? space) nl (* text-line)) +(esrap:defrule text (and ".TEXT" (esrap:? space) newline (* text-line)) (:function cadddr) (:lambda (e) `(emit::x ,@(remove nil e)))) ;;; defines rules to parse the .data segment -(esrap:defrule data-word (and (esrap:? space) int) +(esrap:defrule data-word (and (esrap:? space) integer) (:function cadr) (:lambda (e) (incf var-offset) e)) -(esrap:defrule var-decl alpha +(esrap:defrule var-declaration alphanumeric (:lambda (e) (util:add-variable e var-offset) nil)) -(esrap:defrule data-line (and (esrap:? space) var-decl (+ data-word) (esrap:? space) nl) +(esrap:defrule data-line (and (esrap:? space) var-declaration (+ data-word) newline) (:function caddr)) -(esrap:defrule data (and ".DATA" (esrap:? space) nl (* data-line)) +(esrap:defrule data (and ".DATA" (esrap:? space) newline (* data-line)) (:function cadddr) (:lambda (e) `(emit::d ,@(apply #'append e)))) ;;; defines rules to parse a program -(esrap:defrule str->ast (and (* (or space nl)) data text) +(esrap:defrule str->ast (and (* (or space newline)) data text) (:function cdr) (:lambda (e) `(emit::p ,@e))) diff --git a/src/util.lisp b/src/util.lisp index f3035fe..e52d7aa 100644 --- a/src/util.lisp +++ b/src/util.lisp @@ -4,6 +4,9 @@ "Returns t if FILE is extended with .asm, nil otherwise." (string= (pathname-type file) "asm")) +(defun generate-file-name (file) + "Given a .asm file, generates an identically named .rv file." + (subseq file 0 (- (length file) 4))) (defun format-as-binary (num len) "Formats NUM as a binary number, and pads to LEN with zeros." @@ -12,7 +15,15 @@ (let ((max-val (1- (expt 2 len)))) (format nil "~V,'0b" len (logand num max-val)))) +(defun word-to-bytes (int) + "Given a 32-bit integer, outputs a list of 4 bytes." + (list (logand #xff (ash int -24)) + (logand #xff (ash int -16)) + (logand #xff (ash int -8)) + (logand #xff int))) + (defun insert-in-middle (list element) + "Inserts ELEMENT in the second slot of LIST." (append (list (car list)) (list element) (cdr list))) (defun iota (n) @@ -48,7 +59,7 @@ of the elements from both lists. Returns nil if the lists are not equal size." (alexandria:if-let ((value (gethash name variable-table))) value (progn (maphash #'(lambda (k v) (format t "~A => ~A~%" k v)) variable-table) - (error "~@<Variable ~S not declared.~@:>" name)))) + (error "~@<Variable ~S not declared.~@:>" name)))) (defun get-label (name) (alexandria:if-let ((value (gethash name label-table))) @@ -65,5 +76,5 @@ of the elements from both lists. Returns nil if the lists are not equal size." "I-type instructions.") (defvar j-type - '("JMP" "JRL" "JAL" "BEQ" "BGT" "BUF" "BOF" "PUSH" "POP") + '("JMP" "JRL" "JAL" "BEQ" "BGT" "BUF" "BOF" "PUSH" "POP" "RET" "NOP") "J-type instructions.") diff --git a/t/parse.lisp b/t/parse.lisp index 3c29dbc..2612f45 100644 --- a/t/parse.lisp +++ b/t/parse.lisp @@ -32,9 +32,9 @@ '(emit::p (emit::d) (emit::x - (emit::i "LOADV" (emit::rr 8) (emit::rr 9) (emit::imm 1)) - (emit::i "STORE" (emit::rr 3) (emit::rr 5) (emit::imm 3)) - (emit::i "ADDI" (emit::rr 5) (emit::rr 4) (emit::imm 2)))) + (emit::i "LOADV" (emit::rr 8) (emit::rr 9) 1) + (emit::i "STORE" (emit::rr 3) (emit::rr 5) 3) + (emit::i "ADDI" (emit::rr 4) (emit::rr 5) 2))) (esrap:parse 'parse:str->ast (format nil ".DATA~%.TEXT~%~tLOADV $8 1($9) ~tSTORE $5 3($3)~%~tADDI $5 $4 2~%"))))) @@ -43,18 +43,19 @@ '(emit::p (emit::d) (emit::x - (emit::j "JMP" (emit::rr 3) (emit::imm 3)) + (emit::j "JMP" (emit::rr 3) 3) (emit::j "JRL" (emit::rr 0) (emit::l "FOO" 8)) - (emit::j "PUSH" (emit::rr 5) (emit::imm 0)))) + (emit::j "RET" (emit::rr 0) 0) + (emit::j "PUSH" (emit::rr 5) 0))) (esrap:parse 'parse:str->ast (format nil ".DATA~%.TEXT~%~tJMP 3($3) -~tJRL FOO~%~tPUSH $5~%"))))) +~tJRL FOO~%~tRET~%~tPUSH $5~%"))))) (test esrap-instr-type-i-negative (is (equal '(emit::p (emit::d) (emit::x - (emit::i "LOADV" (emit::rr 8) (emit::rr 3) (emit::imm -3)))) + (emit::i "LOADV" (emit::rr 8) (emit::rr 3) -3))) (esrap:parse 'parse:str->ast (format nil ".DATA~%.TEXT~%~tLOADV $8 -3($3)~%"))))) (test esrap-instr-type-i-vars @@ -62,22 +63,34 @@ '(emit::p (emit::d) (emit::x - (emit::i "LOADV" (emit::rr 8) (emit::rr 0) (emit::var "vector")) - (emit::i "STORE" (emit::rr 0) (emit::rr 5) (emit::var "int")))) - (esrap:parse 'parse:str->ast (format nil ".DATA~%.TEXT~%~tLOADV $8 vector -~tSTORE $5 int~%"))))) + (emit::i "LOADV" (emit::rr 8) (emit::rr 4) 2) + (emit::i "STORE" (emit::rr 1) (emit::rr 5) 2))) + (esrap:parse 'parse:str->ast (format nil ".DATA~%.TEXT~%~tLOADV $8 2($4) +~tSTORE $5 2($1)~%"))))) (test esrap-instr-type-all-lazy-spaces (is (equal '(emit::p (emit::d) (emit::x - (emit::j "JMP" (emit::rr 3) (emit::imm 3)) - (emit::j "JRL" (emit::rr 0) (emit::l "FOO" 14)) - (emit::j "PUSH" (emit::rr 5) (emit::imm 0)))) + (emit::j "JMP" (emit::rr 3) 3) + (emit::j "JRL" (emit::rr 0) (emit::l "FOO" 15)) + (emit::j "PUSH" (emit::rr 5) 0))) (esrap:parse 'parse:str->ast (format nil ".DATA~%~%.TEXT~t~%JMP 3($3)~t JRL FOO~t~%PUSH $5~%"))))) +(test esrap-instr-type-comments + (is (equal + '(emit::p + (emit::d) + (emit::x + (emit::j "JMP" (emit::rr 3) 3) + (emit::j "JRL" (emit::rr 0) (emit::l "FOO" 18)) + (emit::j "PUSH" (emit::rr 5) 0))) + (esrap:parse 'parse:str->ast (format nil ".DATA~%.TEXT;; dot dot dot +~tJMP 3($3) ;; this does things +~tJRL FOO~%~tPUSH $5~%"))))) + (test esrap-data-singleton (is (equal '(emit::p @@ -113,20 +126,29 @@ JRL FOO~t~%PUSH $5~%"))))) (esrap:parse 'parse:str->ast (format nil "~%~t.DATA~t~%F 5 6 7 8~t~%G 4 H 3 5~%.TEXT~%"))))) +(test esrap-negative-ints + (is (equal + '(emit::p + (emit::d + -1) + (emit::x + (emit::i "LOADV" (emit::rr -8) (emit::rr -3) -3))) + (esrap:parse 'parse:str->ast (format nil ".DATA~%~tm -1~%.TEXT~%~tLOADV $-8 -3($-3)~%"))))) + (test esrap-data-full (is (equal '(emit::p (emit::d 1 2 3 4 3 0) (emit::x - (emit::i "LOAD" (emit::rr 5) (emit::rr 0) (emit::var "S")) - (emit::i "LOAD" (emit::rr 10) (emit::rr 0) (emit::var "ARR")) - (emit::i "LOAD" (emit::rr 6) (emit::rr 0) (emit::var "I")) - (emit::j "JRL" (emit::rr 0) (emit::l "CMP" 19)) + (emit::i "ADDI" (emit::rr 0) (emit::rr 5) (emit::var "S")) + (emit::i "ADDI" (emit::rr 0) (emit::rr 10) (emit::var "ARR")) + (emit::i "ADDI" (emit::rr 0) (emit::rr 6) (emit::var "I")) + (emit::j "JRL" (emit::rr 0) (emit::l "CMP" 24)) (emit::r "ADD" (emit::rr 10) (emit::rr 6) (emit::rr 9)) - (emit::i "ADDI" (emit::rr 6) (emit::rr 6) (emit::imm 1)) + (emit::i "ADDI" (emit::rr 6) (emit::rr 6) 1) (emit::r "CMP" (emit::rr 6) (emit::rr 5) (emit::rr 0)) - (emit::j "BGT" (emit::rr 0) (emit::l "L" 23)))) + (emit::j "BGT" (emit::rr 0) (emit::l "L" 28)))) (esrap:parse 'parse:str->ast (format nil " .DATA ARR 1 2 3 4 @@ -134,9 +156,9 @@ H 3 5~%.TEXT~%"))))) I 0 .TEXT - LOAD $5 S - LOAD $10 ARR - LOAD $6 I + ADDI $5 $0 S + ADDI $10 $0 ARR + ADDI $6 $0 I JRL CMP L: ADD $9 $10 $6 |