summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSiddarth Suresh <155843085+SiddarthSuresh98@users.noreply.github.com>2025-04-12 13:06:51 -0400
committerGitHub <noreply@github.com>2025-04-12 13:06:51 -0400
commitfc20e7e7276b712f1e8db773b9215f900e877169 (patch)
treecaecdd1499d2e391cd5bd2dcde3aebfade002a09
parent5dbf0b63988b42c112ca0087cbbbb090566df5c1 (diff)
parent639098b1ea82be82bd18a4af415458fcbaf5e20b (diff)
Merge pull request #8 from bdunahu/bdunahu
Add write raw bytes stage
-rw-r--r--.gitignore1
-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.asm55
-rw-r--r--input/identity.asm59
-rw-r--r--input/rabbits.asm17
-rw-r--r--input/simple.asm5
-rw-r--r--rva.asd2
-rw-r--r--src/emit.lisp17
-rw-r--r--src/main.lisp44
-rw-r--r--src/package.lisp27
-rw-r--r--src/parse.lisp86
-rw-r--r--src/util.lisp15
-rw-r--r--t/parse.lisp68
14 files changed, 311 insertions, 104 deletions
diff --git a/.gitignore b/.gitignore
index 77b3e2b..ab65a90 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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)
diff --git a/rva.asd b/rva.asd
index 092fd44..b6b14d2 100644
--- a/rva.asd
+++ b/rva.asd
@@ -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