summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbd <bdunahu@operationnull.com>2025-04-10 20:28:34 -0400
committerbd <bdunahu@operationnull.com>2025-04-10 20:28:34 -0400
commitc1507d153161413e4958362d19ae9aa9abedee47 (patch)
tree23c6f4538c1b385cb1e6f97d197b8afa18a45619 /src
parentdf508744ec2975cec0ba05e8a4358c1c41265c4c (diff)
Add write raw bytes stage
Diffstat (limited to 'src')
-rw-r--r--src/emit.lisp9
-rw-r--r--src/main.lisp44
-rw-r--r--src/package.lisp27
-rw-r--r--src/util.lisp13
4 files changed, 66 insertions, 27 deletions
diff --git a/src/emit.lisp b/src/emit.lisp
index acc2772..48ebebe 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)))
@@ -62,5 +61,7 @@ concatenated with TYPE."
(+ pos parse:line-number)))
(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..517d395 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 successfull, 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/util.lisp b/src/util.lisp
index f3035fe..8d98680 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)))