URL
https://opencores.org/ocsvn/igor/igor/trunk
Subversion Repositories igor
Compare Revisions
- This comparison shows the changes necessary to convert path
/igor/trunk
- from Rev 2 to Rev 3
- ↔ Reverse comparison
Rev 2 → Rev 3
/processor/mc/README
0,0 → 1,5
The files contained in this directory is the multicycle prosessor. |
|
The toplevel instanciates the processor, the bus interface, some synchronizers for the control lines and the address decoding logic. |
|
The processor top-level is leval.vhd, and from there I guess it's possible do deduce where all the other files fit in. |
/microprogram_assembler/simplemc.lisp
0,0 → 1,30
(in-package #:mcasm) |
|
(defun write-microprogram (&key (output-format :simulator)) |
(with-assembly ("/tmp/microcode" :output-format output-format) |
(%set-type-imm $zero +type-int+) |
(%set-datum-imm $zero 0) |
(%set-type-imm $one +type-int+) |
(%set-datum-imm $one 1) |
(%set-type-imm $two +type-int+) |
(%set-datum-imm $two 2) |
|
(%set-type-imm $tmp1 +type-int+) |
(%set-type-imm $tmp2 +type-int+) |
|
;; do something (here, an %add) #x42 times: |
(%set-datum-imm $tmp1 #x42) |
(%set-datum-imm $tmp2 0) |
:loop1 |
(%add $tmp2 $one) |
(%decr $tmp1) |
(branchimm-false :loop1) |
|
;; do something else (here, a %sub) #x4 times: |
(%set-datum-imm $tmp1 #x4) |
:loop2 |
(%sub $tmp2 $one) |
(%decr $tmp1) |
(branchimm-false :loop2) |
|
(%halt))) |
/microprogram_assembler/bootprogram.lisp
0,0 → 1,1899
;;; |
(in-package #:sexptomem) |
|
(sexp-to-memory* |
(%nil |
%t |
%if |
%quote |
%lambda |
%progn |
%cons |
%car |
%cdr |
%eval |
%apply |
%type |
%make-array |
%array-size |
%array-get |
%array-set |
%make-symbol |
%symbol-to-string |
%char-to-int |
%int-to-char |
%get-char |
%put-char |
%num-devices |
%device-type |
%set-address |
%get-address |
%error |
%add |
%sub |
%mul |
%div |
%bitwise-and |
%bitwise-or |
%bitwise-not |
%bitwise-shift |
%current-environment |
%make-eval-state |
%eval-partial |
%define |
%undefine |
%eq? |
%num-eq? |
%char-eq? |
%less-than? |
%mod |
%set! |
%set-car! |
%set-cdr! |
%function-data |
%builtin-name |
%device-size |
%device-status |
|
xxxaa |
xxxab |
xxxac |
xxxad |
xxxae |
xxxaf |
xxxag |
xxxah |
xxxai |
xxxaj |
xxxak |
|
%symbol-table |
|
%phase-eval |
%phase-eval-args |
%phase-apply |
%phase-eval-if |
%phase-initial |
%phase-env-lookup |
%phase-env-lookup-local |
%phase-apply-function |
%phase-bind-args |
%phase-eval-progn |
%phase-eval-args-top |
%phase-eval-args-cdr |
%phase-eval-args-cons |
%phase-eval-symbol |
%phase-set! |
|
xxx3F |
|
%timeout |
%err-invalid-phase |
%err-unbound-symbol |
%err-invalid-param-list |
%err-too-few-args |
%err-too-many-args |
%err-invalid-state |
%err-invalid-arg-list |
%err-type-error |
%err-not-a-list |
%err-not-a-function |
%err-invalid-function |
%err-malformed-form |
%err-invalid-builtin |
%err-invalid-array-index |
%err-invalid-env |
%err-not-a-pair |
%err-division-by-zero |
%err-overflow |
) |
|
(%progn |
|
(%progn ; Define types |
(%define '+type-none+ #x0) |
(%define '+type-int+ #x1) |
(%define '+type-float+ #x3) |
(%define '+type-cons+ #x4) |
(%define '+type-snoc+ #x5) |
(%define '+type-ptr+ #x6) |
(%define '+type-array+ #x7) |
(%define '+type-nil+ #x8) |
(%define '+type-t+ #x9) |
(%define '+type-char+ #xA) |
(%define '+type-symbol+ #xB) |
(%define '+type-function+ #xC) |
(%define '+type-builtin+ #xD) |
) |
|
(%define 'current-input 2) |
(%define 'current-output 2) |
|
(%define '*print-base* 16) |
|
(%define '1+ (%lambda 1+ (x) |
(%add 1 x))) |
|
(%define '1- (%lambda 1- (x) (%sub x 1))) |
|
(%define 'map (%lambda map (fn list) |
(%if list |
(%cons (fn (%car list)) |
(map fn (%cdr list))) |
%nil))) |
|
(%define 'map-short (%lambda map-short (fn list) |
(%if list |
(%cons (fn (%car list)) |
(map fn (%cdr list))) |
%nil))) |
|
|
(%define 'list (%lambda list list list)) |
|
(%define 'char-upper (%lambda char-upper (char) |
(let ((n (%char-to-int char))) |
(%if (%less-than? (1- (%char-to-int #\a)) n) |
(%if (%less-than? n (1+ (%char-to-int #\z))) |
(%int-to-char (%sub n 32)) |
char) |
char)))) |
|
(%define 'make-string-stream (%lambda make-string-stream (str pos) |
(%lambda string-stream (cmd) |
(%if (%eq? cmd 'get-char) |
(%if (%less-than? (1- (%array-size str)) pos) |
'eos |
(%progn |
(%set! 'pos (1+ pos)) |
(%array-get str (1- pos)))) |
(%if (%eq? cmd 'peek-char) |
(%if (%less-than? (1- (%array-size str)) pos) |
'eos |
(%array-get str pos)) |
%nil))))) |
|
(%define 'make-device-input-stream (%lambda make-device-input-stream (device-number) |
(let ((chpeek %nil)) |
(%lambda device-input-stream (cmd) |
(%if (%eq? cmd 'get-char) |
(let ((thech (%if chpeek |
(let ((ch chpeek)) |
(%set! 'chpeek %nil) |
ch) |
(%get-char device-number)))) |
(%if (or2 (%num-eq? device-number 2) (%num-eq? device-number 0)) |
(%put-char current-output thech) |
%nil) |
thech) |
(%if (%eq? cmd 'peek-char) |
(%if chpeek |
chpeek |
(%set! 'chpeek (%get-char device-number))) |
%nil)))))) |
|
|
|
|
|
(%define |
'stream-wrapper-narwhal |
(%lambda stream-wrapper-narwhal (stream) |
(let ((chpeek %nil)) |
(%lambda input-stream (cmd) |
(%if (%eq? cmd 'get-char) |
(%if chpeek |
(let ((chkeep chpeek)) |
(%set! 'chpeek %nil) |
chkeep) |
(stream 'get-char)) |
(%if (%eq? cmd 'peek-char) |
(%if chpeek |
chpeek |
(%set! 'chpeek (stream 'get-char))) |
(%error 'I-<3-YOU-STREAM-WRAPPER))))))) |
|
;Code for reading the filesystem |
;Filetable first, each entry has [in use, filename, start-block, length] |
;Then comes one word per block, which is rather hilarious usage of space... |
;... "meta-info" about blocks, we'll call it. suuure. |
;Then comes the blocks. Each block is some size. A block has a pointer to |
;the next block that follows it. |
|
;The fileinfo (file identifier) passed around. |
(%define '+fileinfo-num-fields+ 6) |
(%define '+fileinfo-name+ 0) |
(%define '+fileinfo-tableindex+ 1) |
(%define '+fileinfo-block+ 2) |
(%define '+fileinfo-block-pos+ 3) |
(%define '+fileinfo-current-pos+ 4) |
(%define '+fileinfo-size+ 5) |
|
;The metadata structure. |
(%define '+metadata-pos+ 0) |
(%define '+metadata-size+ 16) |
(%define '+metadata-num-blocks+ 0) |
(%define '+metadata-free-blocks+ 1) |
(%define '+metadata-blocksize+ 2) |
(%define '+metadata-block-pos+ 3) |
(%define '+metadata-ft-num-rows+ 4) ;number of filetable rows |
(%define '+metadata-ft-free-rows+ 5) ;number of free rows |
(%define '+metadata-ft-rowsize+ 6) ;size of a filetable row |
(%define '+metadata-ft-pos+ 7) ;position of filetable (absolute address) |
|
;The filetable structure and various values |
(%define '+filetable-pos+ 16) |
(%define '+filetable-field-size+ 16) |
(%define '+filetable-num-rows+ 2) |
(%define '+filetable-size+ 32) |
(%define '+filetable-not-in-use-marker+ 0) |
(%define '+filetable-field-in-use+ 0) |
(%define '+filetable-field-filename+ 1) |
(%define '+filetable-field-start-block+ 14) |
(%define '+filetable-field-filesize+ 15) |
(%define '+filename-size+ 13) |
|
;The blocktale structure |
(%define '+blocktable-pos+ 48) |
(%define '+blocktable-size+ 8) |
|
;Various defines partaining to blocks |
(%define '+block-section-pos+ 56) |
(%define '+block-size+ 8) |
(%define '+num-blocks+ 8) |
|
|
;The device used for storage |
(%define '+storage-dev+ 1) |
|
|
;get the ith entry from the filetable, put it in an array |
(defun filetable-entry (index) |
(get-string |
(address-of-entry index) |
(metadata +metadata-ft-rowsize+))) |
|
(%define '+file-null-char+ 4) |
|
;should've had array-append... |
(defun count-non-null* (s pos num) |
(%if (%num-eq? |
(%array-size s) |
pos) |
num |
(%if (%num-eq? |
+file-null-char+ |
(%char-to-int (%array-get s pos))) |
(count-non-null* s (1+ pos) num) |
(count-non-null* s (1+ pos) (1+ num))))) |
(defun count-non-null (s) |
(count-non-null* s 0 0)) |
|
|
|
(defun strip-null (s) |
(array-resize s (count-non-null s))) |
|
|
|
|
(defun array-resize* (new arr size pos) |
(%if (%num-eq? |
size |
pos) |
new |
(%progn |
(%array-set new pos (%array-get arr pos)) |
(array-resize* new arr size (1+ pos))))) |
|
(defun array-resize (arr size) |
(let ((new (%make-array size %nil))) |
(array-resize* new arr size 0))) |
|
|
|
|
|
|
(defun str-eq?* (f1 f2 pos) |
(%if |
(%num-eq? (%array-size f1) pos) |
%t |
(%if (%char-eq? |
(%array-get f1 pos) |
(%array-get f2 pos)) |
(str-eq?* f1 f2 (1+ pos)) |
%nil))) |
|
(defun str-eq? (f1 f2) |
(%if (%num-eq? (%array-size f1) (%array-size f2)) |
(str-eq?* f1 f2 0) |
%nil)) |
|
;slice of a part of an array of chars [tested ok...] |
(%define |
'string-slice* |
(%lambda |
string-slice* (str slice stringpos pos len) |
(%if (%num-eq? pos len) |
slice |
(%progn |
(%array-set slice pos (%array-get str stringpos)) |
(string-slice* str slice (1+ stringpos) (1+ pos) len))))) |
|
(%define |
'string-slice |
(%lambda |
string-slice (str start len) |
(let ((slice (%make-array len %nil))) |
(string-slice* str slice start 0 len)))) |
|
|
;get the filename of an entry in the filetable |
(%define |
'filetable-entry-filename |
(%lambda filetable-entry-filename (filetable-entry) |
(string-slice |
filetable-entry |
+filetable-field-filename+ |
+filename-size+))) |
|
(%define |
'filetable-entry-block |
(%lambda filetable-entry-block (filetable-entry) |
(%char-to-int |
(%array-get filetable-entry +filetable-field-start-block+)))) |
|
(%define |
'filetable-entry-size |
(%lambda filetable-entry-size (filetable-entry) |
(%char-to-int |
(%array-get filetable-entry +filetable-field-filesize+)))) |
|
|
|
(defun filetable-entry-in-use (entry) |
(%if (%num-eq? |
(%char-to-int (%array-get entry +filetable-field-in-use+)) |
0) |
%nil |
%T)) |
;Get the starting block of the file at index in filetable |
(%define |
'filetable-start-block |
(%lambda filetable-start-block (index) |
(%progn |
(%set-address +storage-dev+ 0) |
(%char-to-int (%get-char (%add |
(%mul +filetable-field-size+ index) |
+filetable-field-start-block+)))))) |
|
;Get the size of the file at index in the filetable |
(%define |
'filetable-filesize |
(%lambda filetable-filesize |
(%set-address +storage-dev+ 0) |
(%char-to-int (%get-char (%add |
(%mul +filetable-field-size+ index) |
+filetable-field-filesize+))))) |
|
;put length chars from starting-position into an array of length size |
(defun get-string* (str len pos) |
(%if (%num-eq? pos len) |
str |
(%progn |
(%array-set str pos (%get-char +storage-dev+)) |
(get-string* str len (1+ pos))))) |
|
|
(defun get-string (start-pos length) |
(let ((string (%make-array length %nil))) |
(%set-address +storage-dev+ start-pos) |
(get-string* string length 0))) |
|
|
(defun put-string* (src len pos) |
(%if (%num-eq? pos len) |
src |
(%progn |
(%put-char +storage-dev+ (%array-get src pos)) |
(put-string* src len (1+ pos))))) |
|
(defun put-string (dst string) |
(%set-address +storage-dev+ dst) |
(put-string* string (%array-size string) 0)) |
|
;iterate file-table, find matching filename and return the fileinfo-entry, used by streams |
(defun open-file* (filename file-info index) |
(%if (%num-eq? |
(metadata +metadata-ft-num-rows+) |
index) |
(display "No such file or filename. IGOR is not happy, making him work this much...") |
|
(let ((entry (filetable-entry index))) ;get ith entry in filetable |
(%if (filetable-entry-in-use entry) |
(let ((entry-filename (strip-null (filetable-entry-filename entry)))) ;store filename |
(%if (str-eq? entry-filename filename) ;compare filenames, if equal: |
(%progn |
;create a file-info structure |
(%array-set file-info +fileinfo-name+ entry-filename) |
(%array-set file-info +fileinfo-block+ (filetable-entry-block entry)) |
(%array-set file-info +fileinfo-size+ (filetable-entry-size entry)) |
file-info) |
;filename mismatch, next entry please |
(open-file* filename file-info (1+ index)))) |
(open-file* filename file-info (1+ index)))))) ;entry not in use, next. |
|
(defun open-file (filename) |
(let ((file-info (%make-array +fileinfo-num-fields+ 0))) |
(open-file* filename file-info 0))) |
|
|
|
|
(defun filetable-get-offset (filename index) |
(let ((current-filename (get-string |
(%add |
+filetable-field-fieldname+ (%mul |
index |
+filetable-field-size+)) |
+filename-size+))))) |
|
|
|
(defun file-address (file-info) |
(%add |
(address-of-block (%array-get file-info +fileinfo-block+)) |
(%array-get file-info +fileinfo-block-pos+))) |
|
(%define |
'make-fisk-stream |
(%lambda make-fisk-stream (open-fisk-dings) |
(stream-wrapper-narwhal |
(%lambda fisk-stream (cmd) |
(%if (%eq? cmd 'get-char) |
(file-get-char open-fisk-dings)))))) |
|
|
(%define |
'file-eof? |
(%lambda file-eof? (file-info) |
(%if (%eq? |
(%array-get file-info +fileinfo-current-pos+) |
(%array-get file-info +fileinfo-size+)) |
%t |
%nil))) |
(%define |
'file-get-char |
(%lambda file-get-char (file-info) |
(%if (file-eof? file-info) |
(%error 'EOF) |
(let ((ch (file-read-char file-info))) |
|
(file-increment-pos file-info) |
ch)))) |
|
|
(%define |
'file-read-char |
(%lambda file-read-char (file-info) |
(%progn |
(%set-address +storage-dev+ (file-address file-info)) |
(%get-char +storage-dev+)))) |
|
(%define |
'file-increment-pos |
(%lambda file-increment-pos (file-info) |
(%if (file-eof? file-info) ;if we're at the end of the file... |
%nil ;...don't increment |
(%progn |
(%array-set ;else, increment the current-position by 1 |
file-info |
+fileinfo-current-pos+ |
(1+ (%array-get file-info +fileinfo-current-pos+))) |
(%if (end-of-block file-info) ;if end of block... |
(%progn |
(%array-set |
file-info |
+fileinfo-block+ |
(file-next-block |
(%array-get file-info +fileinfo-block+))) ;find the next block and set |
(%array-set |
file-info |
+fileinfo-block-pos+ |
0)) ;and set the current inter-block-position to 0 |
(%array-set ;else, we're not at the end of the block. |
file-info |
+fileinfo-block-pos+ |
(1+ (%array-get file-info +fileinfo-block-pos+)))))))) ; simply update current block |
|
|
(%define |
'end-of-block |
(%lambda end-of-block (file-info) |
(%if (%num-eq? |
(%array-get file-info +fileinfo-block-pos+) |
(%sub +block-size+ 2)) |
%t |
%nil);not end of block |
)) |
|
|
(%define |
'file-next-block |
(%lambda file-next-block (current-block) |
(%progn |
(%set-address |
+storage-dev+ |
(%add |
(address-of-block current-block) |
(1- +block-size+))) |
(%char-to-int (%get-char +storage-dev+))))) |
|
(defun address-of-block (bloc) |
(%add |
+block-section-pos+ |
(%mul +block-size+ bloc))) |
|
|
(defun list-files* (index) |
(%if (%num-eq? |
index |
+filetable-num-rows+) |
%T |
(let ((entry (filetable-entry index))) |
(%if (filetable-entry-in-use entry) |
(%progn |
(display (strip-null (filetable-entry-filename entry))) |
(newline) |
(list-files* (1+ index))) |
(list-files* (1+ index)))))) |
|
(defun list-files () |
(list-files* 0)) |
|
|
(defun metadata (num) |
(%set-address +storage-dev+ (%add +metadata-pos+ num)) |
(%char-to-int (%get-char +storage-dev+))) |
|
;Code for writing to the filesystem is below. |
(defun create-file (filename) |
(let ((entry (filetable-free-entry))) |
(let ((addr (address-of-entry entry))) |
(put-char-at-addr addr (%int-to-char 1)) |
(put-string (%add |
addr |
+filetable-field-filename+) |
filename) |
(put-char-at-addr (%add |
addr |
+filetable-field-start-block+) |
(%int-to-char (find-free-block))) |
(put-char-at-addr (%add |
addr |
+filetable-field-filesize+) |
(%int-to-char 0)))) |
(open-file filename)) |
|
(defun put-char-at-addr (addr char) |
(%set-address +storage-dev+ addr) |
(%put-char +storage-dev+ char)) |
|
|
(defun address-of-entry (entry) |
(%add |
(%mul |
entry |
(metadata +metadata-ft-rowsize+)) |
(metadata +metadata-ft-pos+))) |
|
;DOES: Attempts to find a free entry in the file table. |
;THROWS: 'filetable-full |
(defun filetable-free-entry () |
(%if (%num-eq? (metadata +metadata-ft-free-rows+) 0) |
(%error 'filetable-meta-full) |
(filetable-free-entry* 0))) |
(defun filetable-free-entry* (index) |
(%if |
(%num-eq? |
index |
(metadata +metadata-ft-num-rows+)) |
(%error 'filetable-full) |
(%if ;if this entry is not in use |
(%num-eq? |
(%char-to-int (%array-get (filetable-entry index) +filetable-field-in-use+)) |
+filetable-not-in-use-marker+);...eh |
index ;return the index. |
(filetable-free-entry* (1+ index))))) |
|
|
|
(defun find-free-block* (index) |
(%if |
(%num-eq? |
(metadata +metadata-num-blocks+) |
index) |
%nil |
(%progn |
(%set-address +storage-dev+ (%add +blocktable-pos+ index)) |
(%if |
(%num-eq? |
(%char-to-int (%get-char +storage-dev+)) |
0) |
index |
(find-free-block* (1+ index)))))) |
|
(defun find-free-block () |
(%if |
(%num-eq? |
(metadata +metadata-free-blocks+) |
0) |
(%error 'no-free-blocks) |
(find-free-block* 0))) |
|
|
|
(defun set-block-unfree '() |
(display "cannot unfree what has been unseen")) |
(defun set-block-free '() |
(display "setting a block free!")) |
|
|
|
(defun write-filetable-entry (fileinfo) |
(let ((entry (filetable-find-free-entry))))) |
|
|
(%define 'string=-rec (%lambda string=-rec (i s1 s2) |
(%if (%num-eq? i (%array-size s1)) |
%t |
(%if (%char-eq? (%array-get s1 i) |
(%array-get s2 i)) |
(string=-rec (1+ i) s1 s2) |
%nil)))) |
|
(%define 'string=? (%lambda string=? (s1 s2) |
(%if (%num-eq? (%array-size s1) (%array-size s2)) |
(string=-rec 0 s1 s2) |
%nil))) |
|
(%define 'symbol-exists?-rec (%lambda symbol-exists?-rec (symbol-table str) |
(%if symbol-table |
(%if (string=? (%symbol-to-string (%car symbol-table)) str) |
(%car symbol-table) |
(symbol-exists?-rec (%cdr symbol-table) str)) |
%nil))) |
|
;; Check if a symbol is interned |
(%define 'symbol-exists? (%lambda symbol-exists? (str) |
(symbol-exists?-rec %symbol-table str))) |
|
;; Intern a symbol, if it is already intered, just return the symbol |
(%define 'intern (%lambda intern (str) |
(let ((sym (symbol-exists? str))) |
(%if sym sym |
(let ((sym (%make-symbol str))) |
(%set! '%symbol-table (%cons sym %symbol-table)) |
sym))))) |
|
(%define |
'intern-char-hash |
(%lambda |
intern-char-hash (ch) |
(%bitwise-and (%char-to-int ch) 7))) |
|
(%define |
'intern-make-node |
(%lambda |
intern-make-node () |
(%cons nil (%make-array 8 nil)))) |
|
(%define |
'intern-get-node |
(%lambda |
intern-get-node (tab hash) |
(%array-get |
(%if (%array-get tab hash) |
tab |
(%array-set tab hash (intern-make-node))) |
hash))) |
|
(%define |
'intern-get-sym-in-list |
(%lambda |
intern-get-sym-in-list (str list) |
(%if list |
(%if (string=? (%symbol-to-string (%car list)) str) |
(%car list) |
(intern-get-sym-in-list str (%cdr list))) |
nil))) |
|
(%define |
'intern-rec |
(%lambda |
intern-rec (str i tree existing-symbol) |
(%if (%num-eq? i (%array-size str)) |
(let ((sym (intern-get-sym-in-list str (%car tree)))) |
(%if sym sym |
(%car (%set-car! tree (%cons (%if existing-symbol |
existing-symbol |
(%make-symbol str)) |
(%car tree)))))) |
(intern-rec |
str |
(%add i 1) |
(intern-get-node (%cdr tree) (intern-char-hash (%array-get str i))) |
existing-symbol)))) |
|
(%define 'symbol-tree (intern-make-node)) |
|
(%define |
'intern-foo |
(%lambda |
intern (str) |
(intern-rec str 0 symbol-tree nil))) |
|
(%define |
'intern-symbols |
(%lambda |
intern-symbols (list) |
(%if list |
(%progn (intern-rec (%symbol-to-string (%car list)) 0 symbol-tree (%car list)) |
(intern-symbols (%cdr list))) |
nil))) |
|
|
;; See if an element member of a list |
(%define 'member (%lambda member (elem list test) |
(%if list |
(%if (test (%car list) elem) |
%t |
(member elem (%cdr list) test)) |
%nil))) |
|
;; Or functions |
;; XXX: Special form |
(%define 'or2 (%lambda or2 (a b) ; XXX: Special forms |
(%if a a b))) |
(%define 'or3 (%lambda or3 (a b c) |
(or2 a (or2 b c)))) |
|
(%define 'digits (%%list #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)) |
(%define 'digits-hex (%cons #\a (%cons #\b (%cons #\c (%cons #\d (%cons #\e (%cons #\f |
(%cons #\A (%cons #\B (%cons #\C (%cons #\D (%cons #\E (%cons #\F digits))))))))))))) |
|
|
;; Special characters |
;; These will never be in a symbol |
(%define 'special (%%list #\( #\) #\Space)) |
|
;; Convert a digit character to a digit |
(%define 'char-to-digit (%lambda char-to-digit (ch) |
(%sub (%char-to-int ch) 48))) |
|
;; Is the character something we want in our symbol? |
(%define 'isalpha? (%lambda isalpha? (ch) |
(%if (member ch special %char-eq?) |
%nil |
(%if (member ch digits %char-eq?) |
%nil |
%t)))) |
|
;; Convert a |
(%define 'parse-integer* (%lambda parse-integer* (list num radix) |
(%if list |
|
|
(parse-integer* (%cdr list) (%add (%mul num radix) (char->digit (%car list))) radix) |
num))) |
(%define 'parse-integer (%lambda parse-integer (list) |
(parse-integer* list 0 10))) |
|
;; Is the character a whitespace |
(%define 'whitespace? (%lambda whitespace? (ch) |
(or3 (%char-eq? ch #\Space) |
(%char-eq? ch #\Return) |
(%char-eq? ch #\Newline)))) |
|
;; Length of a list |
(%define 'length (%lambda length (list) |
(%if list |
(1+ (length (%cdr list))) |
0))) |
|
;; Convert a list to an array |
(%define 'list->string* (%lambda list->string* (list str pos) |
(%if list |
(%progn |
(%array-set str pos (%car list)) |
(list->string* (%cdr list) str (1+ pos))) |
str))) |
(%define 'list->string (%lambda list->string (list) |
(let ((str (%make-array (length list) #\Space))) |
(list->string* list str 0)))) |
|
;; Skip whitespace characters from an input stream |
(%define 'skip-whitespace (%lambda skip-whitespace (s) |
(let ((ch (s (%quote peek-char)))) |
(%if (%eq? ch 'eos) |
ch |
(%if (whitespace? ch) |
(%progn |
(s 'get-char) |
(skip-whitespace s)) |
ch))))) |
|
;; Tokenize a symbol |
(%define 'tokenize-sym (%lambda tokenize-sym (s ch) |
(%progn |
(let ((type |
(%if (member ch digits %char-eq?) |
'integer |
'symbol))) |
(%define 'tknz |
(%lambda tknz (s) |
(let ((ch (s 'peek-char))) |
(%if (%eq? ch 'eos) |
%nil |
(%if (whitespace? ch) |
%nil |
(%if (isalpha? ch) |
(%progn |
(%set! 'type 'symbol) |
(%cons (s 'get-char) |
(tknz s))) |
(%if (member ch digits %char-eq?) |
(%cons (s 'get-char) |
(tknz s)) |
%nil))))))) |
((%lambda snoc (a b) |
(%cons b a)) |
(let ((lst (%cons ch (tknz s)))) |
((%if (%eq? type 'integer) |
parse-integer |
list->string) |
lst)) |
type))))) |
|
;; Tokenize a string |
(%define 'tokenize-string-rec (%lambda tokenize-string-rec (s) |
(let ((ch (s 'get-char))) |
(%if (%char-eq? ch #\") ; XXX: Check for end of stream |
%nil |
|
(%cons ch (tokenize-string-rec s)))))) |
|
(%define 'tokenize-string (%lambda tokenize-string (s) |
(let ((sl (tokenize-string-rec s))) |
(%cons 'string (list->string sl))))) |
|
;; Tokenize a hash object |
(%define 'tokenize-hash-x (%lambda tokenize-hash-x (s) |
(%progn |
(%define 'rec (%lambda tokenize-hash-x-rec () |
(let ((ch (s 'peek-char))) |
(%if (member ch digits-hex %char-eq?) |
(%cons (s 'get-char) (rec)) |
%nil)))) |
(parse-integer* (rec) 0 16)))) |
|
|
(%define 'tokenize-hash (%lambda tokenize-hash (s) |
(let ((ch (s 'get-char))) |
(%if (%char-eq? ch #\\) |
(%cons 'character (s 'get-char)) |
(%if (%char-eq? ch #\x) |
(%cons 'integer (tokenize-hash-x s)) |
(%cons 'error "Unknown hash character")))))) |
|
;; Tokenize a stream |
(%define 'tokenize (%lambda tokenize (s) |
(%progn |
(skip-whitespace s) |
(let ((ch (s 'get-char))) |
(%if (%eq? ch 'eos) |
(%cons 'eos %nil) |
(%if (%char-eq? ch #\() |
(%cons 'lparen %nil) |
(%if (%char-eq? ch #\)) |
(%cons 'rparen %nil) |
(%if (%char-eq? ch #\') |
(%cons 'quote %nil) |
(%if (%char-eq? ch #\") |
(tokenize-string s) |
(%if (%char-eq? ch #\#) |
(tokenize-hash s) |
(tokenize-sym s ch))))))))))) |
|
;; Make a token stream |
(%define 'make-token-stream (%lambda make-token-stream (s) |
(let ((tok %nil)) |
(%lambda token-stream (cmd) |
(%if (%eq? cmd 'next) |
(%if tok |
(let ((tok2 tok)) |
(%set! 'tok %nil) |
tok2) |
(tokenize s)) |
(%if (%eq? cmd 'peek) |
(%if tok |
tok |
(%progn |
(%set! 'tok (tokenize s)) |
tok)) |
%nil)))))) |
|
;; Parse a list from a token stream |
(%define 'parse-list (%lambda parse-list (s) |
(let ((tok (s 'peek))) |
(let ((token (%car tok))) |
(%if (%eq? token 'eos) |
(%error "Parse error, missing rparen at end of stream") |
(%if (%eq? token 'rparen) |
(%progn |
(s 'next) |
%nil) |
(%cons (parse s) (parse-list s)))))))) |
|
;; Check if the string is a T type |
(%define 'is-t? (%lambda is-t? (str) |
(%if (%num-eq? (%array-size str) 1) |
(%if (%char-eq? (%array-get str 0) #\T) |
%t |
%nil) |
%nil))) |
|
;; Check if the string s a NIL type |
(%define 'is-nil? (%lambda is-nil? (str) |
(string=? str "NIL"))) |
|
;; Uppercase a string |
(%define 'string-upper-rec (%lambda string-upper-rec (orig str i) |
(%if (%num-eq? i (%array-size orig)) |
str |
(%progn |
(%array-set str i (char-upper (%array-get orig i))) |
(string-upper-rec orig str (1+ i)))))) |
|
(%define 'string-upper (%lambda string-upper (str) |
(let ((str2 (%make-array (%array-size str) #\a))) |
(string-upper-rec str str2 0)))) |
|
;; Make a symbol of a string |
;; T and NIL are "special" symbols |
(%define 'symbolify (%lambda symbolify (sym) |
(%if (%num-eq? (%array-size sym) 1) |
(%if (is-t? sym) |
%t |
(%if (%char-eq? #\. (%array-get sym 0)) |
'%. |
(intern sym))) |
(%if (is-nil? sym) |
%nil |
(intern sym))))) |
;; Parse a token stream |
(%define 'parse (%lambda parse (s) |
(let ((tok (s 'next))) |
(%if (%eq? (%car tok) 'lparen) |
(parse-list s) |
(%if (or3 (%eq? (%car tok) 'integer) (%eq? (%car tok) 'string) (%eq? (%car tok) 'character)) |
(%cdr tok) |
(%if (%eq? (%car tok) 'symbol) |
(symbolify (string-upper (%cdr tok))) |
(%if (%eq? (%car tok) 'quote) |
(%cons '%quote (%cons (parse s) %nil))))))))) |
|
;; Parse a string into cons cells |
(%define 'read-from-string (%lambda read-from-string (str) |
(let ((s (make-token-stream (make-string-stream str 0)))) |
(parse s)))) |
|
;; Write each character in the list to current output |
(%define 'print-list* (%lambda print-list* (list) |
(%if list |
(%progn |
(%put-char current-output (%car list)) |
(print-list* (%cdr list))) |
%nil))) |
|
;; Print a character |
(%define 'print-char (%lambda print-char (ch) |
(print-list* (%%list #\# #\\ ch)))) |
|
|
;; Check if an array is a string |
(%define 'is-string?-rec (%lambda is-string?-rec (arr i) |
(%if (%num-eq? i (%array-size arr)) |
%t |
(%if (%num-eq? (%type (%array-get arr i)) +type-char+) |
(is-string?-rec arr (1+ i)) |
%nil)))) |
|
(%define 'is-string? (%lambda is-string? (arr) |
(is-string?-rec arr 0))) |
|
;; Print a string |
(%define 'print-string-rec (%lambda print-string-rec (arr i) |
(%if (%num-eq? (%array-size arr) i) |
%nil |
(%progn |
(%put-char current-output (%array-get arr i)) |
(print-string-rec arr (1+ i)))))) |
|
(%define 'print-string (%lambda print-string (arr) |
(%progn |
(%put-char current-output #\") |
(print-string-rec arr 0) |
(%put-char current-output #\")))) |
|
;; Print an array |
(%define 'print-array-rec (%lambda print-array-rec (arr i) |
(%if (%num-eq? (%array-size arr) i) |
%nil |
(%progn |
(print (%array-get arr i)) |
(%put-char current-output #\Space) |
(print-array-rec arr (1+ i)))))) |
|
|
(%define 'print-array (%lambda print-array (arr) |
; String is a special type of array |
(%if (is-string? arr) |
(print-string arr) |
(%progn |
(print-list* (%%list #\# #\[)) |
(%put-char current-output #\Space) |
(print-array-rec arr 0) |
(%put-char current-output #\]))))) |
|
;; See if a cons cell really is a list |
(%define 'is-list? (%lambda is-list? (cons) |
(%if (%num-eq? (%type cons) +type-cons+) |
(is-list? (%cdr cons)) |
(%if (%num-eq? (%type cons) +type-nil+) |
%t |
%nil)))) |
;; Print a list |
(%define 'print-list-rec (%lambda print-list-rec (list) |
(%progn |
(print (%car list)) |
(%if (%num-eq? (%type (%cdr list)) +type-nil+) |
%nil |
(%progn |
(%put-char current-output #\Space) |
(print-list-rec (%cdr list))))))) |
|
(%define 'print-list (%lambda print-list (list) |
(%progn |
(%put-char current-output #\() |
(print-list-rec list) |
(%put-char current-output #\))))) |
|
;; Print a cons cell |
(%define 'print-cons (%lambda print-cons (cons) |
(%if (is-list? cons) |
(print-list cons) |
(%progn |
(%put-char current-output #\() |
(print (%car cons)) |
(%put-char current-output #\Space) |
(%put-char current-output #\.) |
(%put-char current-output #\Space) |
(print (%cdr cons)) |
(%put-char current-output #\)))))) |
|
;; Print an integer |
(%define 'print-integer-rec (%lambda print-integer-rec (int list) |
(%if (%num-eq? int 0) |
list |
(print-integer-rec (%if (%num-eq? *print-base* 10) |
(%div int 10) |
(%bitwise-shift int -4)) |
(%cons |
(%if (%num-eq? *print-base* 10) |
(%mod int 10) |
(%bitwise-and int #xF)) |
list))))) |
|
; XXX: Make it an array for direct lookup? |
;; Integer to digit character mapping |
(%define 'digit->char-map (%%list (%cons 0 #\0) |
(%cons 1 #\1) |
(%cons 2 #\2) |
(%cons 3 #\3) |
(%cons 4 #\4) |
(%cons 5 #\5) |
(%cons 6 #\6) |
(%cons 7 #\7) |
(%cons 8 #\8) |
(%cons 9 #\9) |
(%cons 10 #\A) |
(%cons 11 #\B) |
(%cons 12 #\C) |
(%cons 13 #\D) |
(%cons 14 #\E) |
(%cons 15 #\F) |
(%cons 10 #\a) |
(%cons 11 #\b) |
(%cons 12 #\c) |
(%cons 13 #\d) |
(%cons 14 #\e) |
(%cons 15 #\f))) |
;; Convert an integer (0 >= n < 10) |
(%define 'digit->char-rec (%lambda digit->char-rec (int list) |
(%if list |
(%if (%num-eq? (%car (%car list)) int) |
(%cdr (%car list)) |
(digit->char-rec int (%cdr list))) |
#\?))) |
(%define 'digit->char (%lambda digit->char (int) |
(digit->char-rec int digit->char-map))) |
|
;; Convert a character to a digit [0, F] |
(%define 'char->digit-rec (%lambda digit->char-rec (ch list) |
(%if list |
(%if (%char-eq? (%cdr (%car list)) ch) |
(%car (%car list)) |
(char->digit-rec ch (%cdr list))) |
0))) |
(%define 'char->digit (%lambda digit->char (ch) |
(char->digit-rec ch digit->char-map))) |
|
(%define 'print-integer (%lambda print-integer (int) |
(%if (%num-eq? int 0) |
(print-list* (%if (%num-eq? *print-base* 10) |
(%%list #\0) |
(%%list #\# #\x #\0))) |
(print-list* |
(let ((start-int (%if (%num-eq? *print-base* 10) |
%nil |
(%%list #\# #\x)))) |
(print-list* start-int) |
(%if (%less-than? int 0) |
(%cons #\- (map digit->char (print-integer-rec (%mul (%sub 0 1) int) %nil))) |
(map digit->char (print-integer-rec int %nil)))))))) |
|
|
;; Print a function |
(%define |
'print-function |
(%lambda |
print-function (f) |
(%progn |
(%put-char current-output #\#) |
(%put-char current-output #\() |
(print (function-name f)) |
(%put-char current-output #\))))) |
|
;; Print a builtin function |
(%define |
'print-builtin |
(%lambda |
print-builtin (b) |
(%progn |
(%put-char current-output #\#) |
(%put-char current-output #\() |
(print (%builtin-name b)) |
(%put-char current-output #\))))) |
|
|
;; Print an object |
(%define |
'print |
(%lambda |
print (expr) |
(%if (%num-eq? (%type expr) +type-t+) |
(%put-char current-output #\T) |
(%if (%num-eq? (%type expr) +type-nil+) |
(print-list* (%%list #\N #\I #\L)) |
(%if (%num-eq? (%type expr) +type-char+) |
(print-char expr) |
(%if (%num-eq? (%type expr) +type-array+) |
(print-array expr) |
(%if (%num-eq? (%type expr) +type-cons+) |
(print-cons expr) |
(%if (%num-eq? (%type expr) +type-symbol+) |
(print-string-rec (%symbol-to-string expr) 0) |
(%if (%num-eq? (%type expr) +type-int+) |
(print-integer expr) |
(%if (%num-eq? (%type expr) +type-function+) |
(print-function expr) |
(%if (%num-eq? (%type expr) +type-builtin+) |
(print-builtin expr) |
(%put-char current-output #\#)))))))))))) |
|
;; Write newline |
(%define 'newline (%lambda newline () |
(%progn |
(%put-char current-output #\Newline) |
(%put-char current-output #\Return) |
nil))) |
|
|
;; Parse the input from a device |
(%define 'read-from-device (%lambda read-from-device (input-device) |
(let ((s (make-token-stream (make-device-input-stream input-device)))) |
(parse s)))) |
|
;; Read line |
(%define 'read-line |
(%lambda read-line (input-device) |
(let ((s (make-device-input-stream input-device))) |
(%define 'rec (%lambda read-line-rec () |
(let ((ch (s 'get-char))) |
(%if (or2 (%char-eq? #\Newline ch) (%char-eq? #\Return ch)) |
%nil |
(%cons ch (rec)))))) |
(skip-whitespace s) |
(list->string (rec))))) |
|
;; Remove backspaced characters |
(%define 'fix-backspace |
(%lambda fix-backspace (strin) |
(let ((str (%make-array (%array-size strin) #\Newline))) |
(let ((size (%array-size strin))) |
(%define 'rec |
(%lambda fix-backspace-rec (i j) |
(%if (%num-eq? j size) |
(%if (%less-than? i j) |
(%progn |
(%array-set str i #\Newline) |
(rec (1+ i) j)) |
str) |
(%if (%char-eq? (%array-get strin j) #\Backspace) |
(rec (%if (%num-eq? i 0) 0 (1- i)) (1+ j)) |
(%progn |
(%array-set str i (%array-get strin j)) |
(rec (1+ i) (1+ j))))))) |
(rec 0 0))))) |
|
|
|
|
;; Macro system |
;; Move to nth-lisp file, RSN |
|
(%define 'macro-functions %nil) |
|
;; defmacro |
(%define 'defmacro-fn (%lambda %defmacro (name fn) |
(%set! 'macro-functions |
(%cons (%cons name fn) |
macro-functions)))) |
|
(%define 'get-macro-fn (%lambda get-macro-fn (name) |
(%progn |
(%define 'rec |
(%lambda get-macro-fn-rec (name list) |
(%if list |
(%if (%eq? (%car (%car list)) name) |
(%cdr (%car list)) |
(rec name (%cdr list))) |
%nil))) |
(rec name macro-functions)))) |
|
|
;; Tree walker and expander |
|
(%define 'fix-lambda-arguments |
(%lambda fix-lambda-arguments (args) |
(%progn |
(%define 'rec (%lambda fix-lambda-arguments-rec (args) |
(%if args |
(%if (%eq? '%. (%car args)) |
(%car (%cdr args)) |
(%cons (%car args) (rec (%cdr args)))) |
%nil))) |
(%if (%num-eq? (%type args) +type-cons+) |
(rec args) |
args)))) |
|
(%define 'fix-pair |
(%lambda fix-pair (pair) |
(%if (is-list? pair) |
(%if (%num-eq? (length pair) 3) |
(%if (%eq? '%. (%car (%cdr pair))) |
(%%list (%car pair) (%car (%cdr (%cdr pair)))) |
pair) |
pair) |
pair))) |
|
(%define 'expand-macro |
(%lambda expand-macro (root) |
(%if (%num-eq? (%type root) +type-cons+) |
(let ((mfn (get-macro-fn (%car root)))) |
(%if mfn |
(expand-macro (mfn root)) |
root)) |
root))) |
|
(%define 'tree-walker |
(%lambda tree-walker (root) |
(%if (%num-eq? (%type root) +type-cons+) |
(%if (%eq? (%car root) '%quote) |
root |
(let ((root (expand-macro (fix-pair root)))) |
(%if (%num-eq? (%type root) +type-cons+) |
(%if (%eq? (%car root) '%lambda) |
(%cons '%lambda |
(%cons (%car (%cdr root)) |
(%cons (fix-lambda-arguments (%car (%cdr (%cdr root)))) |
(map tree-walker (%cdr (%cdr (%cdr root))))))) |
(map tree-walker root)) |
root))) |
root))) |
|
;;; Move this to NTH-Lisp code base |
;;; !!! |
|
;; Lambda macro |
(defmacro-fn 'lambda |
(%lambda 'lambda-macro (root) |
(list '%lambda |
'anonymous |
(%car (%cdr root)) |
(%cons '%progn |
(%cdr (%cdr root)))))) |
|
(defmacro-fn 'named-lambda |
(%lambda 'named-lambda-macro (root) |
(list '%lambda |
(%car (%cdr root)) |
(%car (%cdr (%cdr root))) |
(%cons '%progn |
(%cdr (%cdr (%cdr root))))))) |
|
|
(defmacro-fn 'progn |
(%lambda 'progn-macro (root) |
(%cons '%progn |
(%cdr root)))) |
|
(defmacro-fn 'quote |
(%lambda 'quote-macro (root) |
(%cons '%quote |
(%cdr root)))) |
|
(defmacro-fn 'let |
(%lambda 'let-macro (root) |
(list (%cons 'named-lambda |
(%cons 'let |
(%cons (list (%car (%car (%car (%cdr root))))) |
(%cdr (%cdr root))))) |
(%car (%cdr (%car (%car (%cdr root)))))))) |
|
(defmacro-fn 'define |
(%lambda 'define-macro (root) |
(list '%define |
(list '%quote (%car (%cdr root))) |
(%car (%cdr (%cdr root)))))) |
(defmacro-fn 'setq! |
(%lambda 'setq!-macro (root) |
(list '%set! |
(list '%quote (%car (%cdr root))) |
(%car (%cdr (%cdr root)))))) |
|
(defmacro-fn 'cond |
(%lambda 'cond-macro (root) |
(%progn |
(%define 'rec (%lambda 'cond-macro-rec (lst) |
(%if lst |
(let ((pair (%car lst))) |
(list '%if |
(%car pair) |
(%car (%cdr pair)) |
(rec (%cdr lst)))) |
%nil))) |
(rec (%cdr root))))) |
|
(defmacro-fn 'if |
(%lambda 'if-macro (root) |
(list '%if |
(%car (%cdr root)) |
(%car (%cdr (%cdr root))) |
(%if (%num-eq? (length (%cdr root)) 2) |
%nil |
(%car (%cdr (%cdr (%cdr root)))))))) |
|
(defmacro-fn 'or |
(%lambda 'or-macro (root) |
(%progn |
(%define 'rec (%lambda or-macro-rec (args) |
(%if args |
(list (list '%lambda 'anonymous (list 'x) |
(list '%if |
'x 'x |
(rec (%cdr args)))) |
(%car args)) |
%nil))) |
(rec (%cdr root))))) |
|
(defmacro-fn 'and |
(%lambda 'and-macro (root) |
(%progn |
(%define 'rec (%lambda and-macro-rec (args) |
(%if args |
(list '%if |
(%car args) |
(rec (%cdr args)) |
(%car args)) |
%t))) |
(rec (%cdr root))))) |
|
;; Reduce |
(%define 'reduce (%lambda 'reduce (fn init list) |
(%if list |
(reduce fn (fn init (%car list)) (%cdr list)) |
init))) |
|
;; Make a function that calls reduce with the first argument as the |
;; init value and the rest of the arguments as the list. |
;; reducer takes a function that will be used during the reduce as |
;; the only input. |
(%define 'reducer (%lambda 'reduce (fn identity) |
(%lambda 'anonymous-reducer list |
(%if list |
(reduce fn (%if identity identity (%car list)) (%if identity list (%cdr list))) |
identity)))) |
|
(%define '+ (reducer %add 0)) |
(%define '- (%lambda sub lst |
(%if (%num-eq? (length lst) 1) |
(%sub 0 (%car lst)) |
(reduce %sub (%car lst) (%cdr lst))))) |
(%define '* (reducer %mul 1)) |
(%define '/ %div) |
(%define 'mod %mod) |
|
(%define '= %num-eq?) |
(%define '< %less-than?) |
(%define '> (%lambda 'greater-than? (a b) |
(%if (or2 (%num-eq? a b) |
(%less-than? a b)) |
%nil |
%t))) |
|
(%define 'car %car) |
(%define 'cdr %cdr) |
(%define 'cons %cons) |
(%define 'set! %set!) |
(%define 'set-car! %set-car!) |
(%define 'set-cdr! %set-cdr!) |
(%define 'make-array %make-array) |
(%define 'array-get %array-get) |
(%define 'array-size %array-size) |
|
(defun append (li lu) |
(%if li |
(cons (car li) (append (cdr li) lu)) |
lu)) |
|
(defun null? (dings) |
(%if (%eq? nil dings) |
%t |
%nil)) |
|
|
|
;;; !!! END |
|
(%define |
'combine |
(%lambda |
combine (f g) ; produces combination of single-argument |
; functions f and g |
(%lambda combination (x) (f (g x))))) |
|
(%define 'caar (combine car car)) |
(%define 'cadr (combine car cdr)) |
(%define 'cdar (combine cdr car)) |
(%define 'cddr (combine cdr cdr)) |
(%define 'cdddr (combine cddr cdr)) |
(%define 'caddr (combine cadr cdr)) |
(%define 'cadddr (combine caddr cdr)) |
|
(%define 'igorev-state-func-frame car) |
(%define 'igorev-state-condition cadr) |
(%define 'igorev-state-iterations caddr) |
|
(%define 'igorev-func-frame-func car) |
(%define 'igorev-func-frame-env cadr) |
(%define 'igorev-func-frame-eval-frame caddr) |
(%define 'igorev-func-frame-parent cadddr) |
|
(%define 'igorev-eval-frame-expr car) |
(%define 'igorev-eval-frame-arg cadr) |
(%define 'igorev-eval-frame-result caddr) |
(%define 'igorev-eval-frame-phase cadddr) |
(%define 'igorev-eval-frame-parent (combine caddr cddr)) |
|
(%define |
'igorev-state-huge-success? |
(%lambda |
igorev-state-huge-success? (state) |
(%eq? (igorev-state-condition state) nil))) |
|
(%define |
'igorev-state-result |
(%lambda |
igorev-state-result (state) |
(igorev-eval-frame-result |
(igorev-func-frame-eval-frame |
(igorev-state-func-frame state))))) |
|
(%define |
'igorev-state-expr |
(%lambda |
igorev-state-expr (state) |
(igorev-eval-frame-expr |
(igorev-func-frame-eval-frame |
(igorev-state-func-frame state))))) |
|
(%define 'igorev-env-local-bindings car) |
|
|
(%define |
'function-name |
(%lambda |
function-name (f) |
(%car (%function-data f)))) |
|
(%define |
'function-param-list |
(%lambda |
function-param-list (f) |
(%cadr (%function-data f)))) |
|
(%define |
'function-expr |
(%lambda |
function-expr (f) |
(%caddr (%function-data f)))) |
|
(%define |
'function-env |
(%lambda |
function-end (f) |
(%cadddr (%function-data f)))) |
|
|
|
(%define |
'show-error-message |
(%lambda |
show-error-message (state) |
(%progn |
(display "Error: ") |
(print (igorev-state-condition state)) |
(display " at ") |
(print (igorev-state-expr state)) |
(newline) |
(display " in ") |
(print (igorev-func-frame-func (igorev-state-func-frame state))) |
(newline)))) |
|
|
(%define |
'display |
(%lambda |
display (str) |
(%progn |
(%define |
'display-rec |
(%lambda |
display-rec (i) |
(%if (%less-than? i (%array-size str)) |
(%progn |
(%put-char current-output (%array-get str i)) |
(display-rec (1+ i))) |
nil))) |
(%if (is-string? str) |
(display-rec 0) |
(%error (list '%err-type-error str 'string)))))) |
|
(defun displine (str) |
(display str) |
(newline) |
nil) |
|
|
|
;; (%define |
;; 'new-environment |
;; (%lambda |
;; new-environment (parent) |
;; (%cons %nil parent))) |
|
(defun new-environment (parent) |
(%cons %nil parent)) |
|
(defun debug (state) |
(displine "Entering debugger") |
(let ((top-fframe (igorev-state-func-frame state))) |
(let ((top-eframe (igorev-func-frame-eval-frame top-fframe))) |
(dbg-show-fframe top-fframe) |
(dbg-show-eframe top-eframe) |
(dbg-repl state top-fframe '() top-eframe '())))) |
|
(defun dbg-show-fframe (f) |
(displine "Current function frame:") |
(display " Function: ") |
(print (igorev-func-frame-func f)) |
(newline) |
(display " Local bindings: ") |
(print (igorev-env-local-bindings |
(igorev-func-frame-env f))) |
(newline)) |
|
(defun dbg-show-eframe (e) |
(displine "Current eval frame:") |
(display " Expr: ") |
(print (igorev-eval-frame-expr e)) |
(newline) |
(display " Arg: ") |
(print (igorev-eval-frame-arg e)) |
(newline) |
(display " Result: ") |
(print (igorev-eval-frame-result e)) |
(newline) |
(display " Phase: ") |
(print (igorev-eval-frame-phase e)) |
(newline)) |
|
(defun dbg-show-fstack (frame descendants) |
(defun print-frame (f num is-current) |
(%if is-current (display "(*)") nil) |
(print num) |
(display ": ") |
(print (igorev-func-frame-func f)) |
(newline)) |
(defun print-frames (frames i) |
(%if frames |
(%progn |
(print-frame (car frames) i |
(%eq? (car frames) frame)) |
(print-frames (cdr frames) (1+ i))) |
nil)) |
(defun collect-frames (frame rest) |
(%if frame |
(collect-frames (igorev-func-frame-parent frame) |
(cons frame rest)) |
rest)) |
(print-frames (collect-frames frame descendants) 0)) |
|
(defun dbg-show-estack (frame descendants) |
(defun print-frame (f num is-current) |
(%if is-current (display "(*)") nil) |
(print num) |
(display ": ") |
(print (igorev-eval-frame-expr f)) |
(newline)) |
(defun print-frames (frames i) |
(%if frames |
(%progn |
(print-frame (car frames) i |
(%eq? (car frames) frame)) |
(print-frames (cdr frames) (1+ i))) |
nil)) |
(defun collect-frames (frame rest) |
(%if frame |
(collect-frames (igorev-eval-frame-parent frame) |
(cons frame rest)) |
rest)) |
(print-frames (collect-frames frame descendants) 0)) |
|
(defun dbg-show-env (fframe) |
(displine "(TODO)")) |
|
(defun dbg-repl (state fframe fframes-below eframe eframes-below) |
(%define 'continue %t) |
(defun env () |
(igorev-func-frame-env fframe)) |
(defun deval (expr) |
(%eval expr (env))) |
(defun up () |
(let ((parent (igorev-func-frame-parent fframe))) |
(%if parent |
(%progn |
(%set! 'fframes-below (cons fframe fframes-below)) |
(%set! 'fframe parent) |
(%set! 'eframe (igorev-func-frame-eval-frame fframe)) |
(%set! 'eframes-below '()) |
(displine "Moved one function frame up")) |
(displine "Current function frame is an orphan")))) |
(defun down () |
(%if fframes-below |
(%progn |
(%set! 'fframe (car fframes-below)) |
(%set! 'fframes-below (cdr fframes-below)) |
(%set! 'eframe (igorev-func-frame-eval-frame fframe)) |
(%set! 'eframes-below '()) |
(displine "Moved one function frame down")) |
(displine "Current function frame is childless"))) |
(defun eup () |
(let ((parent (igorev-eval-frame-parent eframe))) |
(%if parent |
(%progn |
(%set! 'eframes-below (cons eframe eframes-below)) |
(%set! 'eframe parent) |
(displine "Moved one eval frame up")) |
(displine "Current eval frame is an orphan")))) |
(defun edown () |
(%if eframes-below |
(%progn |
(%set! 'eframe (car eframes-below)) |
(%set! 'eframes-below (cdr eframes-below)) |
(displine "Moved one eval frame down")) |
(displine "Current eval frame is childless"))) |
(defun show (what) |
(%if (%eq? what 'fframe) |
(dbg-show-fframe fframe) |
(%if (%eq? what 'eframe) |
(dbg-show-eframe eframe) |
(%if (%eq? what 'env) |
(dbg-show-env fframe) |
(%if (%eq? what 'fstack) |
(dbg-show-fstack fframe fframes-below) |
(%if (%eq? what 'estack) |
(dbg-show-estack eframe eframes-below) |
(displine "What what?"))))))) |
(defun quit () |
(%set! 'continue %nil)) |
(defun read () |
(display "dbg> ") |
(let ((expr (tree-walker |
(read-from-string (fix-backspace (read-line current-input)))))) |
(newline) |
expr)) |
(defun eval/print (expr) |
(let ((state (%eval-partial |
(%make-eval-state expr |
(new-environment (%current-environment))) |
0))) |
(%if (igorev-state-huge-success? state) |
(%progn |
(display "Result: ") |
(print (igorev-state-result state)) |
(newline)) |
(show-error-message state)))) |
|
(eval/print (read)) |
(%if continue |
(dbg-repl state fframe fframes-below eframe eframes-below) |
(displine "Exiting debugger"))) |
|
|
|
(defun try (expr) |
(let ((state (%eval-partial |
(%make-eval-state (tree-walker expr) |
(%current-environment)) |
0))) |
(%if (igorev-state-huge-success? state) |
(list 'success (igorev-state-result state)) |
(list 'interrupt (cdr (igorev-state-condition state)) state)))) |
|
(defun catch-fn (handlers expr) |
(defun find-handler (condition handlers) |
(%if handlers |
(%if ((caar handlers) condition) |
(cdar handlers) |
(find-handler condition (cdr handlers))) |
nil)) |
(let ((result (try expr))) |
(%if (%eq? (car result) 'success) |
(cadr result) |
(let ((condition (cadr result))) |
(let ((handler (find-handler condition handlers))) |
(%if handler |
(handler condition) |
(%error condition))))))) |
|
(defmacro-fn |
'catch |
(%lambda |
catch-macro (root) |
(let ((cond-var (cadr root))) |
(let ((handlers (caddr root))) |
(let ((body (cdddr root))) |
(list 'catch-fn |
(cons |
'list |
(map (%lambda |
catch-macro-create-handler-function (handler) |
(list 'cons |
(list '%lambda 'catch-handler-predicate (list cond-var) |
(car handler)) |
(list '%lambda 'catch-handler-function (list cond-var) |
(cadr handler)))) |
handlers)) |
(list '%quote (cons '%progn body)))))))) |
|
(defun condition-type (condition) |
(%if (is-list? condition) |
(car condition) |
condition)) |
|
|
|
(%define '*igorrepl-continue* %t) |
(%define |
'quit |
(%lambda |
quit () ; make it all go away |
(%set! '*igorrepl-continue* nil))) |
|
;; REPL |
(%define 'igorrepl (%lambda igorrepl (n env) |
(%progn |
(display "IGORrepl: ") |
(let ((state (%make-eval-state |
(tree-walker |
(read-from-string (fix-backspace (read-line current-input)))) |
env))) |
(newline) |
(let ((state (%eval-partial state 0))) |
(let ((cond (%car (%cdr state)))) |
(newline) |
(%if (igorev-state-huge-success? state) |
(%progn |
(display "Result: ") |
(print (igorev-state-result state))) |
(%progn |
(show-error-message state) |
(debug state))) |
(newline) |
(%if *igorrepl-continue* |
(%if (%num-eq? n 1) |
%t |
(igorrepl (%if (%num-eq? n 0) 0 (1- n)) env)) |
nil))))))) |
|
|
|
;;(intern-symbols %symbol-table) |
|
(display "boot program $Rev: 1441 $") |
(newline) |
|
(%define |
'looptyloop |
(%lambda |
looptyloop () |
(let ((state (%make-eval-state '(igorrepl 0 (new-environment (%current-environment))) |
(%current-environment)))) |
(let ((new-state (%eval-partial state 0))) |
(%if (igorev-state-huge-success? new-state) |
(%progn |
(display "Happy Happy Joy Joy") |
(newline)) |
(%progn |
(newline) |
(display "ERROR IN TOP-LEVEL REPL") |
(newline) |
(show-error-message new-state) |
(looptyloop))))))) |
(looptyloop) |
)) |
|
/microprogram_assembler/package.lisp
0,0 → 1,13
;;; |
;;; Package definition |
;;; |
|
(defpackage #:mcasm |
(:use :cl)) |
|
(in-package #:mcasm) |
|
;; The pre-assembled data object |
(defvar *pre-assembly-data* ()) |
|
|
/microprogram_assembler/assembler.lisp
0,0 → 1,837
;;; |
;;; Assembler! |
;;; |
|
(in-package #:mcasm) |
|
(defvar *assembler-constants* (make-hash-table :test 'equal)) |
(defvar *assembler-labelnumbers* 0) |
|
(defun next-labelnumber () |
(incf *assembler-labelnumbers*)) |
|
(defstruct constant-info |
type |
name |
number) |
|
(defun constant-info-to-string (info &key (key nil)) |
(format nil "~A~A~A~A" |
(constant-info-type info) |
(if key |
"-" |
" ") |
(constant-info-name info) |
(if key "" |
(format nil " ~X" (constant-info-number info))))) |
|
(defmacro def-const ((name number &key (type "const")) &body body) |
`(let ((info (make-constant-info :type ,type |
:name ',name |
:number ,number))) |
(setf (gethash (constant-info-to-string info :key nil) *assembler-constants*) info) |
,@body)) |
|
(defmacro def-branch (name number) |
`(def-const (,name ,number :type "branch") |
(defparameter ,(intern (format nil "-BRANCH-~A-" name)) ,number))) |
|
(def-branch O 1) |
(def-branch C 2) |
(def-branch N 4) |
(def-branch Z 8) |
(def-branch B 16) |
|
(defmacro def-type (name number) |
`(def-const (,name ,number :type "type") |
(defparameter ,(intern (format nil "+TYPE-~A+" name)) ,number))) |
|
(def-type none #x0) |
(def-type int #x1) |
(def-type float #x3) |
(def-type cons #x4) |
(def-type snoc #x5) |
(def-type ptr #x6) |
(def-type array #x7) |
(def-type nil #x8) |
(def-type t #x9) |
(def-type char #xA) |
(def-type symbol #xB) |
(def-type function #xC) |
(def-type builtin #xD) |
|
(defparameter +n-regs+ #x400) ; number of registers |
|
(defmacro defreg (name number) |
`(def-const (,name ,number :type "reg") |
(defparameter ,(intern (format nil "$~A" name)) ,number))) |
|
(defmacro defmem (name number) |
`(def-const (,name ,number :type "memory") |
(defparameter ,(intern (format nil "%~A" name)) ,number))) |
|
(defreg zero #x00) |
(defreg one #x01) |
(defreg two #x02) |
|
(defreg s-addr #x03) ; address where an sframe has been stored |
;;(defreg s-name #x04) ;; TODO do we want this? |
;;(defreg s-fstack #x04) |
(defreg s-condition #x04) |
(defreg s-iterations #x05) |
(defreg s-parent #x06) |
|
;;(defreg e/f-addr #x07) |
;;(defreg e/f-parent-addr #x08) |
|
(defreg s-tmp #x09) |
(defreg e-tmp1 #x0A) |
(defreg e-tmp2 #x0B) |
(defreg e-tmp3 #x0C) |
(defreg f-tmp1 #x0D) |
(defreg f-tmp2 #x0E) |
(defreg f-tmp3 #x0F) |
|
;;(defreg e-addr #x09) ;; TODO remove this |
(defreg e-expr #x10) |
(defreg e-arg #x11) |
(defreg e-result #x12) |
(defreg e-phase #x13) |
(defreg e-addr #x14) |
|
;;(defreg f-addr #x15) ;; TODO remove this |
(defreg f-func #x16) |
(defreg f-env #x17) |
;;(defreg f-estack #x18) |
(defreg f-addr #x19) |
|
(defreg alloc-addr #x20) |
(defreg alloc-top #x21) |
(defreg alloc-size #x22) |
|
(defreg store-list-start #x23) |
(defreg store-list-end #x24) |
(defreg store-list-addr #x25) |
(defreg store-list-reg #x26) |
(defreg store-list-val #x27) |
|
(defreg apply-result #x28) |
(defreg apply-result-val #x29) |
(defreg apply-func #x2A) |
(defreg builtin-arg1 #x2B) |
(defreg builtin-arg2 #x2C) |
(defreg builtin-arg3 #x2D) |
(defreg builtin-arg1-val #x2E) |
(defreg builtin-arg2-val #x2F) |
(defreg builtin-arg3-val #x30) |
|
(defreg tmp-result #x33) |
|
(defreg apply-argc #x34) |
(defreg apply-required-argc #x35) |
|
(defreg car #x40) |
(defreg cdr #x41) |
(defreg list-terminator #x42) |
|
(defreg interrupt-tmp #x45) |
|
(defreg params-car #x50) |
(defreg args-car #x51) |
(defreg apply-eval-expr #x52) |
(defreg apply-eval-env #x53) |
(defreg apply-apply-args #x54) |
(defreg apply-apply-params #x55) |
(defreg env #x56) |
|
(defreg tmp1 #x57) |
(defreg tmp2 #x58) |
(defreg tmp3 #x59) |
(defreg tmp4 #x5A) |
|
(defreg fetch-args-arg-reg #x60) |
(defreg fetch-args-arg #x61) |
(defreg fetch-args-argval-reg #x62) |
(defreg fetch-args-argval #x63) |
(defreg fetch-args-arglist #x64) |
|
(defreg io-devnr #x65) |
(defreg io-new-devnr #x66) |
(defreg io-mem-addr #x67) |
|
(defreg message #x68) |
(defreg message-shift #x69) |
(defreg message-mask #x6A) |
(defreg message-tmp1 #x6B) |
(defreg message-tmp2 #x6C) |
|
(defreg mc-stack-top #x090) |
(defreg mc-stack-min #x091) |
(defreg mc-stack-max #x09E) |
|
(defreg e/f-top #x09F) |
(defreg e/f-below-marker #x100) |
(defreg e/f-min #x104) |
(defreg e/f-min-expr #x104) |
(defreg e/f-min-arg #x105) |
(defreg e/f-min-result #x106) |
(defreg e/f-min-phase #x107) |
|
;; (defreg e/f-max-expr #x118) |
;; (defreg e/f-max-arg #x119) |
;; (defreg e/f-max-result #x11A) |
;; (defreg e/f-max-phase #x11B) |
;; (defreg e/f-max #x11B) |
;; (defreg e/f-above-marker #x11C) |
|
(defreg e/f-max-expr #x3F8) |
(defreg e/f-max-arg #x3F9) |
(defreg e/f-max-result #x3FA) |
(defreg e/f-max-phase #x3FB) |
(defreg e/f-max #x3FB) |
(defreg e/f-above-marker #x3FC) |
(defreg e/f-frame-size #x3FD) |
|
(defreg init1 #x3F0) |
(defreg init2 #x3F1) |
(defreg init3 #x3F2) |
(defreg init-counter #x3F3) |
(defreg init-counter2 #x3F4) |
(defreg init-shift1 #x3F5) |
(defreg init-shift2 #x3F6) |
(defreg init-char-mask #x3F7) |
(defreg init-chars-start #x3F8) |
(defreg init-symbol-addr #x3F9) |
(defreg init-symbol-str-addr #x3FA) |
(defreg init-symbol-char-addr #x3FB) |
(defreg init-symbol-array #x3FC) |
|
;; needed variables (registers) for gc |
|
;; register values that must be predefined |
;; set these when testing gc standalone in emulator |
(defreg gc-maxblocks #x70) ;; total memory size |
(defreg gc-spaces #x71) ;; number of spaces we'll divide the memory in |
(defreg gc-startofmem #x76) ;; start of variable address space |
|
;; registers set by evaluator before invoking gc |
;; set these when testing gc standalone in emulator |
(defreg gc-rootptr #x78) ;; pointer to topmost object! hopefully |
;; there will be only one |
|
;; registers set by init, keep these throughout |
(defreg gc-spacesize #x72) ;; size of each space: maxblocks / spaces |
(defreg gc-sup #x73) ;; first address beyond legal space: |
;; spaces * spacesize (NB: can be lower than |
;; maxblocks) |
(defreg gc-gcspace #x74) ;; start of gc exclusize space, sup - spacesize |
|
;; registers used by everyone |
(defreg gc-firstfree #x75) ;; first free memory block |
;; (might exist already in other microcode) |
|
;; scratch registers, can be used when gc is not running (but gc will |
;; destroy them) |
|
(defreg gc-1 #x80) ;; temp |
(defreg gc-vi #x83) |
(defreg gc-t #x84) ;; ptr-rev |
(defreg gc-x #x85) ;; ptr-rev |
(defreg gc-y #x86) ;; ptr-rev |
(defreg gc-v #x87) ;; ptr-rev |
(defreg gc-followp #x88) ;; ptr-rev |
(defreg gc-cannext #x89) ;; ptr-rev |
(defreg gc-canprev #x8a) ;; ptr-rev |
|
(defreg gc-temp #x8b) |
(defreg gc-mem #x8c) |
(defreg gc-from #x84) ;; at this stage we're no longer using |
(defreg gc-to #x85) ;; some of the above variables |
(defreg gc-val #x86) |
(defreg gc-temp2 #x87) |
(defreg gc-baseaddr #x88) |
|
(defreg gc-mem-limit #x7F) |
|
;; div-variables (reusing gc-registers) |
(defreg div-low #x88) |
(defreg div-high #x89) |
(defreg div-mid #x8a) |
(defreg div-res #x8b) |
(defreg div-sign #x8c) |
(defreg mod-val1 #x87) |
(defreg mod-val2 #x86) |
|
(defparameter +gc-free+ #x00) |
(defparameter +gc-used+ #x01) |
|
(defparameter +gc-spaces+ #xA) |
|
(defparameter +gc-limit+ #x1000) ; if free space is less than this, GC should be run |
|
|
;; memory: |
|
(defmem nil #x00) |
(defmem t #x01) |
(defmem if #x02) |
(defmem quote #x03) |
(defmem lambda #x04) |
(defmem progn #x05) |
|
(defparameter +first-builtin+ #x06) |
(defmem cons #x06) |
(defmem car #x07) |
(defmem cdr #x08) |
(defmem eval #x09) |
(defmem apply #x0A) |
(defmem type #x0B) |
(defmem make-array #x0C) |
(defmem array-size #x0D) |
(defmem array-get #x0E) |
(defmem array-set #x0F) |
(defmem make-symbol #x10) |
(defmem symbol-to-string #x11) |
(defmem char-to-int #x12) |
(defmem int-to-char #x13) |
(defmem get-char #x14) |
(defmem put-char #x15) |
(defmem num-devices #x16) |
(defmem device-type #x17) |
(defmem set-address #x18) |
(defmem get-address #x19) |
(defmem error #x1A) |
(defmem add #x1B) |
(defmem sub #x1C) |
(defmem mul #x1D) |
(defmem div #x1E) |
(defmem bitwise-and #x1F) |
(defmem bitwise-or #x20) |
(defmem bitwise-not #x21) |
(defmem bitwise-shift #x22) |
(defmem current-environment #x23) |
(defmem make-eval-state #x24) |
(defmem eval-partial #x25) |
(defmem define #x26) |
(defmem undefine #x27) |
(defmem eq? #x28) |
(defmem num-eq? #x29) |
(defmem char-eq? #x2A) |
(defmem less-than? #x2B) |
(defmem mod #x2C) |
(defmem set! #x2D) |
(defmem set-car! #x2E) |
(defmem set-cdr! #x2F) |
(defmem function-data #x30) |
(defmem builtin-name #x31) |
(defmem device-size #x32) |
(defmem device-status #x33) |
(defparameter +last-builtin+ %device-status) |
(defparameter +first-magic-var+ +first-builtin+) |
(defparameter +last-magic-var+ +last-builtin+) |
|
(defmem symbol-table #x3F) |
(defparameter +first-phase+ #x40) |
(defmem phase-eval #x40) |
(defmem phase-eval-args #x41) |
(defmem phase-apply #x42) |
(defmem phase-eval-if #x43) |
(defmem phase-initial #x44) |
(defmem phase-env-lookup #x45) |
(defmem phase-env-lookup-local #x46) |
(defmem phase-apply-function #x47) |
(defmem phase-bind-args #x48) |
(defmem phase-eval-progn #x49) |
(defmem phase-eval-args-top #x4A) |
(defmem phase-eval-args-cdr #x4B) |
(defmem phase-eval-args-cons #x4C) |
(defmem phase-eval-symbol #x4D) |
(defmem phase-set! #x4E) |
(defparameter +last-phase+ %phase-set!) |
|
(defmem timeout #x50) |
(defmem err-invalid-phase #x51) |
(defmem err-unbound-symbol #x52) |
(defmem err-invalid-param-list #x53) |
(defmem err-too-few-args #x54) |
(defmem err-too-many-args #x55) |
(defmem err-invalid-state #x56) |
(defmem err-invalid-arg-list #x57) |
(defmem err-type-error #x58) |
(defmem err-not-a-list #x59) |
(defmem err-not-a-function #x5A) |
(defmem err-invalid-function #x5B) |
(defmem err-malformed-form #x5C) |
(defmem err-invalid-builtin #x5D) |
(defmem err-invalid-array-index #x5E) |
(defmem err-invalid-env #x5F) |
(defmem err-not-a-pair #x60) |
(defmem err-io-error #x61) |
(defmem err-division-by-zero #x62) |
(defmem err-overflow #x63) |
(defparameter +last-symbol+ %err-overflow) |
|
(defmem area-builtins #x100) |
(defmem area-chars #x200) |
(defmem area-ints #x280) |
(defmem area-strings #x300) |
(defmem area-symlist #xE00) |
|
(defparameter +constant-chars+ (- %area-ints %area-chars)) |
(defparameter +constant-ints+ (- %area-strings %area-ints)) |
|
(defmem memory-root #xFFE) |
(defmem mem-reserved-top #x1000) |
(defmem boot-prog-start %mem-reserved-top) |
|
(defparameter +memory-size+ (* 2 (* 1024 1024))) |
|
(defmem io-mem-addr #x3FFFF00) ; TODO too large for immediate value |
(defmem io-devices #x00) |
(defmem io-curdev #x01) |
(defmem io-cli #x02) |
(defmem io-sai #x03) |
(defmem io-intrdev #x04) |
(defmem io-object #x10) |
(defmem io-addr-l #x11) |
(defmem io-addr-h #x12) |
(defmem io-size-l #x13) |
(defmem io-size-h #x14) |
(defmem io-status #x15) |
(defmem io-identification #x16) |
(defmem io-irqenable #x17) |
|
(defparameter +dev-boot+ #x03) |
(defparameter +dev-serial+ #x00) |
|
|
;;; Helper functions |
|
;; Convert a argument to the argument type |
(defun argument-to-type (arg) |
(typecase arg |
(integer 'imm) |
(keyword 'label) |
(t 'other))) |
|
;; Make the instruction |
;; Only set the opcode |
(defun make-inst-opcode (opcode &key (debug 0) (break 0)) |
(let ((inst 0)) |
(setf (ldb (byte 6 42) inst) opcode) |
(setf (ldb (byte 1 41) inst) debug) |
(setf (ldb (byte 1 40) inst) break) |
inst)) |
|
;; Parse an integer symbol and return the register number |
(defun reg-to-num (reg) |
(typecase reg |
(symbol |
(parse-integer (subseq (format nil "~A" reg) 1))) |
(integer |
reg))) |
|
(defmacro rewrite-inst-part (inst &key from size value) |
`(setf (ldb (byte ,size ,from) ,inst) ,value)) |
|
;; Make a function that returnes the binary representation of an instruction |
(defmacro set-instruction ((&rest rest) &body body) |
(let ((opcodevar (gensym)) |
(debugvar (gensym)) |
(instvar (gensym)) |
(breakvar (gensym))) |
`(lambda (,opcodevar ,@rest &key (,debugvar 0) (,breakvar 0)) |
(let ((,instvar (make-inst-opcode ,opcodevar :debug ,debugvar :break ,breakvar))) |
,@(loop for part in body |
collect (cons 'rewrite-inst-part (cons instvar part))) |
,instvar)))) |
|
;; The different opcode formats |
(defparameter +opcodeformats+ |
`( |
(noarg . (() ,(set-instruction ()))) |
(mem . ((r r imm) ,(set-instruction (r1 r2 imm) |
(:size 11 :from 29 :value (reg-to-num r1)) |
(:size 11 :from 18 :value (reg-to-num r2)) |
(:size 18 :from 0 :value imm)))) |
(data . ((r r) ,(set-instruction (r1 r2) |
(:size 11 :from 29 :value (reg-to-num r1)) |
(:size 11 :from 18 :value (reg-to-num r2))))) |
(dataimm . ((r imm) ,(set-instruction (r1 imm) |
(:size 11 :from 29 :value (reg-to-num r1)) |
;(:size 11 :from 18 :value (reg-to-num r2)) |
(:size 29 :from 0 :value imm)))) |
(onereg . ((r) ,(set-instruction (r1) |
(:size 11 :from 29 :value (reg-to-num r1))))) |
(alu . ((r r) ,(set-instruction (r1 r2) |
(:size 11 :from 29 :value (reg-to-num r1)) |
(:size 11 :from 18 :value (reg-to-num r2))))) |
(argtype0 . ((imm) ,(set-instruction (imm) |
(:size 40 :from 0 :value imm)))) |
(argtype1 . ((r imm) ,(set-instruction (r1 imm) |
(:size 11 :from 29 :value (reg-to-num r1)) |
(:size 29 :from 0 :value imm)))) |
(branch . ((r imm imm imm) ,(set-instruction (r1 mask flag addr) |
(:size 11 :from 29 :value (reg-to-num r1)) |
(:size 8 :from 21 :value mask) |
(:size 8 :from 13 :value flag) |
(:size 13 :from 0 :value addr)))) |
)) |
|
;; Get the function from a format type |
(defun get-format-function (format) |
(second (cdr (assoc format +opcodeformats+)))) |
|
;; Add an instruction to the list |
(defun add-instruction (opcode args function) |
(setf *pre-assembly-data* |
(append |
(list (list opcode args function)) |
*pre-assembly-data*))) |
|
;; Define an instruction |
;; The generated function returns a list that contains the opcode, |
;; the arguments and the function that makes the bit representation. |
(defmacro make-instruction (name format opcode) |
`(defun ,(intern (format nil "%~A" name)) (&rest args) |
(when (eq *assembler-state* :gather) |
(incf *assembler-position*)) |
(let ((f (cdr (assoc ',format +opcodeformats+)))) |
(when (not f) |
(error "Missing opcode group for ~A for instruction ~A" ',format ',name)) |
(add-instruction ,opcode args f)))) |
|
;; Write a 48bit binary value to a stream |
(defun write-48bit-unsigned (value s) |
(write-byte (ldb (byte 8 40) value) s) |
(write-byte (ldb (byte 8 32) value) s) |
(write-byte (ldb (byte 8 24) value) s) |
(write-byte (ldb (byte 8 16) value) s) |
(write-byte (ldb (byte 8 8) value) s) |
(write-byte (ldb (byte 8 0) value) s)) |
|
;; Assemble our instructions |
(defun assemble-it (pre-assembly stream &key output-format simulator-lines) |
(let ((pre-assembly (copy-tree (reverse pre-assembly)))) |
;; Assemble and write out |
(format t "Writing out assembly~%") |
(let ((instructions (loop for a in pre-assembly |
unless (labelp a) |
collect (apply (second (third a)) (first a) (second a))))) |
(let ((number-of-instructions (length instructions))) |
(dolist (inst instructions) |
(cond ((eq output-format :human-readable) |
(format stream "~12,'0X -- ~48,'0B~%" inst inst)) |
((eq output-format :simulator) |
(format stream "~48,'0B~%" inst)) |
(t |
(write-48bit-unsigned inst stream)))) |
(when simulator-lines |
(dotimes (i (- simulator-lines number-of-instructions)) |
(format stream "~48,'0B~%" 0))))))) |
|
;; Empty assembler cache |
(defun reset-assembler () |
(setf *pre-assembly-data* (list))) |
|
;;; Setup instructions and reset the assembler |
(defun setup-assembler () |
(make-instruction nop noarg #x00) |
(make-instruction halt noarg #x01) |
|
;; ALU |
(make-instruction add alu #x02) |
(make-instruction sub alu #x03) |
(make-instruction mul alu #x04) |
(make-instruction div alu #x05) |
(make-instruction and alu #x06) |
(make-instruction or alu #x07) |
(make-instruction xor alu #x08) |
(make-instruction not alu #x09) |
(make-instruction shift-l alu #x0A) |
(make-instruction mod alu #x0B) |
(make-instruction shift-r alu #x0C) |
|
;; Memory |
(make-instruction load mem #x10) |
(make-instruction store mem #x11) |
|
;; Branch |
(make-instruction branch branch #x16) |
|
;; Status |
(make-instruction set-flag argtype1 #x17) |
(make-instruction clear-flag argtype0 #x18) |
(make-instruction get-flag argtype1 #x19) |
|
;; Data |
(make-instruction get-type data #x20) |
(make-instruction set-type data #x21) |
(make-instruction set-type-imm dataimm #x22) |
|
(make-instruction set-datum data #x23) |
(make-instruction set-datum-imm dataimm #x24) |
|
(make-instruction get-gc data #x25) |
(make-instruction set-gc data #x26) |
(make-instruction set-gc-imm dataimm #x27) |
|
(make-instruction cpy data #x28) |
|
;; Compare |
(make-instruction cmp-type data #x29) |
(make-instruction cmp-type-imm dataimm #x2A) |
(make-instruction cmp-datum data #x2B) |
(make-instruction cmp-datum-imm dataimm #x2C) |
(make-instruction cmp-gc data #x2D) |
(make-instruction cmp-gc-imm dataimm #x2E) |
(make-instruction cmp data #x2F) |
|
;; Leds |
(make-instruction set-leds onereg #x3F) |
|
(reset-assembler) |
|
t) |
|
;; Info gathering or assembling state |
;; The first get labels information and so on, the second assemble correct instructions |
(defvar *assembler-state*) |
(defvar *assembler-labels*) |
(defvar *assembler-position*) |
|
;; Debug functions |
|
;; Write labels |
(defun write-labels (file labels) |
(format t "Writing out label information~%") |
(with-open-file (s |
(concatenate 'string file ".labels") |
:element-type 'character |
:direction :output |
:if-does-not-exist :create |
:if-exists :supersede) |
(maphash |
(lambda (key value) |
(format s "~A ~X~%" key value)) |
labels))) |
|
;; Write constant information |
(defun write-constants (file constants labels) |
(format t "Writing constant information~%") |
(with-open-file (s |
(concatenate 'string file ".const") |
:element-type 'character |
:direction :output |
:if-does-not-exist :create |
:if-exists :supersede) |
(maphash |
(lambda (key value) |
(format s "label ~A ~X~%" key value)) |
labels) |
(maphash (lambda (key value) |
(declare (ignore key)) |
(format s "~A~%" (constant-info-to-string value))) |
constants))) |
|
;; The main assembly macro |
;; Adds inst-prefixes and fixes labels |
(defmacro with-assembly ((outfile &key output-format simulator-lines) &body body) |
(let ((streamvar (gensym "STREAM"))) |
`(let ((*assembler-labels* (make-hash-table)) |
(*assembler-state* :gather) |
(*assembler-position* 0)) |
(setf *assembler-labelnumbers* 0) |
,@(loop |
for inst in (copy-tree body) |
when (not (labelp inst)) |
collect (rewrite-instruction inst :gather) |
when (labelp inst) |
collect `(setf (gethash ,inst *assembler-labels*) *assembler-position*)) |
(setf *assembler-labelnumbers* 0) |
(format t "We got ~D instructions~%" *assembler-position*) |
(with-open-file (,streamvar ,outfile |
:element-type ,(cond ((or (eq output-format :human-readable) |
(eq output-format :simulator)) |
''character) |
(t ''unsigned-byte)) |
:direction :output |
:if-does-not-exist :create |
:if-exists :supersede) |
(setf *assembler-state* :assemble) |
(reset-assembler) |
,@(loop |
for inst in body |
when (not (labelp inst)) |
collect (rewrite-instruction inst :assemble)) |
;; Write out assembled exectuable |
(assemble-it *pre-assembly-data* ,streamvar :output-format ,output-format :simulator-lines ,simulator-lines) |
;; Output debug info |
(write-constants ,outfile *assembler-constants* *assembler-labels*) |
(write-labels ,outfile *assembler-labels*))))) |
|
;;; Microcode instructions |
|
(defmacro with-new-label ((prefix var) &body body) |
`(let ((,var (intern (format nil "~A-~A" (string-upcase ,prefix) (next-labelnumber)) (find-package "KEYWORD")))) |
,@body)) |
|
(defmacro force-label (label) |
`(when (labelp ,label) |
(if (eq *assembler-state* :gather) |
(setf ,label 0) |
(progn |
(unless (gethash ,label *assembler-labels*) |
(error "Unknown label: ~A" ,label)) |
(setf ,label (gethash ,label *assembler-labels*)))))) |
|
(defmacro with-force-label ((label) &body body) |
(if (integerp label) |
`(progn |
,@body) |
`(let ((,label ,label)) |
(force-label ,label) |
,@body))) |
|
(defmacro with-force-label* ((var label) &body body) |
`(let ((,var ,label)) |
(force-label ,var) |
,@body)) |
|
(defmacro %when (comparison &body body) |
`(with-new-label ("when" end) |
,comparison |
(branchimm-false end) |
,@body |
(make-label end))) |
|
(defmacro %when-not (comparison &body body) |
`(with-new-label ("when" end) |
,comparison |
(branchimm end) |
,@body |
(make-label end))) |
|
(defmacro when= ((r1 r2) &body body) |
`(with-new-label ("when=" end) |
(%cmp-datum ,r1 ,r2) |
(branchimm-false end) |
,@body |
(make-label end))) |
|
(defmacro when!= ((r1 r2) &body body) |
`(with-new-label ("when=" end) |
(%cmp-datum ,r1 ,r2) |
(branchimm end) |
,@body |
(make-label end))) |
|
(defun some-stuff () |
(make-integer 3 4) |
(make-integer 4 4) |
(when= (3 4) |
(make-integer 5 4))) |
|
;; Make a indirect register |
(defun indirect-register (reg) |
(let ((i reg)) |
(setf (ldb (byte 1 10) i) 1) |
i)) |
|
;; Branch |
|
(defmacro %branch* (reg offset &rest flags) |
(let ((maskvar (gensym)) |
(flagvar (gensym))) |
`(let ((,maskvar (funcall #'logior ,@(loop for flag in flags |
collect (intern (format nil "-BRANCH-~A-" (if (listp flag) (cadr flag) flag)))))) |
(,flagvar (funcall #'logior ,@(loop for flag in flags |
when (not (listp flag)) |
collect (intern (format nil "-BRANCH-~A-" flag)))))) |
(%branch ,reg ,maskvar ,flagvar ,offset)))) |
|
(defun branchimm* (mask flag addr) |
(with-force-label (addr) ;; Hack to fix labels in a few places, sorry about this. |
(%branch $zero mask flag addr))) |
|
;; Immediate branch true |
(defun branchimm (addr) |
(branchimm* #x8 #x8 addr)) |
|
;; Immediate branch false |
(defun branchimm-false (addr) |
(branchimm* #x8 0 addr)) |
|
;; Jmp |
(defun jump (r addr) |
(with-force-label (addr) |
(%branch r 0 0 addr))) |
|
(defun jump-imm (addr) |
(with-force-label (addr) |
(jump $zero addr))) |
|
(defun jump-reg (r) |
(jump r 0)) |
|
(defun make-object-imm (reg type value) |
(%set-type-imm reg type) |
(%set-datum-imm reg value)) |
|
(defun make-integer (reg value) |
(make-object-imm reg +type-int+ value)) |
|
(defun %add* (d a b) |
(%cpy d a) |
(%add d b)) |
|
(defun %sub* (d a b) |
(%cpy d a) |
(%sub d b)) |
|
(defun %mul* (d a b) |
(%cpy d a) |
(%mul d b)) |
|
(defun %div* (d a b) |
(%cpy d a) |
(%div d b)) |
|
(defun %mod* (d a b) |
(%cpy d a) |
(%mod d b)) |
|
(defun %and* (d a b) |
(%cpy d a) |
(%and d b)) |
|
(defun %or* (d a b) |
(%cpy d a) |
(%or d b)) |
|
(defun %incr (reg) |
(%add reg $one)) |
|
(defun %decr (reg) |
(%sub reg $one)) |
|
(defun labeltest () |
(let ((label (gensym "IF-"))) |
(make-integer 10 #x5) |
(make-label (intern (format nil "~A" label) (find-package "KEYWORD"))))) |
|
#| |
;; Another simple test function |
;; Suppose to be used to define the real API the assembler will have |
(defun test-set2 () |
(with-assembly ("/tmp/microcode" :output-format :simulator :simulator-lines 100) |
(make-integer 3 4) |
(make-integer 4 4) |
(when= (3 4) |
(make-integer 5 4)) |
(when!= (3 4) |
(make-integer 6 4)))) |
|# |
|
;; Make microcode instruction functions |
(setup-assembler) |
/microprogram_assembler/mem.lisp
0,0 → 1,166
(in-package #:sexptomem) |
|
(sexp-to-memory |
(%nil |
%t |
%if |
%quote |
%lambda |
%progn |
%cons |
%car |
%cdr |
%eval |
%apply |
%type |
%make-array |
%array-size |
%array-get |
%array-set |
%make-symbol |
%symbol-to-string |
%char-to-int |
%int-to-char |
%get-char |
%put-char |
%num-devices |
%device-type |
%set-address |
%get-address |
%error |
%add |
%sub |
%mul |
%div |
%bitwise-and |
%bitwise-or |
%bitwise-not |
%bitwise-shift |
%current-environment |
%make-eval-state |
%eval-partial |
%define |
%undefine |
%eq? |
%num-eq? |
%char-eq? |
%less-than? |
%mod |
%set! |
%set-car! |
%set-cdr! |
|
%phase-eval |
%phase-eval-args |
%phase-apply |
%phase-eval-if |
%phase-initial |
%phase-env-lookup |
%phase-env-lookup-local |
%phase-apply-function |
%phase-bind-args |
%phase-eval-progn |
%phase-eval-args-top |
%phase-eval-args-cdr |
%phase-eval-args-cons |
%phase-eval-symbol |
%phase-set! |
|
xxx3F |
|
%timeout |
%err-invalid-phase |
%err-unbound-symbol |
%err-invalid-param-list |
%err-too-few-args |
%err-too-many-args |
%err-invalid-state |
%err-invalid-arg-list |
%err-type-error |
%err-not-a-list |
%err-not-a-function |
%err-invalid-function |
%err-malformed-form |
%err-invalid-builtin |
%err-invalid-array-index |
%err-invalid-env |
%err-not-a-pair) |
:1000 |
(%progn |
(%define (%quote =) (%lambda (a b) (%num-eq? a b))) |
(%define (%quote -) (%lambda (a b) (%sub a b))) |
(%define (%quote +) (%lambda (a b) (%add a b))) |
(%define (%quote *) (%lambda (a b) (%mul a b))) |
|
;; (%define (%quote print-string) |
;; (%lambda (str devnr) |
;; (%progn |
;; (%define (%quote iter) |
;; (%lambda (n) (%if (= n (%array-size str)) |
;; %nil |
;; (%progn |
;; (%put-char devnr (%array-get str n)) |
;; (iter (+ n 1)))))) |
;; (iter 0)))) |
|
(%put-char 1 #\h) |
(%put-char 1 #\e) |
(%put-char 1 #\l) |
(%put-char 1 #\l) |
(%put-char 1 #\o) |
(%put-char 1 #\Newline) |
|
(%define (%quote count) |
(%lambda (a b) |
(%progn |
(%define (%quote iter) |
(%lambda (n) |
(%if (= n b) n (iter (+ n 1))))) |
(iter a)))) |
|
;; (count 0 #x1000000) |
|
|
(%define (%quote echo) |
(%lambda (devnr) |
(%progn (%put-char devnr (%get-char devnr)) (echo devnr)))) |
;; (echo 1) |
|
(%define (%quote a) (%make-array 5 2)) |
|
(%array-get a 0) |
(%array-set a 1 (+ (%array-get a 0) |
(%array-get a 1))) |
(%array-set a 1 (+ (%array-get a 0) |
(%array-get a 1))) |
(%define (%quote r) %nil) |
(%set! (%quote r) 2) |
(%define |
(%quote fact) |
(%lambda (n) (%if (= n 1) 1 (* n (fact (- n 1)))))) |
(%set! (%quote r) (fact (- 12 (* (+ 3 1) 2)))) |
(%set! (%quote r) (%array-get a 1)) |
(%set! (%quote r) (%cons r a)) |
;;(%error (%quote foo)) |
|
;;(%define (%quote foo) (%lambda (a . foo) foo)) |
(%set! (%quote r) (foo 1 2 3)) |
|
r)) |
|
;; (%add 2 3) |
;; (%eval-partial |
;; (%make-eval-state (%quote (%add 11 5)) |
;; (%current-environment)) |
;; 0) |
;; (%apply |
;; (%lambda (p n) (%apply p (%cons p (%cons n %nil)))) |
;; (%cons (%lambda (p n) |
;; (%if (%num-eq? n 1) |
;; 1 |
;; (%mul n (%apply p (%cons p (%cons (%sub n 1) %nil)))))) |
;; (%cons 4 %nil))) |
;; (%apply (%lambda (a b) (%add a (%mul b 2))) (%quote (4 5)))) |
|
;; (sexp-to-memory |
;; (%if nil (%add 5 2) 3)) |
/microprogram_assembler/mc.lisp
0,0 → 1,89
;; veldig rask skisse til del av mikrokoden, med haugevis av mer eller |
;; mindre dumme antagelser om hva som er tilgjengelig i språket |
|
;; registers: pc, car/cdr, data/data-ext, state, stack-top, stack-op-start, op |
|
(defconst state-value 0) |
(defconst state-arglist 0) |
(defconst state-apply 0) |
|
(defconst op-none 0) |
(defconst op-+ 1) |
|
(defconst evaluation-start-address 0) |
|
(init) |
(main) |
|
(defmcop init |
(mov stack-top stack-op-start) |
(imm-mov evaluation-start-address pc) |
(mov pc car) |
(imm-mov op-none op) |
(imm-mov value state)) |
|
(defmcop main |
(imm-eq? state-value state) |
(callt eval-value) |
(imm-eq? state-arglist state) |
(callt eval-arglist) |
(imm-eq? state-apply state) |
(callt apply-primitive) |
(jmp main)) |
|
(defmcop eval-value |
(load-double car data) |
(is-pair? data) |
(callf eval-atom) |
(callt eval-pair)) |
|
(defmcop eval-atom |
(push data) ;; assume all atoms are self-evaluating |
(imm-mov state-arglist state)) |
|
(defmcop eval-pair |
(push pc) |
(push op) |
(mov stack-top stack-op-start) |
(mov-double data car) |
(load car data) |
(mov data op) |
(imm-mov state-arglist state)) |
|
|
(defmcop eval-arglist |
(is-nil? cdr) |
(imm-jmpt at-end-of-list) |
(mov cdr pc) |
(load-double pc car) |
(imm-mov state-value state) |
(return) |
(label at-end-of-list) |
(imm-mov state-apply state)) |
|
|
(defmcop apply-primitive |
(imm-eq? op-+ op) |
(callt primitive-+) |
(jmpt apply-primitive-end) |
;; more ops |
|
(label apply-primitive-end) |
(pop op) |
(pop pc) |
(push data) |
(imm-eq? op-none op) |
(callt happy-happy-joy-joy) |
(imm-mov state-arglist state) |
(load-double pc car)) |
|
|
(defmcop primitive-+ |
(pop data) |
(label primitive-+-loop) |
(> stack-top stack-op-start) |
;; todo |
) |
|
(defmcop happy-happy-joy-joy |
(halt)) |
/microprogram_assembler/gc-micro.lisp
0,0 → 1,361
;; needed variables (registers) for gc |
|
;; register values that must be predefined |
;; set these when testing gc standalone in emulator |
(defreg gc-maxblocks #x70) ;; total memory size |
(defreg gc-spaces #x71) ;; number of spaces we'll divide the memory in |
(defreg gc-startofmem #x76) ;; start of variable address space |
|
;; registers set by evaluator before invoking gc |
;; set these when testing gc standalone in emulator |
(defreg gc-rootptr #x78) ;; pointer to topmost object! hopefully |
;; there will be only one |
|
;; registers set by init, keep these throughout |
(defreg gc-spacesize #x72) ;; size of each space: maxblocks / spaces |
(defreg gc-sup #x73) ;; first address beyond legal space: |
;; spaces * spacesize (NB: can be lower than |
;; maxblocks) |
(defreg gc-gcspace #x74) ;; start of gc exclusize space, sup - spacesize |
|
;; registers used by everyone |
(defreg gc-firstfree #x75) ;; first free memory block |
;; (might exist already in other microcode) |
|
;; scratch registers, can be used when gc is not running (but gc will |
;; destroy them) |
|
(defreg gc-1 #x80) ;; temp |
(defreg gc-vi #x83) |
(defreg gc-t #x84) ;; ptr-rev |
(defreg gc-x #x85) ;; ptr-rev |
(defreg gc-y #x86) ;; ptr-rev |
(defreg gc-v #x87) ;; ptr-rev |
(defreg gc-followp #x88) ;; ptr-rev |
(defreg gc-cannext #x89) ;; ptr-rev |
(defreg gc-canprev #x8a) ;; ptr-rev |
|
(defreg gc-temp #x8b) |
(defreg gc-mem #x8c) |
(defreg gc-from #x84) ;; at this stage we're no longer using |
(defreg gc-to #x85) ;; some of the above variables |
(defreg gc-val #x86) |
(defreg gc-temp2 #x87) |
|
;;(def-gc free #x00) ;; eirik must do eirik-magic to make |
;;(def-gc used #x01) ;; these work as i want to |
(defparameter +gc-free+ #x00) |
(defparameter +gc-used+ #x01) |
|
;; initialization of gc |
;; call this before evaluator is run for the first time |
|
(defun write-microprogram (&key (output-format :simulator)) |
(with-assembly ("/tmp/microcode" :output-format output-format) |
:gc-init |
|
;; for testing, delete later |
(%set-datum-imm $one 1) |
(%set-type-imm $one +type-int+) |
(%set-datum-imm $zero 0) |
(%set-type-imm $zero +type-int+) |
|
;; temporarily commented out for testing, as this is set via register file |
;; MAGIC CONSTANTS, define max memory size here |
;; (%set-datum-imm $gc-maxblocks (* 1048576 2)) |
;; (%set-type-imm $gc-maxblocks +type-int+) |
|
;; number of spaces |
;; (%set-datum-imm $gc-spaces 10) |
;; (%set-type-imm $gc-spaces +type-int+) |
|
;; set start of gcspace (allowed heap space) |
;; (%set-datum-imm $gc-firstfree 123) ;; TODO replace with proper number |
;; (%set-type-imm $gc-firstfree +type-int+) |
|
|
|
;; calculate spacesize |
(%div* $gc-spacesize $gc-maxblocks $gc-spaces) |
|
;; find maximal address + 1 (sup) |
(%mul* $gc-sup $gc-spaces $gc-spacesize) |
|
;; find start of gcspace |
(%sub* $gc-gcspace $gc-sup $gc-spacesize) |
|
|
;; do not want to ret while testing |
;; (ret) |
|
;; garbagecollect - the entry point |
|
:gc-garbagecollect |
;; mark everything as free |
(%cpy $gc-vi $gc-startofmem) |
|
|
:gc-loop1 |
;; load the contents of memory address (contained in gc-vi) |
;; into register gc-1) |
;; loop tested in emu: OK |
(%load $gc-1 $gc-vi 0) |
(%set-gc-imm $gc-1 +gc-free+) |
(%store $gc-1 $gc-vi 0) |
(%add $gc-vi $one) |
(%cmp-datum $gc-vi $gc-gcspace) |
(branchimm-false :gc-loop1) |
|
;; pointer reversal! skrekk og gru |
;; algorithm based on tiger book |
|
;; start of pointer reversal |
;; the algorithm is able to "slide" sideways without reversing |
;; underlying pointers within the following structures |
;; CONS - SNOC |
;; ARRAY - PTR - ... - PTR - SNOC |
|
;; CONS/ARRAY are identified as start of structure |
;; SNOC is identified as end of structure |
|
(%set-type-imm $gc-t +type-int+) |
(%set-datum-imm $gc-t 0) |
(%cpy $gc-x $gc-rootptr) |
|
|
:gc-mainreverseloop |
|
;; visit current block |
;; gc-x holds current memory address |
;; gc-y will hold the contents of the address |
;; address 0x14 |
(%load $gc-y $gc-x 0) |
(%set-gc-imm $gc-y +gc-used+) |
(%store $gc-y $gc-x 0) |
|
(%cpy $gc-followp $zero) |
(%cpy $gc-cannext $zero) |
(%cpy $gc-canprev $zero) |
|
;; if memory address x contains a pointer, and it points to |
;; a memory address marked as gc-free (ie. unvisited so far) |
;; set followp to true (1) |
;; the following types have pointers: CONS PTR SNOC |
;; tested OK for case: cell is pointer, cell pointed to is unvisited |
(%cmp-type-imm $gc-y +type-cons+) |
(branchimm :gc-setfollowp) |
(%cmp-type-imm $gc-y +type-snoc+) |
(branchimm :gc-setfollowp) |
(%cmp-type-imm $gc-y +type-ptr+) |
(branchimm :gc-setfollowp) |
;; if any other types contain pointers, add them here! |
(jump-imm :gc-afterfollowp) |
|
:gc-setfollowp |
|
; copy from memory location $gc-y, into $gc-v |
(%load $gc-v $gc-y 0) |
(%cmp-gc-imm $gc-v +gc-used+) |
(branchimm :gc-afterfollowp) |
(%cpy $gc-followp $one) |
|
:gc-afterfollowp |
|
;; if we aren't at the last position of a memory structure spanning |
;; several addresses and the next adress is free, set cannext=1 |
;; currently, these types can occur at the non-end: CONS, ARRAY, PTR |
;; tested OK for case: cell is not end of structure, next cell is unvisited |
(%cmp-type-imm $gc-y +type-cons+) |
(branchimm :gc-setcannext) |
(%cmp-type-imm $gc-y +type-array+) |
(branchimm :gc-setcannext) |
(%cmp-type-imm $gc-y +type-ptr+) |
(branchimm :gc-setcannext) |
(jump-imm :gc-aftercannext) |
:gc-setcannext |
(%cpy $gc-1 $gc-x) ;; check is address x+1 is unvisited |
(%add $gc-1 $one) |
(%load $gc-1 $gc-1 0) ;; lykkebo says this is safe |
(%cmp-gc-imm $gc-1 +gc-used+) |
(branchimm :gc-aftercannext) |
(%cpy $gc-cannext $one) |
|
:gc-aftercannext |
|
;; if we aren't at the first position of a memory structure spanning |
;; several addresses, set canprev=1 |
;; the following types can occur at the non-start: SNOC PTR |
;; tested OK for case: cell is not end of structure |
(%cmp-type-imm $gc-y +type-snoc+) |
(branchimm :gc-setcanprev) |
(%cmp-type-imm $gc-y +type-ptr+) |
(branchimm :gc-setcanprev) |
(jump-imm :gc-aftercanprev) |
:gc-setcanprev |
(%cpy $gc-canprev $one) |
|
:gc-aftercanprev |
|
;; do stuff based on followp, cannext, canprev |
;; follow the pointer we're at, and reverse the pointer |
;; =====> addr 0x39 <====== |
(%cmp-datum $gc-followp $one) |
(branchimm-false :gc-afterfollowedp) |
(%cpy $gc-temp $gc-x) |
(%load $gc-mem $gc-temp 0) |
(%set-datum $gc-mem $gc-t) |
(%store $gc-mem $gc-temp 0) |
(%cpy $gc-t $gc-temp) |
(%set-datum $gc-x $gc-y) |
(jump-imm :gc-mainreverseloop) |
|
:gc-afterfollowedp |
|
;; move to next memory location |
(%cmp-datum $gc-cannext $one) |
(branchimm-false :gc-aftercouldnext) |
(%add $gc-x $one) |
(jump-imm :gc-mainreverseloop) |
|
:gc-aftercouldnext |
|
;; move to previous memory location |
(%cmp-datum $gc-canprev $one) |
(branchimm-false :gc-aftercouldprev) |
;; address 0x48 |
(%sub $gc-x $one) |
(jump-imm :gc-mainreverseloop) |
|
:gc-aftercouldprev |
|
;; all cases exhausted: follow pointer back and reverse the reversal |
(%cmp-datum $gc-t $zero) |
(branchimm :gc-donepointerreversal) |
(%load $gc-temp $gc-t 0) ;; read from address gc-t, into gc-temp |
(%cpy $gc-mem $gc-temp) |
(%set-datum $gc-mem $gc-x) |
(%store $gc-mem $gc-t 0) ;; restore the correct pointer in gc-t |
(%cpy $gc-x $gc-t) |
(%cpy $gc-t $gc-temp) |
(jump-imm :gc-mainreverseloop) |
|
:gc-donepointerreversal |
|
;; end of pointer reversal routine, from this point on, |
;; all variables marked with "ptr-rev" are free for other use |
;; ========> address 0x52 <======= |
|
;; find the first address that's going to be copied |
(%cpy $gc-from $gc-startofmem) |
(%cpy $gc-to $gc-startofmem) |
:gc-findchangeloop |
(%cmp-datum $gc-from $gc-gcspace) |
(branchimm :gc-findnextloop) |
(%load $gc-mem $gc-from 0) |
(%cmp-gc-imm $gc-mem +gc-free+) |
(branchimm :gc-findnextloop) |
(%add $gc-from $one) |
(%add $gc-to $one) |
(jump-imm :gc-findchangeloop) |
:gc-findnextloop |
;; we found the first hole, find the next element |
(%cmp-datum $gc-from $gc-gcspace) |
(branchimm :gc-copyloop) |
(%load $gc-mem $gc-from 0) |
(%cmp-gc-imm $gc-mem +gc-used+) |
(branchimm :gc-copyloop) |
(%add $gc-from $one) |
(jump-imm :gc-findnextloop) |
|
;; copy the stuff |
;; address 0x63 |
|
:gc-copyloop |
|
(%load $gc-mem $gc-from 0) ;; read from gc-from into gc-mem |
(%cmp-gc-imm $gc-mem +gc-used+) |
(branchimm-false :gc-notrans) |
;; put address in translation table |
(%cpy $gc-temp $gc-mem) |
(%div* $gc-mem $gc-from $gc-spacesize) |
(%mul $gc-mem $gc-spacesize) |
(%cpy $gc-temp2 $gc-from) |
(%sub $gc-temp2 $gc-mem) |
(%add $gc-temp2 $gc-gcspace) |
(%store $gc-to $gc-temp2 0) ;; write to-address to gc-temp2 |
;; copy |
(%load $gc-mem $gc-from 0) |
(%store $gc-temp $gc-to 0) |
(%add $gc-to $one) |
:gc-notrans |
(%add $gc-from $one) |
|
(%div* $gc-temp $gc-from $gc-spacesize) |
(%mul $gc-temp $gc-spacesize) |
(%sub* $gc-temp2 $gc-from $gc-temp) |
(%cmp-datum $gc-temp2 $zero) |
(branchimm-false :gc-noconvert) |
|
;; translate pointers |
;; address 0x79 |
:gc-transloop |
(%cpy $gc-vi $gc-startofmem) |
:gc-transloop2 |
(%load $gc-mem $gc-vi 0) ;; read from address gc-i and put into gc-mem |
(%cmp-gc-imm $gc-mem +gc-used+) |
(branchimm-false :gc-nexttrans) |
(%cmp-type-imm $gc-mem +type-ptr+) |
(branchimm :gc-isptr) |
(%cmp-type-imm $gc-mem +type-cons+) |
(branchimm :gc-isptr) |
(%cmp-type-imm $gc-mem +type-snoc+) |
(branchimm :gc-isptr) |
(jump-imm :gc-nexttrans) |
|
:gc-isptr |
;; check that these branches work |
;; OK for mem>=from-spacesize og mem<from |
(%sub* $gc-temp $gc-from $gc-spacesize) |
(%cmp-datum $gc-mem $gc-temp) |
(%branch* $zero :gc-nexttrans N) |
(%cmp-datum $gc-mem $gc-from) |
(%branch* $zero :gc-nexttrans (not N)) |
|
;; TODO replace the following section whenever (if) we get a |
;; modulo instruction! |
|
;; calculate gcspace+val%spacesize, put in val |
(%cpy $gc-val $gc-mem) |
(%div* $gc-temp $gc-val $gc-spacesize) |
(%mul $gc-temp $gc-spacesize) |
(%sub* $gc-temp2 $gc-val $gc-temp) |
(%add* $gc-val $gc-temp2 $gc-gcspace) |
(%load $gc-temp2 $gc-val 0) |
(%set-datum $gc-mem $gc-temp2) |
(%store $gc-mem $gc-vi 0) |
|
:gc-nexttrans |
(%add $gc-vi $one) |
(%cmp $gc-vi $gc-to) |
(branchimm-false :gc-noto) |
(%cpy $gc-vi $gc-from) |
:gc-noto |
(%cmp $gc-vi $gc-gcspace) |
(branchimm-false :gc-transloop2) |
|
:gc-noconvert |
|
(%cmp-datum $gc-from $gc-gcspace) |
(branchimm-false :gc-copyloop) |
|
;; whee, gc is finished and we have a new address where |
;; free space starts |
(%cpy $gc-firstfree $gc-to) |
|
;; dummy-labels |
:ret-error |
:call-error |
;; address 0x9E (as of now) |
|
(ret))) |
|
/microprogram_assembler/microprogram.lisp
0,0 → 1,2398
(in-package #:mcasm) |
|
(defparameter +microprogram-version+ #x12) |
|
(defun alloc-imm (sz) |
(%set-datum-imm $alloc-size sz) |
(alloc $alloc-size)) |
|
(defun alloc (sz-reg) |
(%cpy $alloc-addr $gc-firstfree) |
(%add $gc-firstfree sz-reg) |
(%cmp-datum $gc-firstfree $gc-mem-limit) |
;; TODO |
) |
|
(defun %store-typed (datum-reg addr-reg addr-imm type) |
(%set-type-imm $car type) |
(%set-datum $car datum-reg) |
(%store $car addr-reg addr-imm)) |
|
(defun %make-obj (result-reg datum-reg type) |
(alloc $one) |
(%store-typed datum-reg $alloc-addr 0 type) |
(%set-datum result-reg $alloc-addr)) |
|
(defun %make-char (result-reg datum-reg) |
(with-new-label ("make-char-const" constant-char) |
(with-new-label ("make-char-non-const" non-constant-char) |
(%set-datum-imm result-reg %area-chars) |
(%add result-reg datum-reg) |
(with-force-label (non-constant-char) |
(%cmp-datum-imm datum-reg +constant-chars+) |
(%branch* $zero non-constant-char (not N)) |
(%cmp-datum-imm datum-reg 0) |
(%branch* $zero non-constant-char N)) |
(jump-imm constant-char) |
(make-label non-constant-char) |
(%make-obj result-reg datum-reg +type-char+) |
(make-label constant-char)))) |
|
(defun %make-int (result-reg datum-reg) |
(with-new-label ("make-int-const" constant-int) |
(with-new-label ("make-int-non-const" non-constant-int) |
(%set-datum-imm result-reg %area-ints) |
(%add result-reg datum-reg) |
(with-force-label (non-constant-int) |
(%cmp-datum-imm datum-reg +constant-ints+) |
(%branch* $zero non-constant-int (not N)) |
(%cmp-datum-imm datum-reg 0) |
(%branch* $zero non-constant-int N)) |
(jump-imm constant-int) |
(make-label non-constant-int) |
(%make-obj result-reg datum-reg +type-int+) |
(make-label constant-int)))) |
|
(defun %load-typed (result-reg addr-reg addr-imm type err-handler) |
(%load result-reg addr-reg addr-imm) |
(%cmp-type-imm result-reg type) |
(branchimm-false err-handler)) |
|
(defun %cons (result-reg car-reg cdr-reg) |
(%set-type-imm $car +type-cons+) |
(%set-type-imm $cdr +type-snoc+) |
(%set-datum $car car-reg) |
(%set-datum $cdr cdr-reg) |
(alloc $two) |
(%store $car $alloc-addr 0) |
(%store $cdr $alloc-addr 1) |
(%set-datum result-reg $alloc-addr)) |
|
(defun %car (result-reg cons-reg err-handler) |
(%load result-reg cons-reg 0) |
(%cmp-type-imm result-reg +type-cons+) |
(branchimm-false err-handler)) |
|
(defun %cdr (result-reg cons-reg err-handler) |
;; TODO should check that cons-reg actually points to a cons |
;; cell |
(%load result-reg cons-reg 1) |
(%cmp-type-imm result-reg +type-snoc+) |
(branchimm-false err-handler)) |
|
(defun call (addr) |
(with-new-label ("call" return-addr) |
(%cmp-datum-imm $mc-stack-top $mc-stack-max) |
(branchimm :call-error) |
(let ((return-addr return-addr)) |
(force-label return-addr) |
(%set-datum-imm (indirect-register $mc-stack-top) return-addr)) |
(%add $mc-stack-top $one) |
(jump-imm addr) |
(make-label return-addr))) |
|
(defun ret () |
(%cmp-datum-imm $mc-stack-top $mc-stack-min) |
(branchimm :ret-error) |
(%sub $mc-stack-top $one) |
(jump-reg (indirect-register $mc-stack-top))) |
|
(defun %error-imm (error-type) |
(%set-datum-imm $car %error) |
(%set-datum-imm $cdr error-type) |
(%cons $s-condition $car $cdr) |
(%set-datum-imm $mc-stack-top $mc-stack-min) |
(call :interrupt) |
(jump-imm :main-loop-end)) |
|
(defun %error (error-type-reg) |
(%set-datum-imm $car %error) |
(%cons $s-condition $car error-type-reg) |
(%set-datum-imm $mc-stack-top $mc-stack-min) |
(call :interrupt) |
(jump-imm :main-loop-end)) |
|
(defun select-device (devnr-reg) |
(%when-not (%cmp-datum $io-devnr devnr-reg) |
(%cpy $io-devnr devnr-reg) |
(%store $io-devnr $io-mem-addr %io-curdev))) |
|
(defun select-device-imm (devnr) |
(%when-not (%cmp-datum-imm $io-devnr devnr) |
(%set-datum-imm $io-devnr devnr) |
(%store $io-devnr $io-mem-addr %io-curdev))) |
|
(defun message (msg-reg) ; output a char from a register |
(select-device-imm +dev-serial+) |
(%store msg-reg $io-mem-addr %io-object)) |
|
(defun message-reg-no-nl (reg) |
(%set-datum $message reg) |
(call :message-reg)) |
|
(defun message-reg (reg) ; output an integer from a register |
(message-reg-no-nl reg) |
(message-imm #\Return) |
(message-imm #\Newline)) |
|
(defun message-imm (msg) ; output an immediate character |
(%set-type-imm $message +type-char+) |
(%set-datum-imm $message (char-int msg)) |
(message $message)) |
|
(defun message-str-no-nl (str) |
(%set-type-imm $message +type-char+) |
(select-device-imm +dev-serial+) |
(loop for ch across str do |
(%set-datum-imm $message (char-int ch)) |
(%store $message $io-mem-addr %io-object))) |
|
(defun message-str (str) |
(message-str-no-nl str) |
(message-imm #\Return) |
(message-imm #\Newline)) |
|
(defun e-expr () (indirect-register $e-expr)) |
(defun e-arg () (indirect-register $e-arg)) |
(defun e-result () (indirect-register $e-result)) |
(defun e-phase () (indirect-register $e-phase)) |
|
(defun push-eframe () |
(with-new-label ("push-eframe-free-frame" push-eframe-free-frame) |
(%add $e-expr $e/f-frame-size) |
(%add $e-arg $e/f-frame-size) |
(%add $e-result $e/f-frame-size) |
(%add $e-phase $e/f-frame-size) |
|
;; new frame in use or above top? |
(%cmp-type-imm (indirect-register $e-expr) +type-none+) |
;; if so, call the subroutine to handle such cases |
(branchimm push-eframe-free-frame) |
(call :push-eframe-handle-overflow) |
(make-label push-eframe-free-frame) |
|
(%set-type-imm (e-expr) +type-cons+) |
(%set-datum-imm (e-arg) %nil) |
(%set-datum-imm (e-result) %nil))) ; caller must set $e-expr, $e-phase |
|
(defun pop-eframe () |
(with-new-label ("pop-eframe-start" pop-eframe-start) |
(with-new-label ("pop-eframe-non-empty-frame" pop-eframe-non-empty-frame) |
(with-new-label ("pop-eframe-not-func-frame" pop-eframe-not-func-frame) |
(make-label pop-eframe-start) |
(%set-type-imm (indirect-register $e-expr) +type-none+) |
|
(%sub $e-expr $e/f-frame-size) |
(%sub $e-arg $e/f-frame-size) |
(%sub $e-result $e/f-frame-size) |
(%sub $e-phase $e/f-frame-size) |
|
;; is this frame empty or below bottom? |
(%cmp-type-imm (indirect-register $e-expr) +type-none+) |
(branchimm-false pop-eframe-non-empty-frame) |
(call :pop-eframe-handle-underflow) |
(make-label pop-eframe-non-empty-frame) |
|
(%cmp-type-imm (indirect-register $e-expr) +type-function+) |
(branchimm-false pop-eframe-not-func-frame) |
(%set-datum $f-func (indirect-register $e-expr)) |
(%set-datum $f-env (indirect-register $e-arg)) |
(jump-imm pop-eframe-start) |
(make-label pop-eframe-not-func-frame))))) |
|
|
|
(defun write-microprogram (&key (output-format :simulator)) |
(with-assembly ("/tmp/microcode" :output-format output-format) |
:init |
|
;; I/O init: |
(%load $io-devnr $io-mem-addr %io-curdev) |
|
(message-str (format nil "IGOREV INIT v. 0x~X" +microprogram-version+)) |
|
|
;; write initial data to memory: |
|
;; nil/t/symbols, strings: |
(%store $init1 $zero %nil) |
|
;; (message-str "READ NIL,") |
;; (%load $tmp1 $zero %nil) |
;; (message-reg $tmp1) |
;; (%get-type $tmp2 $tmp1) |
;; (message-reg $tmp2) |
|
(%store $init2 $zero 1) |
(%set-type-imm $init1 +type-ptr+) |
(%set-type-imm $init2 +type-ptr+) |
(%set-type-imm $init3 +type-ptr+) |
:init-mem-symbols-loop |
(%set-datum $init1 (indirect-register $init-counter)) |
(%shift-r $init1 $init-shift1) |
(%set-datum $init2 (indirect-register $init-counter)) |
(%shift-r $init2 $init-shift2) |
(%and $init2 $init-char-mask) |
(%set-datum $init3 (indirect-register $init-counter)) |
(%and $init3 $init-char-mask) |
(%set-type-imm (indirect-register $init-counter) 0) |
(%set-datum-imm (indirect-register $init-counter) 0) |
(%set-datum-imm $init-counter2 $init1) |
:init-mem-symbols-loop2 |
(%cmp-datum-imm (indirect-register $init-counter2) 0) |
(branchimm :init-mem-symbols-end-symbol) |
(%add (indirect-register $init-counter2) $init-chars-start) |
(%incr $init-symbol-char-addr) |
(%store (indirect-register $init-counter2) $init-symbol-char-addr 0) |
:init-mem-symbols-loop2-continue |
(%cmp-datum-imm $init-counter2 $init3) |
(branchimm :init-mem-symbols-loop2-end) |
(%incr $init-counter2) |
(jump-imm :init-mem-symbols-loop2) |
:init-mem-symbols-end-symbol |
(%store-typed $zero $init-symbol-addr 0 +type-none+) ; in case there is no symbol |
(%sub* $init-symbol-array $init-symbol-char-addr $init-symbol-str-addr) |
(branchimm |
:init-mem-symbols-end-symbol-next) ; if there are no characters, |
; just skip to the next symbol |
(%set-type-imm $init-symbol-array +type-array+) |
(%store $init-symbol-array $init-symbol-str-addr 0) |
(%store $list-terminator $init-symbol-char-addr 1) |
(%store-typed $init-symbol-str-addr $init-symbol-addr 0 +type-symbol+) |
(%add $init-symbol-char-addr 2) |
(%set-datum $init-symbol-str-addr $init-symbol-char-addr) |
:init-mem-symbols-end-symbol-next |
(%incr $init-symbol-addr) |
(jump-imm :init-mem-symbols-loop2-continue) |
:init-mem-symbols-loop2-end |
(%incr $init-counter) |
(%cmp-type-imm (indirect-register $init-counter) +type-int+) |
(branchimm :init-mem-symbols-loop) |
|
;; builtins: |
(%set-type-imm $init1 +type-builtin+) |
(%set-datum-imm $init1 +first-builtin+) |
:init-mem-builtins-loop |
(%store $init1 $init1 %area-builtins) |
(%cmp-datum-imm $init1 +last-builtin+) |
(branchimm :init-mem-builtins-loop-end) |
(%incr $init1) |
(jump-imm :init-mem-builtins-loop) |
:init-mem-builtins-loop-end |
|
;; characters: |
(%set-type-imm $init1 +type-char+) |
(%set-datum-imm $init1 0) |
:init-mem-chars-loop |
(%store $init1 $init1 %area-chars) |
(%incr $init1) |
(%cmp-datum-imm $init1 +constant-chars+) |
(branchimm-false :init-mem-chars-loop) |
|
;; ints: |
(%set-type-imm $init1 +type-int+) |
(%set-datum-imm $init1 0) |
:init-mem-ints-loop |
(%store $init1 $init1 %area-ints) |
(%incr $init1) |
(%cmp-datum-imm $init1 +constant-ints+) |
(branchimm-false :init-mem-ints-loop) |
|
;; symbol list: |
(%set-type-imm $init1 +type-cons+) |
(%set-type-imm $init2 +type-snoc+) |
(%set-datum-imm $init1 2) ; init1: address of symbol |
(%set-datum-imm $init2 (+ %area-symlist 2)) ; init2: address of next cons cell |
:init-mem-symlist-loop |
(%load $init3 $init1 0) ; init3: current symbol |
(%cmp-type-imm $init3 +type-none+) |
(branchimm |
:init-mem-symlist-loop-continue) ; skip to next if no symbol |
; (there may be gaps) |
(%store $init1 $init2 -2) |
(%store $init2 $init2 -1) |
(%add $init2 $two) |
:init-mem-symlist-loop-continue |
(%incr $init1) |
(%cmp-datum-imm $init1 +last-symbol+) |
(branchimm-false :init-mem-symlist-loop) |
(%store $init1 $init2 -2) |
(%store $list-terminator $init2 -1) |
|
;; memory root pointer: |
(%set-type-imm $tmp1 +type-cons+) |
(%set-datum-imm $tmp1 %nil) |
(%store $tmp1 $zero %memory-root) |
(%store $list-terminator $zero (+ %memory-root 1)) |
;; end memory initialization |
|
;; most essential initialization: |
(%set-type-imm $zero +type-int+) |
(%set-datum-imm $zero 0) |
|
(%set-type-imm $one +type-int+) |
(%set-datum-imm $one 1) |
|
(%set-type-imm $two +type-int+) |
(%set-datum-imm $two 2) |
|
;; (%set-type-imm $list-terminator +type-snoc+) |
;; (%set-datum-imm $list-terminator 0) |
|
(%set-type-imm $mc-stack-top +type-int+) |
(%set-datum-imm $mc-stack-top $mc-stack-min) |
|
;;(make-integer $gc-firstfree #x20000) |
(%set-type-imm $alloc-size +type-int+) |
(%set-type-imm $alloc-addr +type-int+) |
|
;; (%set-type-imm $io-mem-addr +type-int+) |
;; (%set-datum-imm $io-mem-addr #x3FFFF) |
;; (%set-datum-imm $tmp1 #x8) |
;; (%shift $io-mem-addr $tmp1) |
;; end most essential initialization |
|
|
(message-str-no-nl "BOOT: ") |
:boot |
(select-device-imm +dev-boot+) |
(%load $tmp1 $io-mem-addr %io-size-l) ; $tmp1: boot program size |
(message-reg-no-nl $tmp1) (message-str " WORDS") |
(select-device-imm +dev-boot+) |
;; (%cmp-datum-imm $tmp1 0) ; temporary to avoid loading boot program |
;; (branchimm :boot-end) |
(%set-type-imm $tmp2 +type-int+) |
(%set-datum-imm $tmp2 0) ; $tmp2: address counter |
(%store $tmp2 $io-mem-addr %io-addr-l) |
:boot-loop |
(%set-datum-imm $tmp4 #xFF) |
(%and $tmp4 $tmp2) |
(%cmp-datum-imm $tmp4 0) |
(branchimm-false :boot-loop-no-print) |
(message-reg-no-nl $tmp2) |
(message-imm #\Return) |
(select-device-imm +dev-boot+) |
:boot-loop-no-print |
|
(%load $tmp3 $io-mem-addr %io-object) |
(%store $tmp3 $tmp2 %boot-prog-start) |
(%incr $tmp2) |
;;(message-reg $tmp2) (select-device-imm +dev-boot+) |
(%cmp-datum $tmp2 $tmp1) |
(branchimm-false :boot-loop) |
(%set-datum-imm $gc-firstfree %boot-prog-start) |
(%add $gc-firstfree $tmp2) |
:boot-end |
(message-str "COMPLETE") |
|
|
;; start GC initialization |
(%set-datum-imm $gc-rootptr %memory-root) |
|
(%set-datum-imm $gc-startofmem (- %mem-reserved-top 2)) ; include root pointer |
|
;; number of spaces |
(%set-datum-imm $gc-spaces +gc-spaces+) |
(%set-type-imm $gc-spaces +type-int+) |
|
;; calculate spacesize |
;; set this manually for now! not easy to replace div |
;;(%set-datum-imm $gc-spacesize (/ (* 1048576 2) +gc-spaces+)) |
;; (%div* $gc-spacesize $gc-maxblocks $gc-spaces) |
|
;; find maximal address + 1 (sup) |
(%mul* $gc-sup $gc-spaces $gc-spacesize) |
|
;; find start of gcspace |
(%sub* $gc-gcspace $gc-sup $gc-spacesize) |
|
(%set-datum-imm $tmp1 +gc-limit+) |
(%sub* $gc-mem-limit $gc-gcspace $tmp1) |
;; end GC initialization |
|
|
;; initialize evaluation stacks: |
(%set-datum-imm $e/f-frame-size 4) |
(%set-type-imm $e/f-below-marker +type-none+) |
(%set-type-imm $e/f-above-marker +type-cons+) |
|
(%set-datum-imm $tmp1 $e/f-min) |
:clear-e/f-loop |
(%set-type-imm (indirect-register $tmp1) +type-none+) |
(%set-datum-imm (indirect-register $tmp1) 0) |
(%add $tmp1 $one) |
(%cmp-datum-imm $tmp1 $e/f-max) |
(branchimm-false :clear-e/f-loop) |
|
(call :init-evaluation-level) |
|
;; set current expression and environment to boot program's |
;; expression and environment: |
(%set-datum-imm $tmp1 %boot-prog-start) |
(%car (e-expr) $tmp1 :err-not-a-pair) |
(%cdr $f-env $tmp1 :err-not-a-pair) |
(%set-datum-imm (e-phase) %phase-eval) |
|
|
|
;; (message-str "NIL IS ") |
;; (%load $tmp1 $zero %nil) |
;; (message-reg $tmp1) |
;; (message-str "TYPE ") |
;; (%get-type $tmp2 $tmp1) |
;; (message-reg $tmp2) |
;; (message-str "T IS ") |
;; (%load $tmp1 $zero 1) |
;; (message-reg $tmp1) |
;; (message-str "TYPE ") |
;; (%get-type $tmp2 $tmp1) |
;; (message-reg $tmp2) |
;; (message-str "IF IS ") |
;; (%load $tmp1 $zero 2) |
;; (message-reg $tmp1) |
;; (message-str "TYPE ") |
;; (%get-type $tmp2 $tmp1) |
;; (message-reg $tmp2) |
;; (message-str "CONS IS ") |
;; (%load $tmp1 $zero 6) |
;; (message-reg $tmp1) |
;; (message-str "TYPE ") |
;; (%get-type $tmp2 $tmp1) |
;; (message-reg $tmp2) |
;; (message-str "PHASE-EVAL IS ") |
;; (%load $tmp1 $zero #x40) |
;; (message-reg $tmp1) |
;; (message-str "TYPE ") |
;; (%get-type $tmp2 $tmp1) |
;; (message-reg $tmp2) |
;; (message-str "CONS FUNCTION IS ") |
;; (%load $tmp1 $zero #x106) |
;; (message-reg $tmp1) |
;; (message-str "TYPE ") |
;; (%get-type $tmp2 $tmp1) |
;; (message-reg $tmp2) |
|
|
|
|
:main-loop |
|
;; check that phase is valid: |
(%cmp-datum-imm (e-phase) +first-phase+) |
(%branch* $zero :err-invalid-phase N) |
(%cmp-datum-imm (e-phase) (+ +last-phase+ 1)) |
(%branch* $zero :err-invalid-phase (not N)) |
|
;;dispatch: |
(let ((label :phase-dispatch-table)) |
(force-label label) |
(jump (e-phase) (- label +first-phase+))) |
|
:phase-dispatch-table |
(jump-imm :p-eval) |
(jump-imm :p-eval-args) |
(jump-imm :p-apply) |
(jump-imm :p-eval-if) |
(jump-imm :p-initial) |
(jump-imm :p-env-lookup) |
(jump-imm :p-env-lookup-local) |
(jump-imm :p-apply-function2) |
(jump-imm :p-bind-args) |
(jump-imm :p-eval-progn) |
(jump-imm :p-eval-args-top) |
(jump-imm :p-eval-args-cdr) |
(jump-imm :p-eval-args-cons) |
(jump-imm :p-eval-symbol) |
(jump-imm :p-set!) |
|
|
;; PHASE: EVAL |
|
:p-eval |
(%load $car (e-expr) 0) |
(%cmp-type-imm $car +type-cons+) |
(branchimm :p-eval-form) |
(%cmp-type-imm $car +type-symbol+) |
(branchimm :p-eval-symbol1) |
:p-eval-self-evaluating |
(%cpy $tmp1 (e-expr)) |
(pop-eframe) |
(%set-datum (e-result) $tmp1) |
(jump-imm :main-loop-end) |
|
|
:p-eval-symbol1 |
(%cmp-datum-imm (e-expr) +first-magic-var+) |
(%branch* $zero :p-eval-symbol1-regular-var N) |
(%cmp-datum-imm (e-expr) (+ +last-magic-var+ 1)) |
(%branch* $zero :p-eval-symbol1-regular-var (not N)) |
|
:p-eval-symbol1-magic-var |
(%set-datum-imm $tmp1 %area-builtins) |
(%add $tmp1 (e-expr)) |
(pop-eframe) |
(%set-datum (e-result) $tmp1) |
;; (%when (%cmp-datum-imm (e-expr) %symbol-table) |
;; (%set-datum-imm (e-result) %area-symlist)) |
(jump-imm :main-loop-end) |
|
:p-eval-symbol1-regular-var |
(%set-datum $tmp1 (e-expr)) |
(%set-datum-imm (e-phase) %phase-eval-symbol) |
(push-eframe) |
(%set-datum (e-expr) $tmp1) |
(%set-datum (e-arg) $f-env) |
(%set-datum-imm (e-phase) %phase-env-lookup) |
(jump-imm :main-loop-end) |
|
|
:p-eval-form |
(%load $car (e-expr) 0) |
(%load $cdr (e-expr) 1) |
(%cmp-datum-imm $car %quote) |
(branchimm :p-eval-form-quote) |
(%cmp-datum-imm $car %if) |
(branchimm :p-eval-form-if) |
(%cmp-datum-imm $car %lambda) |
(branchimm :p-eval-form-lambda) |
(%cmp-datum-imm $car %progn) |
(branchimm :p-eval-progn1) |
|
:p-eval-form-function |
(%set-datum-imm (e-phase) %phase-eval-args-top) |
(%set-datum $tmp1 $car) |
(push-eframe) |
(%set-datum (e-expr) $tmp1) |
(%set-datum-imm (e-phase) %phase-eval) |
(jump-imm :main-loop-end) |
|
:p-eval-form-quote |
(%set-datum $tmp1 $cdr) |
(pop-eframe) |
(%load $car $tmp1 0) |
(%set-datum (e-result) $car) |
(jump-imm :main-loop-end) |
|
:p-eval-form-lambda ; (%lambda name param-list expr) |
;; TODO check args |
;; TODO take name as additional argument |
(%car $tmp1 $cdr :err-not-a-list) ; $tmp1: name |
(%cdr $cdr $cdr :err-not-a-list) ; $cdr: (param-list expr) |
(%car $tmp2 $cdr :err-not-a-list) ; $tmp2: param-list |
(%cdr $cdr $cdr :err-not-a-list) ; $cdr: (expr) |
(%car $tmp3 $cdr :err-not-a-list) ; $tmp3: expr |
(%cdr $cdr $cdr :err-not-a-list) |
(%cmp-datum-imm $cdr %nil) |
(branchimm-false :err-too-many-args) |
(%cons $tmp4 $f-env $list-terminator) ; $tmp4: (env) |
(%cons $tmp4 $tmp3 $tmp4) ; $tmp4: (expr env) |
(%cons $tmp4 $tmp2 $tmp4) ; $tmp4: (param-list expr env) |
(%cons $tmp4 $tmp1 $tmp4) ; $tmp4: (name param-list expr env) |
(%make-obj $tmp1 $tmp4 +type-function+) ; $tmp1: function (address) |
(pop-eframe) |
(%set-datum (e-result) $tmp1) |
(jump-imm :main-loop-end) |
|
:p-eval-form-if ; (%if test a b) |
(%load $tmp1 $cdr 0) |
;;(%load $cdr $cdr 1) |
(%set-datum-imm (e-phase) %phase-eval-if) |
(push-eframe) |
(%set-datum (e-expr) $tmp1) |
(%set-datum-imm (e-phase) %phase-eval) |
(jump-imm :main-loop-end) |
|
|
;; PHASE: EVAL-IF |
|
:p-eval-if ; (%if test a b) caddr, cadddr |
(%load $cdr (e-expr) 1) |
(%load $cdr $cdr 1) ;; cddr |
(%cmp-datum-imm (e-result) %nil) |
(branchimm-false :p-eval-if-true) |
(%load $cdr $cdr 1) ;; cdddr |
:p-eval-if-true |
(%load $car $cdr 0) ;; caddr/cadddr |
(%set-datum (e-expr) $car) |
(%set-datum-imm (e-phase) %phase-eval) |
(jump-imm :main-loop-end) |
|
|
;; PHASE: EVAL-PROGN |
|
:p-eval-progn1 ; this first part belongs to EVAL phase |
(%set-datum (e-arg) $cdr) |
(%set-datum-imm (e-result) %nil) |
(%set-datum-imm (e-phase) %phase-eval-progn) |
:p-eval-progn ; (%progn form ...) |
(%cmp-datum-imm (e-arg) %nil) |
(branchimm :p-eval-progn-empty) |
(%car $tmp1 (e-arg) :err-not-a-list) ; $tmp1: first argument |
(%cdr (e-arg) (e-arg) :err-not-a-list) |
(%cmp-datum-imm (e-arg) %nil) |
(branchimm :p-eval-progn-last) |
;; more than one argument: |
(push-eframe) |
(%set-datum (e-expr) $tmp1) |
(%set-datum-imm (e-phase) %phase-eval) |
(jump-imm :main-loop-end) |
:p-eval-progn-empty ; no arguments |
(pop-eframe) |
(%set-datum-imm (e-result) %nil) |
(jump-imm :main-loop-end) |
:p-eval-progn-last ; exactly one argument, eval it in this eframe |
(%set-datum (e-expr) $tmp1) |
(%set-datum-imm (e-arg) %nil) |
(%set-datum-imm (e-result) %nil) |
(%set-datum-imm (e-phase) %phase-eval) |
(jump-imm :main-loop-end) |
|
|
;; PHASE: EVAL-SYMBOL |
|
:p-eval-symbol |
(%cmp-datum-imm (e-result) %nil) |
(branchimm :err-unbound-symbol) |
(%cdr $tmp1 (e-result) :err-invalid-state) |
(pop-eframe) |
(%set-datum (e-result) $tmp1) |
(jump-imm :main-loop-end) |
|
|
;; PHASES: EVAL-ARGS, EVAL-ARGS-{TOP,CDR,CONS} |
|
:p-eval-args-top |
(%set-datum (e-arg) (e-result)) ; copy function pointer to (e-arg) |
(%set-datum-imm (e-phase) %phase-apply) |
(%cdr $tmp1 (e-expr) :err-malformed-form) |
(push-eframe) |
(%set-datum-imm (e-phase) %phase-eval-args) |
(%set-datum (e-expr) $tmp1) |
(jump-imm :main-loop-end) |
|
:p-eval-args |
(%cmp-datum-imm (e-expr) %nil) |
(branchimm :p-eval-args-empty-list) |
(%car $tmp1 (e-expr) :p-eval-args-error) |
(%set-datum-imm (e-phase) %phase-eval-args-cdr) |
(push-eframe) |
(%set-datum (e-expr) $tmp1) |
(%set-datum-imm (e-phase) %phase-eval) |
(jump-imm :main-loop-end) |
:p-eval-args-empty-list |
(pop-eframe) |
(%set-datum-imm (e-result) %nil) |
(jump-imm :main-loop-end) |
;; (%set-datum (e-arg) (e-result)) |
;; (%load $cdr (e-expr) 1) |
;; (%cmp-datum-imm $cdr %nil) |
;; (branchimm :p-apply1) |
;; (%load $cdr $cdr 1) |
;; (%load $car $cdr 0) |
;; (%set-datum-imm (e-phase) %phase-apply) |
;; (call :push-e) |
;; (%set-datum (e-expr) $car) |
;; (jump-imm :main-loop-end) |
|
:p-eval-args-cdr |
(%set-datum (e-arg) (e-result)) |
(%cdr $tmp1 (e-expr) :p-eval-args-error) |
(%set-datum-imm (e-phase) %phase-eval-args-cons) |
(push-eframe) |
(%set-datum (e-expr) $tmp1) |
(%set-datum-imm (e-phase) %phase-eval-args) |
(jump-imm :main-loop-end) |
|
:p-eval-args-cons |
(%cons $tmp1 (e-arg) (e-result)) |
(pop-eframe) |
(%set-datum (e-result) $tmp1) |
(jump-imm :main-loop-end) |
|
:p-eval-args-error ; common to p-eval-args, p-eval-args-cdr, p-eval-args-cons |
(%error %err-invalid-arg-list) |
|
|
;; PHASE: ENV-LOOKUP |
|
:p-env-lookup |
;; (e-expr): variable name (address) |
;; (e-arg): env (address) |
(%cmp-datum-imm (e-result) %nil) |
(branchimm-false :p-env-lookup-ret) |
(%cmp-datum-imm (e-arg) %nil) |
(branchimm :p-env-lookup-ret) |
;;(branchimm :err-unbound-symbol) |
(%set-datum $tmp1 (e-expr)) |
(%car $tmp2 (e-arg) :err-invalid-env) |
(%cdr (e-arg) (e-arg) :err-invalid-env) |
(push-eframe) |
(%set-datum (e-expr) $tmp1) |
(%set-datum (e-arg) $tmp2) |
(%set-datum-imm (e-phase) %phase-env-lookup-local) |
(jump-imm :main-loop-end) |
:p-env-lookup-ret |
(%set-datum $tmp1 (e-result)) |
(pop-eframe) |
(%set-datum (e-result) $tmp1) |
(jump-imm :main-loop-end) |
|
|
;; PHASE: ENV-LOOKUP-LOCAL |
|
:p-env-lookup-local |
;; (e-expr): variable name (address) |
;; (e-arg): env binding list (address) |
(%set-datum-imm $tmp1 %nil) |
(%cmp-datum-imm (e-arg) %nil) |
(branchimm :p-env-lookup-local-ret) |
(%car $tmp1 (e-arg) :err-invalid-env) ; $tmp1: (symbol . value) |
(%car $tmp2 $tmp1 :err-invalid-env) ; $tmp2: symbol |
(%cmp-datum $tmp2 (e-expr)) |
(branchimm :p-env-lookup-local-ret) |
(%cdr (e-arg) (e-arg) :err-invalid-env) |
(jump-imm :main-loop-end) |
:p-env-lookup-local-ret |
(pop-eframe) |
(%set-datum (e-result) $tmp1) |
(jump-imm :main-loop-end) |
|
|
;; PHASE: BIND-ARGS |
|
:p-bind-args |
;; (e-expr): existing bindings |
;; (e-arg): (rest of) param list |
;; (e-result): (rest of) arg list |
(%load $params-car (e-arg) 0) |
;; dispatch on type of param list: |
(%cmp-type-imm $params-car +type-cons+) |
(branchimm :p-bind-args-head) |
(%cmp-type-imm $params-car +type-nil+) |
(branchimm :p-bind-args-empty) |
(%cmp-type-imm $params-car +type-symbol+) |
(branchimm :p-bind-args-tail) |
(jump-imm :err-invalid-param-list) |
|
:p-bind-args-head |
;; param list is of form (p1 . rest). check that arg list has form |
;; (a1 . rest) and that p1 is actually a symbol. if so, bind p1 to |
;; a1 and continue cdr-ing down both lists: |
(%load $tmp1 $params-car 0) |
(%cmp-type-imm $tmp1 +type-symbol+) |
(branchimm-false :err-invalid-param-list) |
(%load $args-car (e-result) 0) |
(%cmp-type-imm $args-car +type-cons+) |
(branchimm-false :err-too-few-args) |
;; make a binding (p1 . a1): |
(%cons $tmp1 $params-car $args-car) |
;; cons the new binding on the list: |
(%cons (e-expr) $tmp1 (e-expr)) |
;; cdr down param and arg list: |
(%load (e-arg) (e-arg) 1) |
(%load (e-result) (e-result) 1) |
(jump-imm :main-loop-end) |
|
:p-bind-args-tail |
;; param list is of form p1, that is, just a single symbol; so |
;; bind this to the whole arglist and return: |
(%cons $tmp1 (e-arg) (e-result)) |
(%cons $tmp1 $tmp1 (e-expr)) |
(pop-eframe) |
(%set-datum (e-result) $tmp1) |
(jump-imm :main-loop-end) |
|
:p-bind-args-empty |
;; empty param list; check that arg list is empty too, and return: |
(%cmp-datum-imm (e-result) %nil) |
(branchimm-false :err-too-many-args) |
(%set-datum $tmp1 (e-expr)) |
(pop-eframe) |
(%set-datum (e-result) $tmp1) |
(jump-imm :main-loop-end) |
|
|
;; PHASE: APPLY |
|
:p-apply |
;; (e-arg): function (address) |
;; (e-result): argument list (address) |
(%load $apply-func (e-arg) 0) |
(%cmp-type-imm $apply-func +type-builtin+) |
(branchimm :p-apply-builtin) |
(%cmp-type-imm $apply-func +type-function+) |
(branchimm :p-apply-function1) |
(%error-imm %err-not-a-function) |
|
:p-apply-builtin ; $apply-func contains the identifier of the |
; function (the adress of the symbol used for |
; naming it), use this as offset into the table |
; below |
(%set-type-imm $builtin-arg1 +type-none+) |
(%set-type-imm $builtin-arg2 +type-none+) |
(%set-type-imm $builtin-arg3 +type-none+) |
|
;; check builtin identifier: |
(%cmp-datum-imm $apply-func +first-builtin+) |
(%branch* $zero :err-invalid-builtin N) |
(%cmp-datum-imm $apply-func (+ +last-builtin+ 1)) |
(%branch* $zero :err-invalid-builtin (not N)) |
|
(let ((label :p-apply-table)) |
(force-label label) |
(jump $apply-func (- label +first-builtin+))) |
:p-apply-table |
(jump-imm :builtin-cons) |
(jump-imm :builtin-car) |
(jump-imm :builtin-cdr) |
(jump-imm :builtin-eval) |
(jump-imm :builtin-apply) |
(jump-imm :builtin-type) |
(jump-imm :builtin-make-array) |
(jump-imm :builtin-array-size) |
(jump-imm :builtin-array-get) |
(jump-imm :builtin-array-set) |
(jump-imm :builtin-make-symbol) |
(jump-imm :builtin-symbol-to-string) |
(jump-imm :builtin-char-to-int) |
(jump-imm :builtin-int-to-char) |
(jump-imm :builtin-get-char) |
(jump-imm :builtin-put-char) |
(jump-imm :builtin-num-devices) |
(jump-imm :builtin-device-type) |
(jump-imm :builtin-set-address) |
(jump-imm :builtin-get-address) |
(jump-imm :builtin-error) |
(jump-imm :builtin-add) |
(jump-imm :builtin-sub) |
(jump-imm :builtin-mul) |
(jump-imm :builtin-div) |
(jump-imm :builtin-bitwise-and) |
(jump-imm :builtin-bitwise-or) |
(jump-imm :builtin-bitwise-not) |
(jump-imm :builtin-bitwise-shift) |
(jump-imm :builtin-current-environment) |
(jump-imm :builtin-make-eval-state) |
(jump-imm :builtin-eval-partial) |
(jump-imm :builtin-define) |
(jump-imm :builtin-undefine) |
(jump-imm :builtin-eq?) |
(jump-imm :builtin-num-eq?) |
(jump-imm :builtin-char-eq?) |
(jump-imm :builtin-less-than?) |
(jump-imm :builtin-mod) |
(jump-imm :builtin-set!) |
(jump-imm :builtin-set-car!) |
(jump-imm :builtin-set-cdr!) |
(jump-imm :builtin-function-data) |
(jump-imm :builtin-builtin-name) |
(jump-imm :builtin-device-size) |
(jump-imm :builtin-device-status) |
|
:builtin-cons ; (%cons obj1 obj2) |
(%set-type-imm $builtin-arg1 +type-t+) |
(%set-type-imm $builtin-arg2 +type-t+) |
(call :fetch-args) |
(%cons $apply-result $builtin-arg1 $builtin-arg2) |
(jump-imm :p-apply-end) |
|
:builtin-car ; (%car cons-cell) |
(%set-type-imm $builtin-arg1 +type-cons+) |
(call :fetch-args) |
(%set-datum $apply-result $builtin-arg1-val) |
(jump-imm :p-apply-end) |
|
:builtin-cdr ; (%cdr cons-cell) |
(%set-type-imm $builtin-arg1 +type-cons+) |
(call :fetch-args) |
(%load $apply-result $builtin-arg1 1) |
(jump-imm :p-apply-end) |
|
:builtin-eq? ; (%eq? obj1 obj2) |
(%set-type-imm $builtin-arg1 +type-t+) |
(%set-type-imm $builtin-arg2 +type-t+) |
(call :fetch-args) |
(%set-datum-imm $apply-result %nil) |
(when= ($builtin-arg1 $builtin-arg2) |
(%set-datum-imm $apply-result %t)) |
(jump-imm :p-apply-end) |
|
:builtin-type ; (%type obj) |
(%set-type-imm $builtin-arg1 +type-t+) |
(call :fetch-args) |
(%get-type $tmp1 $builtin-arg1-val) |
(%make-obj $apply-result $tmp1 +type-int+) |
(jump-imm :p-apply-end) |
|
:builtin-eval ; (%eval expr env) |
(%set-type-imm $builtin-arg1 +type-t+) |
(%set-type-imm $builtin-arg2 +type-t+) |
(call :fetch-args) |
(%set-datum $apply-eval-expr $builtin-arg1) |
(%set-datum $apply-eval-env $builtin-arg2) |
(call :push-or-reuse-fframe) |
(%set-datum-imm $f-func %eval) ; should maybe have a dedicated symbol for this |
(%set-datum $f-env $apply-eval-env) |
(%set-datum (e-expr) $apply-eval-expr) |
(%set-datum-imm (e-phase) %phase-eval) |
(jump-imm :main-loop-end) ; note: not :p-apply-end |
|
:builtin-apply ; (%apply func args) |
;; move stuff around and go through APPLY phase again: |
(%set-type-imm $builtin-arg1 +type-t+) ; function or builtin |
(%set-type-imm $builtin-arg2 +type-t+) ; list (cons or nil) |
(call :fetch-args) |
(%set-datum (e-arg) $builtin-arg1) |
(%set-datum (e-result) $builtin-arg2) |
(jump-imm :main-loop-end) |
|
:builtin-make-array ; (%make-array size init-value) |
(%set-type-imm $builtin-arg1 +type-int+) |
(%set-type-imm $builtin-arg2 +type-t+) |
(call :fetch-args) |
;; TODO check size |
(%set-datum $tmp1 $builtin-arg1-val) |
(%add $tmp1 $two) ; $tmp1: words needed (array object + pointers + end marker) |
(alloc $tmp1) |
(%store-typed $builtin-arg1-val $alloc-addr 0 +type-array+) |
(%add $tmp1 $alloc-addr) |
(%decr $tmp1) ; $tmp1: address of end marker |
(%set-datum $tmp2 $alloc-addr) |
(%incr $tmp2) ; $tmp2: address to store pointer at |
:builtin-make-array-loop |
(%store-typed $builtin-arg2 $tmp2 0 +type-ptr+) |
(%incr $tmp2) |
(%cmp-datum $tmp2 $tmp1) |
(branchimm-false :builtin-make-array-loop) |
(%store-typed $zero $tmp2 0 +type-snoc+) ; end marker |
(%set-datum $apply-result $alloc-addr) |
(jump-imm :p-apply-end) |
|
:builtin-array-size ; (%array-size array) |
(%set-type-imm $builtin-arg1 +type-array+) |
(call :fetch-args) |
(%make-obj $apply-result $builtin-arg1-val +type-int+) |
(jump-imm :p-apply-end) |
|
:builtin-array-get ; (%array-get array index) |
(%set-type-imm $builtin-arg1 +type-array+) |
(%set-type-imm $builtin-arg2 +type-int+) |
(call :fetch-args) |
|
;; check index; |
(%cmp-datum $builtin-arg2-val $builtin-arg1-val) |
(%branch* $zero :err-invalid-array-index (not N)) |
(%cmp-datum $builtin-arg2-val $zero) |
(%branch* $zero :err-invalid-array-index N) |
|
(%add* $tmp1 $builtin-arg1 $builtin-arg2-val) |
(%load $apply-result $tmp1 1) |
(jump-imm :p-apply-end) |
|
:builtin-array-set ; (%array-set array index value) => array |
(%set-type-imm $builtin-arg1 +type-array+) |
(%set-type-imm $builtin-arg2 +type-int+) |
(%set-type-imm $builtin-arg3 +type-t+) |
(call :fetch-args) |
|
;; check index; |
(%cmp-datum $builtin-arg2-val $builtin-arg1-val) |
(%branch* $zero :err-invalid-array-index (not N)) |
(%cmp-datum $builtin-arg2-val $zero) |
(%branch* $zero :err-invalid-array-index N) |
|
(%add* $tmp1 $builtin-arg1 $builtin-arg2-val) |
(%store-typed $builtin-arg3 $tmp1 1 +type-ptr+) |
(%set-datum $apply-result $builtin-arg1) |
(jump-imm :p-apply-end) |
|
:builtin-make-symbol ; (%make-symbol str) |
(%set-type-imm $builtin-arg1 +type-array+) ; TODO check that it is a string |
(call :fetch-args) |
(%make-obj $apply-result $builtin-arg1 +type-symbol+) |
(jump-imm :p-apply-end) |
|
:builtin-symbol-to-string ; (%symbol-to-string symb) |
(%set-type-imm $builtin-arg1 +type-symbol+) |
(call :fetch-args) |
(%set-datum $apply-result $builtin-arg1-val) |
(jump-imm :p-apply-end) |
|
:builtin-char-to-int ; (%char-to-int ch) |
(%set-type-imm $builtin-arg1 +type-char+) |
(call :fetch-args) |
(%make-int $apply-result $builtin-arg1-val) |
(jump-imm :p-apply-end) |
|
:builtin-int-to-char ; (%int-to-char n) |
(%set-type-imm $builtin-arg1 +type-int+) |
(call :fetch-args) |
(%make-char $apply-result $builtin-arg1-val) |
;;(%make-obj $apply-result $builtin-arg1-val +type-char+) |
(jump-imm :p-apply-end) |
|
:builtin-char-eq? ; (%char-eq? ch1 ch2) |
(%set-type-imm $builtin-arg1 +type-char+) |
(%set-type-imm $builtin-arg2 +type-char+) |
(call :fetch-args) |
(%set-datum-imm $apply-result %nil) |
(%when (%cmp-datum $builtin-arg1-val $builtin-arg2-val) |
(%set-datum-imm $apply-result %t)) |
(jump-imm :p-apply-end) |
|
:builtin-get-char ; (%get-char devnr) |
(%set-type-imm $builtin-arg1 +type-int+) |
(call :fetch-args) |
(select-device $builtin-arg1-val) |
;; :builtin-get-char-read |
(%load-typed $tmp1 $io-mem-addr %io-object +type-char+ :err-io-error) |
;; TODO handle errors |
(%make-char $apply-result $tmp1) |
(jump-imm :p-apply-end) |
|
;; :builtin-get-char-io-error |
;; (message-str "I/O ERROR") |
;; (message-reg $tmp1) |
;; (%get-type $tmp2 $tmp1) |
;; (message-reg $tmp2) |
;; (jump-imm :builtin-get-char-read) |
|
:builtin-put-char ; (%put-char devnr ch) => ch |
(%set-type-imm $builtin-arg1 +type-int+) |
(%set-type-imm $builtin-arg2 +type-char+) |
(call :fetch-args) |
(select-device $builtin-arg1-val) |
(%store $builtin-arg2-val $io-mem-addr %io-object) |
;; TODO handle errors |
(%set-datum $apply-result $builtin-arg2) |
(jump-imm :p-apply-end) |
|
:builtin-num-devices ; (%num-devices) |
(call :fetch-args) |
(%load-typed $tmp1 $io-mem-addr %io-devices +type-int+ :err-io-error) |
(%make-int $apply-result $tmp1) |
(jump-imm :p-apply-end) |
|
:builtin-device-type ; (%device-type devnr) |
(%set-type-imm $builtin-arg1 +type-int+) |
(call :fetch-args) |
(select-device $builtin-arg1-val) |
(%load-typed $tmp1 $io-mem-addr %io-identification +type-int+ :err-io-error) |
(%make-int $apply-result $tmp1) |
(jump-imm :p-apply-end) |
|
:builtin-set-address ; (%set-address devnr addr) => addr |
;; only sets lower part of address as of now |
(%set-type-imm $builtin-arg1 +type-int+) |
(%set-type-imm $builtin-arg2 +type-int+) |
(call :fetch-args) |
(select-device $builtin-arg1-val) |
(%store-typed $builtin-arg2-val $io-mem-addr %io-addr-l +type-int+) |
(%set-datum $apply-result $builtin-arg2) |
(jump-imm :p-apply-end) |
|
:builtin-get-address ; (%get-address devnr) |
;; only gets lower part of address as of now |
(%set-type-imm $builtin-arg1 +type-int+) |
(call :fetch-args) |
(select-device $builtin-arg1-val) |
(%load-typed $tmp1 $io-mem-addr %io-addr-l +type-int+ :err-io-error) |
(%make-int $apply-result $tmp1) |
(jump-imm :p-apply-end) |
|
:builtin-device-size ; (%builtin-device-size devnr) |
;; only get lower part of size |
(%set-type-imm $builtin-arg1 +type-int+) |
(call :fetch-args) |
(select-device $builtin-arg1-val) |
(%load-typed $tmp1 $io-mem-addr %io-size-l +type-int+ :err-io-error) |
(%make-int $apply-result $tmp1) |
(jump-imm :p-apply-end) |
|
:builtin-device-status ; (%builtin-device-status devnr) |
(%set-type-imm $builtin-arg1 +type-int+) |
(call :fetch-args) |
(select-device $builtin-arg1-val) |
(%load-typed $tmp1 $io-mem-addr %io-status +type-int+ :err-io-error) |
(%make-int $apply-result $tmp1) |
(jump-imm :p-apply-end) |
|
|
|
:builtin-error ; (%error reason) |
(%set-type-imm $builtin-arg1 +type-t+) |
(call :fetch-args) |
(%error $builtin-arg1) |
|
:builtin-add |
(call :builtin-binop-fetch-args) |
(%add* $apply-result-val $builtin-arg1-val $builtin-arg2-val) |
(%branch* $zero :err-overflow O) |
(jump-imm :builtin-binop-end) |
:builtin-sub |
(call :builtin-binop-fetch-args) |
(%sub* $apply-result-val $builtin-arg1-val $builtin-arg2-val) |
(%branch* $zero :err-overflow O) |
(jump-imm :builtin-binop-end) |
:builtin-mul |
(call :builtin-binop-fetch-args) |
(%mul* $apply-result-val $builtin-arg1-val $builtin-arg2-val) |
(%branch* $zero :err-overflow O) |
(jump-imm :builtin-binop-end) |
:builtin-div |
(call :builtin-binop-fetch-args) |
(%when (%cmp-datum-imm $builtin-arg2-val 0) |
(%error-imm %err-division-by-zero)) |
;; binary search for the answer |
(call :div-wrapper) |
(jump-imm :builtin-binop-end) |
:div-wrapper |
(%sub* $div-res $zero $one) |
(%cpy $div-sign $one) |
(%cmp-datum $builtin-arg1-val $zero) |
(%branch* $zero :div-nozero1 (not N)) |
(%xor $div-sign $one) |
(%mul $builtin-arg1-val $div-res) |
:div-nozero1 |
(%cmp-datum $builtin-arg2-val $zero) |
(%branch* $zero :div-nozero2 (not N)) |
(%xor $div-sign $one) |
(%mul $builtin-arg2-val $div-res) |
:div-nozero2 |
(%cmp-datum $div-sign $zero) |
(branchimm-false :div-nofix) |
(%sub $div-sign $one) |
:div-nofix |
(call :div-noneg) |
:div-afterdiv |
(%mul $div-low $div-sign) |
(%cpy $apply-result-val $div-low) |
:div-slutten |
(ret) |
|
;; binaersoek: gitt arg1, arg2: |
;; finn ans slik at ans*arg2<=arg1 og (ans+1)*arg2>arg1 |
|
:div-noneg |
(%cmp-datum $builtin-arg1-val $builtin-arg2-val) |
(branchimm-false :div-notequal) |
(%cpy $div-low $one) |
(ret) |
:div-notequal |
(%cmp-datum $builtin-arg1-val $builtin-arg2-val) |
(%branch* $zero :div-fortsett (not N)) |
(%cpy $div-low $zero) |
(ret) |
:div-fortsett |
(%set-datum $div-low $one) |
(%set-type-imm $div-low +type-int+) |
(%set-datum-imm $div-high 18631) |
(%set-type-imm $div-high +type-int+) |
(%set-datum-imm $div-mid 1801) |
(%set-type-imm $div-mid +type-int+) |
(%mul $div-high $div-mid) ;; voila, 2^25-1 (luckily 25 isn't prime) |
|
(%cmp-datum $builtin-arg2-val $zero) |
(branchimm-false :div-check1) |
(%cpy $div-low $zero) |
(jump-imm :div-end) |
;; error |
:div-check1 |
(%sub* $div-mid $div-high $div-low) |
(%cmp-datum $div-mid $one) |
(branchimm :div-end) |
|
:div-bsloop |
(%sub* $div-mid $div-high $div-low) |
(%shift-r $div-mid $one) |
(%add $div-mid $div-low) |
(%mul* $div-res $div-mid $builtin-arg2-val) |
(%branch* $zero :div-toohigh O) |
(%sub $div-res $one) |
(%cmp-datum $div-res $builtin-arg1-val) |
(%branch* $zero :div-toohigh (not N)) |
(%cpy $div-low $div-mid) |
(jump-imm :div-check1) |
:div-toohigh |
(%cpy $div-high $div-mid) |
(jump-imm :div-check1) |
:div-end |
(ret) |
:builtin-mod |
(call :builtin-binop-fetch-args) |
(%cpy $mod-val1 $builtin-arg1-val) |
(%cpy $mod-val2 $builtin-arg2-val) |
(%when (%cmp-datum-imm $builtin-arg2-val 0) |
(%error-imm %err-division-by-zero)) |
(call :div-wrapper) |
:modbreak |
(%mul $apply-result-val $mod-val2) |
(%sub $mod-val1 $apply-result-val) |
(%cpy $apply-result-val $mod-val1) |
(jump-imm :builtin-binop-end) |
:builtin-bitwise-and |
(call :builtin-binop-fetch-args) |
(%and* $apply-result-val $builtin-arg1-val $builtin-arg2-val) |
(jump-imm :builtin-binop-end) |
:builtin-bitwise-or |
(call :builtin-binop-fetch-args) |
(%or* $apply-result-val $builtin-arg1-val $builtin-arg2-val) |
(jump-imm :builtin-binop-end) |
:builtin-bitwise-not |
(%set-type-imm $builtin-arg1 +type-int+) |
(call :fetch-args) |
(%set-type-imm $apply-result-val +type-int+) |
(%not $apply-result-val $builtin-arg1-val) |
(jump-imm :p-apply-end) |
:builtin-bitwise-shift |
(%set-type-imm $builtin-arg1 +type-int+) |
(%set-type-imm $builtin-arg2 +type-int+) |
(call :fetch-args) |
(%cpy $apply-result-val $builtin-arg1-val) |
(%cmp-datum-imm $builtin-arg2-val 0) |
(%branch* $zero :builtin-bitwise-shift-right N) |
(%shift-l $apply-result-val $builtin-arg2-val) |
(jump-imm :builtin-binop-end) |
:builtin-bitwise-shift-right |
(%cpy $tmp1 $zero) |
(%sub $tmp1 $builtin-arg2-val) ; $tmp1 = -arg2 |
(%shift-r $apply-result-val $tmp1) |
(jump-imm :builtin-binop-end) |
|
:builtin-binop-fetch-args ; subroutine |
;; (%set-type-imm $builtin-arg1 +type-t+) |
;; (%set-type-imm $builtin-arg2 +type-t+) |
(%set-type-imm $builtin-arg1 +type-int+) ; assume all binops want INTs as args |
(%set-type-imm $builtin-arg2 +type-int+) |
(jump-imm :fetch-args) ; tail call |
|
:builtin-binop-end |
;; TODO check for errors |
(%cmp-type-imm $apply-result-val +type-int+) |
(branchimm :builtin-binop-end-int) |
(alloc-imm 1) |
(%store $apply-result-val $alloc-addr 0) |
(%set-datum $apply-result $alloc-addr) |
(jump-imm :p-apply-end) |
:builtin-binop-end-int |
(%make-int $apply-result $apply-result-val) |
(jump-imm :p-apply-end) |
|
:builtin-num-eq? ; (%num-eq? n1 n2) |
(call :builtin-binop-fetch-args) |
(%set-datum-imm $apply-result %nil) |
(%when (%cmp-datum $builtin-arg1-val $builtin-arg2-val) |
(%set-datum-imm $apply-result %t)) |
(jump-imm :p-apply-end) |
|
:builtin-less-than? ; (%less-than? n1 n2) |
(call :builtin-binop-fetch-args) |
(%set-datum-imm $apply-result %t) |
(%cmp-datum $builtin-arg1-val $builtin-arg2-val) |
(%branch* $zero :builtin-less-than?-end N) |
(%set-datum-imm $apply-result %nil) |
:builtin-less-than?-end |
(jump-imm :p-apply-end) |
|
:builtin-current-environment ; (%current-environment) |
(call :fetch-args) |
(%set-datum $apply-result $f-env) |
(jump-imm :p-apply-end) |
|
:builtin-make-eval-state ; (%make-eval-state expr env) |
(%set-type-imm $builtin-arg1 +type-t+) |
(%set-type-imm $builtin-arg2 +type-t+) |
(call :fetch-args) |
;; TODO should we do some typechecking here? |
(%set-datum $tmp1 $builtin-arg1) |
(%set-datum $tmp2 $builtin-arg2) |
(pop-eframe) |
(call :push-s) |
(call :init-evaluation-level) |
(%set-datum (e-expr) $tmp1) |
(%set-datum-imm (e-phase) %phase-eval) |
(%set-datum $f-env $tmp2) |
(call :interrupt) |
(jump-imm :main-loop-end) ; note: not :p-apply-end |
|
:builtin-eval-partial ; (%eval-partial state iterations) => new-state |
(%set-type-imm $builtin-arg1 +type-t+) |
(%set-type-imm $builtin-arg2 +type-int+) |
(call :fetch-args) |
;; TODO should we do some typechecking here? |
(%set-datum $tmp1 $builtin-arg1) |
(%set-datum $tmp2 $builtin-arg2-val) |
(pop-eframe) |
(call :push-s) |
(%set-datum $s-addr $tmp1) |
(call :load-sframe-without-parent) |
(%set-datum $s-iterations $tmp2) |
(jump-imm :main-loop) |
|
:builtin-define ; (%define symb val) => val |
(%set-type-imm $builtin-arg1 +type-symbol+) |
(%set-type-imm $builtin-arg2 +type-t+) |
(call :fetch-args) |
(%cons $tmp1 $builtin-arg1 $builtin-arg2) ; $tmp1: new binding |
(%car $tmp2 $f-env :err-invalid-env) ; $tmp2: local binding list |
(%cons $tmp1 $tmp1 $tmp2) ; $tmp1: new local binding list |
(%store-typed $tmp1 $f-env 0 +type-cons+) ; (set-car! $f-env $tmp1) |
(%set-datum $apply-result $builtin-arg2) |
(jump-imm :p-apply-end) |
|
:builtin-undefine ; (%undefine symb) => nil |
;;(%set-type-imm $builtin-arg1 +type-symbol+) |
;;(call :fetch-args) |
;;TODO |
(message-str "UNDEF") |
(%halt) |
|
:builtin-set! ; (%set! symb val) => val |
(%set-type-imm $builtin-arg1 +type-symbol+) |
(%set-type-imm $builtin-arg2 +type-t+) |
(call :fetch-args) |
(%set-datum $tmp1 $builtin-arg1) |
(%set-datum (e-arg) $builtin-arg2) |
(%set-datum-imm (e-phase) %phase-set!) |
(push-eframe) |
(%set-datum (e-expr) $tmp1) |
(%set-datum (e-arg) $f-env) |
(%set-datum-imm (e-phase) %phase-env-lookup) |
(jump-imm :main-loop-end) |
|
:builtin-set-car! ; (%set-car! cell val) => val |
(%set-type-imm $builtin-arg1 +type-cons+) |
(%set-type-imm $builtin-arg2 +type-t+) |
(call :fetch-args) |
(%store-typed $builtin-arg2 $builtin-arg1 0 +type-cons+) |
(%set-datum $apply-result $builtin-arg2) |
(jump-imm :p-apply-end) |
|
:builtin-set-cdr! ; (%set-cdr! cell val) => val |
(%set-type-imm $builtin-arg1 +type-cons+) |
(%set-type-imm $builtin-arg2 +type-t+) |
(call :fetch-args) |
(%store-typed $builtin-arg2 $builtin-arg1 0 +type-snoc+) |
(%set-datum $apply-result $builtin-arg2) |
(jump-imm :p-apply-end) |
|
:builtin-function-data |
(%set-type-imm $builtin-arg1 +type-function+) |
(call :fetch-args) |
(%load $apply-result $builtin-arg1 0) |
(jump-imm :p-apply-end) |
|
:builtin-builtin-name |
(%set-type-imm $builtin-arg1 +type-builtin+) |
(call :fetch-args) |
(%load $apply-result $builtin-arg1 0) |
(jump-imm :p-apply-end) |
|
|
:p-apply-end |
(pop-eframe) |
(%set-datum (e-result) $apply-result) |
(jump-imm :main-loop-end) |
|
|
;; subroutine for getting the arguments to a builtin function |
:fetch-args |
(%set-datum $fetch-args-arglist (e-result)) |
|
(%set-datum-imm $fetch-args-arg-reg $builtin-arg1) |
(%set-datum-imm $fetch-args-argval-reg $builtin-arg1-val) |
:fetch-args-loop |
|
(%cmp-type-imm (indirect-register $fetch-args-arg-reg) +type-none+) |
(branchimm :fetch-args-end) |
(%car $fetch-args-arg $fetch-args-arglist :err-too-few-args) |
(%load $fetch-args-argval $fetch-args-arg 0) |
(%when-not (%cmp-type-imm (indirect-register $fetch-args-arg-reg) +type-t+) |
(%when-not (%cmp-type (indirect-register $fetch-args-arg-reg) $fetch-args-argval) |
(%error-imm %err-type-error))) |
(%cpy (indirect-register $fetch-args-arg-reg) $fetch-args-arg) |
(%cpy (indirect-register $fetch-args-argval-reg) $fetch-args-argval) |
(%cdr $fetch-args-arglist $fetch-args-arglist :err-too-few-args) |
|
(%cmp-datum-imm $fetch-args-arg-reg $builtin-arg3) |
(branchimm :fetch-args-end) |
(%add $fetch-args-arg-reg $one) |
(%add $fetch-args-argval-reg $one) |
(jump-imm :fetch-args-loop) |
|
:fetch-args-end |
(%cmp-datum-imm $fetch-args-arglist %nil) |
(branchimm-false :err-too-many-args) |
(ret) |
|
|
|
:p-apply-function1 |
(%set-datum-imm (e-phase) %phase-apply-function) |
(%cdr $tmp1 $apply-func :err-invalid-function) ; $tmp1: (param-list expr env) |
(%car $tmp1 $tmp1 :err-invalid-function) ; $tmp1: param list |
(%set-datum $tmp2 (e-result)) ; $tmp2: arg list |
(push-eframe) |
(%set-datum-imm (e-expr) %nil) |
(%set-datum (e-arg) $tmp1) |
(%set-datum (e-result) $tmp2) |
(%set-datum-imm (e-phase) %phase-bind-args) |
(jump-imm :main-loop-end) |
|
;; PHASE: APPLY-FUNCTION |
|
:p-apply-function2 |
;; (e-arg): function (address) |
;; (e-result): list of argument bindings (address) |
(%load-typed $apply-func (e-arg) 0 +type-function+ :err-not-a-function) |
(%cdr $cdr $apply-func :err-invalid-function) ; $cdr: (param-list expr env) |
(%cdr $cdr $cdr :err-invalid-function) ; $cdr: (expr env) |
(%car $tmp1 $cdr :err-invalid-function) ; $tmp1: expr |
(%cdr $cdr $cdr :err-invalid-function) ; $cdr: (env) |
(%car $tmp2 $cdr :err-invalid-function) ; $tmp2: env |
(%cons $tmp2 (e-result) $tmp2) ; $tmp2: new env |
(%set-datum $tmp3 (e-arg)) ; $tmp3: function (address) |
(call :push-or-reuse-fframe) |
(%set-datum $f-func $tmp3) |
(%set-datum $f-env $tmp2) |
(%set-datum (e-expr) $tmp1) |
(%set-datum-imm (e-phase) %phase-eval) |
(jump-imm :main-loop-end) |
|
|
;; PHASE: SET! |
|
:p-set! |
;; (e-arg): new value |
;; (e-result): existing binding (or nil if variable is unbound) |
(%cmp-datum-imm (e-result) %nil) |
(branchimm :err-unbound-symbol) |
(%car $tmp1 (e-result) :err-invalid-state) ; check that (e-result) is a cons cell |
(%store-typed (e-arg) (e-result) 1 +type-snoc+) ; (set-cdr! (e-result) (e-arg)) |
(%set-datum $tmp1 (e-arg)) |
(pop-eframe) |
(%set-datum (e-result) $tmp1) |
(jump-imm :main-loop-end) |
|
|
;; PHASE: INITIAL |
|
:p-initial |
(%when (%cmp-datum-imm $s-parent %nil) |
(message-str "HALT") |
(%halt)) |
(call :interrupt) |
;; (jump-imm :main-loop-end) ; not necessary here |
|
|
;; All paths inside the main loop lead to here |
:main-loop-end |
(%cmp-datum $gc-firstfree $gc-mem-limit) ; lots of memory left? |
(%branch* $zero :main-loop-end-after-gc N) ; if so, skip GC |
;; Not enough memory, invoke GC. First store the evaluation state: |
(call :store-sframe) |
(%set-type-imm $tmp1 +type-cons+) |
(%set-datum $tmp1 $s-addr) |
(%store $tmp1 $zero %memory-root) |
;; Then call garbage collector: |
(call :gc-garbagecollect) |
(%cmp-datum $gc-firstfree $gc-mem-limit) ; lots of memory now? |
(%branch* $zero :out-of-memory (not N)) ; if not, give up completely |
(%load $s-addr $zero %memory-root) |
(call :load-sframe) |
:main-loop-end-after-gc |
(%cmp-datum-imm $s-iterations 0) |
(branchimm :main-loop) |
(%sub $s-iterations $one) |
(%cmp-datum-imm $s-iterations 0) |
(branchimm-false :main-loop) |
(%set-datum-imm $s-condition %timeout) |
(call :interrupt) |
(jump-imm :main-loop) |
|
|
:out-of-memory |
(message-str "ERROR: OUT OF MEMORY") |
(%halt) |
|
|
;; ERROR HANDLERS: |
|
:err-not-a-list |
(%error-imm %err-not-a-list) |
|
:err-not-a-pair |
(%error-imm %err-not-a-pair) |
|
:err-not-a-function |
(%error-imm %err-not-a-function) |
|
:err-malformed-form |
(%error-imm %err-malformed-form) |
|
:err-invalid-function |
(%error-imm %err-invalid-function) |
|
:err-invalid-builtin |
(%error-imm %err-invalid-builtin) |
|
:err-invalid-env |
(%error-imm %err-invalid-env) |
|
:err-unbound-symbol |
(%error-imm %err-unbound-symbol) |
|
:err-invalid-param-list |
(%error-imm %err-invalid-param-list) |
:err-too-few-args |
(%error-imm %err-too-few-args) |
:err-too-many-args |
(%error-imm %err-too-many-args) |
|
:err-invalid-array-index |
(%error-imm %err-invalid-array-index) |
|
:err-invalid-phase |
(%error-imm %err-invalid-phase) |
|
:err-invalid-state |
(%error-imm %err-invalid-state) |
|
:err-io-error |
(%error-imm %err-io-error) |
|
:err-overflow |
(%error-imm %err-overflow) |
|
|
;; SUBROUTINES: |
|
:make-empty-environment |
(%set-datum-imm $env %nil) |
(%cons $env $env $env) |
(ret) |
|
|
;; Subroutine. Initializes a new evaluation level (that is, a new |
;; state). Puts an initial e-frame at the bottom of the e/f |
;; buffer, pushes an e-frame on top of it (it is the caller's |
;; responsibility to initialize expr and phase in this new frame). |
:init-evaluation-level |
(%set-datum-imm $s-condition %nil) |
(%set-datum-imm $s-iterations 0) |
|
(%set-datum-imm $f-func %nil) |
(call :make-empty-environment) |
(%set-datum $f-env $env) |
(%set-datum-imm $f-addr %nil) |
|
(%set-datum-imm $e-expr $e/f-min-expr) |
(%set-datum-imm $e-arg $e/f-min-arg) |
(%set-datum-imm $e-result $e/f-min-result) |
(%set-datum-imm $e-phase $e/f-min-phase) |
|
(%set-type-imm (e-expr) +type-cons+) |
(%set-datum-imm (e-expr) %nil) |
(%set-datum-imm (e-arg) %nil) |
(%set-datum-imm (e-result) %nil) |
(%set-datum-imm (e-phase) %phase-initial) |
(%set-datum-imm $e-addr %nil) |
(push-eframe) |
(ret) |
|
|
;; Subroutine. End the current evaluation level. Stores the whole |
;; state to memory, returns it to the active e-frame in the |
;; previous level (or halt the machine if we were at the |
;; top-level). |
:interrupt |
(%cmp-datum-imm $s-parent %nil) |
(branchimm :interrupt-at-top-level) |
(call :store-sframe-without-parent) |
(%set-datum $interrupt-tmp $s-addr) |
(call :pop-s) |
(%set-datum (e-result) $interrupt-tmp) |
(ret) |
:interrupt-at-top-level |
(message-str "ERR:INTERRUPT") |
(%load $tmp1 $s-condition 1) |
(message-reg $tmp1) |
(message-reg $e-expr) |
(message-reg $e-arg) |
(message-reg $e-result) |
(message-reg $e-phase) |
(%halt) |
|
|
;; STACK SUBROUTINES |
|
;; Subroutine to take care of the cases in pushing e-frames when the |
;; new place isn't immediately available. This might be either because |
;; it is above the top of the buffer (in which case we should wrap |
;; around) or because it is occupied (in which case we should store |
;; the frame which is there to main memory). |
:push-eframe-handle-overflow |
(%cmp-datum-imm $e-expr $e/f-above-marker) |
(branchimm-false :push-eframe-handle-overflow-store) |
(%set-datum-imm $e-expr $e/f-min-expr) |
(%set-datum-imm $e-arg $e/f-min-arg) |
(%set-datum-imm $e-result $e/f-min-result) |
(%set-datum-imm $e-phase $e/f-min-phase) |
(%cmp-type-imm (e-expr) +type-none+) |
(branchimm :push-eframe-handle-overflow-end) |
:push-eframe-handle-overflow-store |
;; buffer is full |
(%cmp-type-imm (e-expr) +type-function+) |
(branchimm-false :push-eframe-handle-overflow-store-e) |
(call :store-fframe) ; sets $f-addr |
(jump-imm :push-eframe-handle-overflow-end) |
:push-eframe-handle-overflow-store-e |
(call :store-eframe) ; sets $e-addr |
:push-eframe-handle-overflow-end |
(%set-datum-imm (e-expr) +type-cons+) |
(ret) |
|
|
:pop-eframe-handle-underflow |
(%cmp-datum-imm $e-expr $e/f-below-marker) |
(branchimm-false :pop-eframe-handle-underflow-load) |
(%set-datum-imm $e-expr $e/f-max-expr) |
(%set-datum-imm $e-arg $e/f-max-arg) |
(%set-datum-imm $e-result $e/f-max-result) |
(%set-datum-imm $e-phase $e/f-max-phase) |
(%cmp-type-imm (e-expr) +type-none+) |
(branchimm-false :pop-eframe-handle-underflow-end) |
:pop-eframe-handle-underflow-load |
;; buffer is empty |
(%cmp-datum-imm $e-addr %nil) |
(branchimm-false :pop-eframe-handle-underflow-load-e) |
(jump-imm :load-fframe) ; tail call |
;; (call :load-f-and-e-frame-to-empty-buffer) ; sets $e-addr, $f-addr |
;; (ret) |
:pop-eframe-handle-underflow-load-e |
(call :load-eframe) |
:pop-eframe-handle-underflow-end |
(ret) |
|
|
|
|
:store-eframe |
(%set-type-imm (indirect-register $e-expr) +type-cons+) |
(%set-type-imm (indirect-register $e-arg) +type-cons+) |
(%set-type-imm (indirect-register $e-result) +type-cons+) |
(%set-type-imm (indirect-register $e-phase) +type-cons+) |
(%set-type-imm $e-addr +type-cons+) |
(alloc-imm 10) |
(%set-type-imm $e-tmp1 +type-snoc+) |
(%set-datum $e-tmp1 $alloc-addr) |
(%set-type-imm $e-tmp2 +type-int+) |
(%set-datum-imm $e-tmp2 2) |
(%set-type-imm $e-tmp3 +type-int+) |
(%set-datum $e-tmp3 $e-tmp1) |
(%store $e-addr $e-tmp1 0) |
(%store $list-terminator $e-tmp1 1) |
(%store (indirect-register $e-phase) $e-tmp1 2) |
(%store $e-tmp1 $e-tmp1 3) |
(%add $e-tmp3 $e-tmp2) |
(%set-datum $e-tmp1 $e-tmp3) |
(%store (indirect-register $e-result) $e-tmp1 2) |
(%store $e-tmp1 $e-tmp1 3) |
(%add $e-tmp3 $e-tmp2) |
(%set-datum $e-tmp1 $e-tmp3) |
(%store (indirect-register $e-arg) $e-tmp1 2) |
(%store $e-tmp1 $e-tmp1 3) |
(%add $e-tmp3 $e-tmp2) |
(%set-datum $e-tmp1 $e-tmp3) |
(%store (indirect-register $e-expr) $e-tmp1 2) |
(%store $e-tmp1 $e-tmp1 3) |
(%add $e-tmp3 $e-tmp2) |
(%set-datum $e-addr $e-tmp3) |
(ret) |
|
:load-eframe |
(%car (indirect-register $e-expr) $e-addr :load-eframe-error) |
(%cdr $e-tmp1 $e-addr :load-eframe-error) |
(%car (indirect-register $e-arg) $e-tmp1 :load-eframe-error) |
(%cdr $e-tmp1 $e-tmp1 :load-eframe-error) |
(%car (indirect-register $e-result) $e-tmp1 :load-eframe-error) |
(%cdr $e-tmp1 $e-tmp1 :load-eframe-error) |
(%car (indirect-register $e-phase) $e-tmp1 :load-eframe-error) |
(%cdr $e-tmp1 $e-tmp1 :load-eframe-error) |
(%car $e-addr $e-tmp1 :load-eframe-error) |
(ret) |
:load-eframe-error |
(message-str "ERR:L-E") |
(%halt) |
|
|
|
;; Subroutine. Makes sure there is a function frame with a single |
;; evaluation frame at the top of the stack. These might be the |
;; frames currently at the top (if the current e-frame has no |
;; parent, in which case it is safe to tail-call optimize) or new |
;; frames. If a new f-frame is pushed, the current e-frame is |
;; popped first. |
:push-or-reuse-fframe |
(%sub* $f-tmp1 $e-expr $e/f-frame-size) |
(%when (%cmp-datum-imm $f-tmp1 $e/f-below-marker) |
(%set-datum-imm $f-tmp1 $e/f-max-expr)) |
;; is frame below current a func frame? |
(%cmp-type-imm (indirect-register $f-tmp1) +type-function+) |
;; if it is, eframe has no parent, so we can reuse fframe: |
(branchimm :push-or-reuse-fframe-can-reuse) |
;; is frame below current empty? |
(%cmp-type-imm (indirect-register $f-tmp1) +type-none+) |
;; if not, eframe has parent in e/f buffer, so we cannot reuse fframe: |
(branchimm-false :push-or-reuse-fframe-cannot-reuse) |
;; if we got here, $e-addr is the address of this e-frame's |
;; parent. check if it is NIL: |
(%cmp-datum-imm $e-addr %nil) |
;; if not, eframe has parent in memory, so cannot reuse fframe: |
(branchimm-false :push-or-reuse-fframe-cannot-reuse) |
:push-or-reuse-fframe-can-reuse |
;; if we get to here, the eframe has no parent, so we can reuse fframe: |
(%set-datum-imm (indirect-register $e-arg) %nil) |
(%set-datum-imm (indirect-register $e-result) %nil) ; caller must set $e-expr, $e-phase |
(ret) |
:push-or-reuse-fframe-cannot-reuse |
(pop-eframe) |
(call :push-fframe) |
(push-eframe) |
(ret) |
|
|
;; Subroutine. Pushes the current f-frame onto the e/f buffer. |
:push-fframe |
;; get a nice empty place in the e/f buffer: |
(push-eframe) |
;; put our current fframe there: |
(%set-datum (indirect-register $e-expr) $f-func) |
(%set-datum (indirect-register $e-arg) $f-env) |
;; mark this as being an fframe by setting the type of the first |
;; register: |
(%set-type-imm (indirect-register $e-expr) +type-function+) |
(ret) |
|
|
|
;; Subroutine. Stores the current frame in e/f buffer as an |
;; f-frame. Sets $f-addr to the address it was stored to, $e-addr to |
;; %nil (to indicate that the e-frame directly above this in the |
;; buffer has no parent). |
:store-fframe |
(%set-type-imm (indirect-register $e-expr) +type-cons+) |
(%set-type-imm (indirect-register $e-arg) +type-cons+) |
(%set-type-imm $f-addr +type-cons+) |
(alloc-imm 8) |
(%set-type-imm $f-tmp1 +type-snoc+) |
(%set-datum $f-tmp1 $alloc-addr) |
(%set-type-imm $f-tmp2 +type-int+) |
(%set-datum-imm $f-tmp2 2) |
(%set-type-imm $f-tmp3 +type-int+) |
(%set-datum $f-tmp3 $f-tmp1) |
(%store $f-addr $f-tmp1 0) |
(%store $list-terminator $f-tmp1 1) |
(%store $e-addr $f-tmp1 2) |
(%store $f-tmp1 $f-tmp1 3) |
(%add $f-tmp3 $f-tmp2) |
(%set-datum $f-tmp1 $f-tmp3) |
(%store (indirect-register $e-arg) $f-tmp1 2) |
(%store $f-tmp1 $f-tmp1 3) |
(%add $f-tmp3 $f-tmp2) |
(%set-datum $f-tmp1 $f-tmp3) |
(%store (indirect-register $e-expr) $f-tmp1 2) |
(%store $f-tmp1 $f-tmp1 3) |
(%add $f-tmp3 $f-tmp2) |
(%set-datum $f-addr $f-tmp3) |
(%set-datum-imm $e-addr %nil) |
(ret) |
|
;; Subroutine. Loads an f-frame into the e/f buffer. The f-frame is |
;; found at the memory address in $f-addr; this register is changed to |
;; be the address of this frame's parent. Sets $e-addr to the address |
;; of the top e-frame in this f-frame. |
:load-fframe |
(%car $f-tmp1 $f-addr :load-fframe-error) |
(%set-datum (e-expr) $f-tmp1) |
(%set-type-imm (e-expr) +type-function+) |
(%cdr $f-tmp1 $f-addr :load-fframe-error) |
(%car (e-arg) $f-tmp1 :load-fframe-error) |
(%cdr $f-tmp1 $f-tmp1 :load-fframe-error) |
(%car $e-addr $f-tmp1 :load-fframe-error) |
(%cdr $f-tmp1 $f-tmp1 :load-fframe-error) |
(%car $f-addr $f-tmp1 :load-fframe-error) |
(ret) |
;;(jump-imm :load-eframe) ; tail call |
:load-fframe-error |
(message-str "ERR:L-F") |
(%halt) |
|
|
:load-f-and-e-frame-to-empty-buffer |
(call :load-fframe) |
(%set-datum $f-func (e-expr)) |
(%set-datum $f-env (e-arg)) |
(%set-type-imm (e-expr) +type-none+) |
(jump-imm :load-eframe) ; tail call |
|
|
|
:store-e/f-stack |
(call :push-fframe) ; put current fframe into e/f buffer |
(%set-datum $e/f-top $e-expr) ; remember current position |
;; Traverse the whole buffer, pushing dummy frames. This has the |
;; effect that all frames in the buffer will be stored to main memory. |
:store-e/f-stack-loop |
(push-eframe) |
(%set-type-imm (indirect-register $e-expr) +type-none+) |
(%cmp-datum $e-expr $e/f-top) |
(branchimm-false :store-e/f-stack-loop) |
(ret) |
|
|
:push-s |
(call :store-sframe) |
(%set-datum $s-parent $s-addr) |
(ret) |
|
|
:store-sframe |
(%cons $s-tmp $s-parent $list-terminator) |
:store-sframe-without-parent-1 |
(%make-obj $s-iterations $s-iterations +type-int+) |
(%cons $s-tmp $s-iterations $s-tmp) |
(%cons $s-tmp $s-condition $s-tmp) |
(call :store-e/f-stack) ; stores the whole e/f buffer, we get address |
; of top f-frame in $f-addr |
(%cons $s-tmp $f-addr $s-tmp) |
(%set-datum $s-addr $s-tmp) |
(ret) |
:store-sframe-without-parent |
(%set-datum-imm $s-tmp %nil) |
(jump-imm :store-sframe-without-parent-1) |
|
|
|
:pop-s |
(%set-datum $s-addr $s-parent) |
:load-sframe |
(call :load-sframe-common) |
(%cdr $s-tmp $s-tmp :load-sframe-error) |
(%car $s-parent $s-tmp :load-sframe-error) |
(jump-imm :load-f-and-e-frame-to-empty-buffer) ; tail call |
:load-sframe-error |
;;(%error %err-invalid-state) |
(message-str "ERR:L-S") |
(%halt) |
|
|
|
:load-sframe-without-parent |
(call :load-sframe-common) |
(jump-imm :load-f-and-e-frame-to-empty-buffer) ; tail call |
:load-sframe-without-parent-error |
(%halt) |
|
:load-sframe-common |
(%car $f-addr $s-addr :load-sframe-error) |
(%cdr $s-tmp $s-addr :load-sframe-error) |
(%car $s-condition $s-tmp :load-sframe-error) |
(%cdr $s-tmp $s-tmp :load-sframe-error) |
(%car $s-iterations $s-tmp :load-sframe-error) |
(%load $s-iterations $s-iterations 0) |
(ret) |
|
|
|
;; OUTPUT |
|
;; Subroutine, print int from $message |
:message-reg |
(select-device-imm +dev-serial+) |
(%set-datum-imm $message-shift 24) |
(%set-datum-imm $message-mask #xF) |
:message-reg-loop |
(%set-datum $message-tmp1 $message) |
(%shift-r $message-tmp1 $message-shift) |
(%and $message-tmp1 $message-mask) |
(%set-datum-imm $message-tmp2 (char-int #\0)) |
(%cmp-datum-imm $message-tmp1 #xA) |
(%branch* $zero :message-reg-below-a N) |
(%set-datum-imm $message-tmp2 (- (char-int #\A) #xA)) |
:message-reg-below-a |
(%add $message-tmp1 $message-tmp2) |
(%store $message-tmp1 $io-mem-addr %io-object) |
(%cmp-datum-imm $message-shift 0) |
(branchimm :message-reg-loop-end) |
(%set-datum-imm $message-tmp1 4) |
(%sub $message-shift $message-tmp1) |
(jump-imm :message-reg-loop) |
:message-reg-loop-end |
(ret) |
|
|
|
|
;; GARBAGE COLLECTOR |
|
|
;; Garbage collection subroutine |
:gc-garbagecollect |
(message-str-no-nl ":") |
|
;; mark everything as free |
(%cpy $gc-vi $gc-startofmem) |
|
:gc-loop1 |
;; load the contents of memory address (contained in gc-vi) |
;; into register gc-1) |
;; loop tested in emu: OK |
(%load $gc-1 $gc-vi 0) |
;; if gc-flag already free, stop |
(%cmp-gc-imm $gc-1 +gc-free+) |
(branchimm :gc-nodeletegc) |
(%set-gc-imm $gc-1 +gc-free+) |
(%store $gc-1 $gc-vi 0) |
:gc-nodeletegc |
(%add $gc-vi $one) |
(%cmp-datum $gc-vi $gc-gcspace) |
(branchimm-false :gc-loop1) |
;; pointer reversal! skrekk og gru |
;; algorithm based on tiger book |
|
;; start of pointer reversal |
;; the algorithm is able to "slide" sideways without reversing |
;; underlying pointers within the following structures |
;; CONS - SNOC |
;; ARRAY - PTR - ... - PTR - SNOC |
|
;; CONS/ARRAY are identified as start of structure |
;; SNOC is identified as end of structure |
|
(%set-type-imm $gc-t +type-int+) |
(%set-datum-imm $gc-t 0) |
(%cpy $gc-x $gc-rootptr) |
|
|
:gc-mainreverseloop |
|
;; visit current block |
;; gc-x holds current memory address |
;; gc-y will hold the contents of the address |
(%load $gc-y $gc-x 0) |
(%set-gc-imm $gc-y +gc-used+) |
(%store $gc-y $gc-x 0) |
|
(%cpy $gc-followp $zero) |
(%cpy $gc-cannext $zero) |
(%cpy $gc-canprev $zero) |
|
;; if memory address x contains a pointer, and it points to |
;; a memory address marked as gc-free (ie. unvisited so far) |
;; set followp to true (1) |
;; the following types have pointers: CONS PTR SNOC |
;; tested OK for case: cell is pointer, cell pointed to is unvisited |
(%cmp-type-imm $gc-y +type-cons+) |
(branchimm :gc-setfollowp) |
(%cmp-type-imm $gc-y +type-snoc+) |
(branchimm :gc-setfollowp) |
(%cmp-type-imm $gc-y +type-ptr+) |
(branchimm :gc-setfollowp) |
(%cmp-type-imm $gc-y +type-function+) |
(branchimm :gc-setfollowp) |
(%cmp-type-imm $gc-y +type-symbol+) |
(branchimm :gc-setfollowp) |
(%cmp-type-imm $gc-y +type-builtin+) |
(branchimm :gc-setfollowp) |
;; if any other types contain pointers, add them here! |
(jump-imm :gc-afterfollowp) |
|
:gc-setfollowp |
|
;; don't follow pointer if it's a low address |
; (%cmp-datum $gc-y $gc-startofmem) |
; (%branch* $zero :gc-afterfollowp (not N)) |
|
; copy from memory location $gc-y, into $gc-v |
(%load $gc-v $gc-y 0) |
(%cmp-gc-imm $gc-v +gc-used+) |
(branchimm :gc-afterfollowp) |
(%cpy $gc-followp $one) |
|
:gc-afterfollowp |
|
;; if we aren't at the last position of a memory structure spanning |
;; several addresses and the next adress is free, set cannext=1 |
;; currently, these types can occur at the non-end: CONS, ARRAY, PTR |
;; tested OK for case: cell is not end of structure, next cell is unvisited |
(%cmp-type-imm $gc-y +type-cons+) |
(branchimm :gc-setcannext) |
(%cmp-type-imm $gc-y +type-array+) |
(branchimm :gc-setcannext) |
(%cmp-type-imm $gc-y +type-ptr+) |
(branchimm :gc-setcannext) |
(jump-imm :gc-aftercannext) |
:gc-setcannext |
(%cpy $gc-1 $gc-x) ;; check is address x+1 is unvisited |
(%add $gc-1 $one) |
(%load $gc-1 $gc-1 0) ;; lykkebo says this is safe |
(%cmp-gc-imm $gc-1 +gc-used+) |
(branchimm :gc-aftercannext) |
(%cpy $gc-cannext $one) |
|
:gc-aftercannext |
|
;; if we aren't at the first position of a memory structure spanning |
;; several addresses, set canprev=1 |
;; the following types can occur at the non-start: SNOC PTR |
;; tested OK for case: cell is not end of structure |
(%cmp-type-imm $gc-y +type-snoc+) |
(branchimm :gc-setcanprev) |
(%cmp-type-imm $gc-y +type-ptr+) |
(branchimm :gc-setcanprev) |
(jump-imm :gc-aftercanprev) |
:gc-setcanprev |
(%cpy $gc-canprev $one) |
|
:gc-aftercanprev |
|
;; do stuff based on followp, cannext, canprev |
;; follow the pointer we're at, and reverse the pointer |
(%cmp-datum $gc-followp $one) |
(branchimm-false :gc-afterfollowedp) |
(%cpy $gc-temp $gc-x) |
(%load $gc-mem $gc-temp 0) |
(%set-datum $gc-mem $gc-t) |
(%store $gc-mem $gc-temp 0) |
(%cpy $gc-t $gc-temp) |
(%set-datum $gc-x $gc-y) |
(jump-imm :gc-mainreverseloop) |
|
:gc-afterfollowedp |
|
;; move to next memory location |
(%cmp-datum $gc-cannext $one) |
(branchimm-false :gc-aftercouldnext) |
(%add $gc-x $one) |
(jump-imm :gc-mainreverseloop) |
|
:gc-aftercouldnext |
|
;; move to previous memory location |
(%cmp-datum $gc-canprev $one) |
(branchimm-false :gc-aftercouldprev) |
;; address 0x48 |
(%sub $gc-x $one) |
(jump-imm :gc-mainreverseloop) |
|
:gc-aftercouldprev |
|
;; all cases exhausted: follow pointer back and reverse the reversal |
(%cmp-datum $gc-t $zero) |
(branchimm :gc-donepointerreversal) |
(%load $gc-temp $gc-t 0) ;; read from address gc-t, into gc-temp |
(%cpy $gc-mem $gc-temp) |
(%set-datum $gc-mem $gc-x) |
(%store $gc-mem $gc-t 0) ;; restore the correct pointer in gc-t |
(%cpy $gc-x $gc-t) |
(%cpy $gc-t $gc-temp) |
(jump-imm :gc-mainreverseloop) |
|
:gc-donepointerreversal |
|
|
(message-str-no-nl ",") |
|
;; end of pointer reversal routine, from this point on, |
;; all variables marked with "ptr-rev" are free for other use |
|
;; pre-fill low memory values into translation area |
(%cpy $gc-from $zero) |
(%cpy $gc-to $gc-gcspace) |
:gc-prefill |
(%store $gc-from $gc-to 0) |
(%add $gc-from $one) |
(%add $gc-to $one) |
(%cmp-datum $gc-from $gc-startofmem) |
(branchimm-false :gc-prefill) |
|
;; copy the stuff |
|
(%cpy $gc-to $gc-from) |
(%cpy $gc-baseaddr $zero) |
:gc-copyloop |
|
(%load $gc-mem $gc-from 0) ;; read from gc-from into gc-mem |
(%cmp-gc-imm $gc-mem +gc-used+) |
(branchimm-false :gc-notrans) |
;; put address in translation table |
(%cpy $gc-temp $gc-from) |
(%sub $gc-temp $gc-baseaddr) |
; (%div* $gc-mem $gc-from $gc-spacesize) |
; (%mul $gc-mem $gc-spacesize) |
; (%cpy $gc-temp2 $gc-from) |
; (%sub $gc-temp2 $gc-mem) |
(%add $gc-temp $gc-gcspace) |
(%store $gc-to $gc-temp 0) ;; write to-address to gc-temp |
;; copy |
;; (%load $gc-mem $gc-from 0) |
(%store $gc-mem $gc-to 0) |
(%add $gc-to $one) |
:gc-notrans |
(%add $gc-from $one) |
|
(%cpy $gc-temp $gc-baseaddr) |
(%add $gc-temp $gc-spacesize) |
|
|
; (%div* $gc-temp $gc-from $gc-spacesize) |
; (%mul $gc-temp $gc-spacesize) |
; (%sub* $gc-temp2 $gc-from $gc-temp) |
(%cmp-datum $gc-from $gc-temp) |
(branchimm-false :gc-noconvert) |
|
;; translate pointers |
:gc-transloop |
(%cpy $gc-vi $gc-startofmem) |
|
(message-str-no-nl ".") |
|
:gc-transloop2 |
(%load $gc-mem $gc-vi 0) ;; read from address gc-i and put into gc-mem |
(%cmp-gc-imm $gc-mem +gc-used+) |
(branchimm-false :gc-nexttrans) |
(%cmp-type-imm $gc-mem +type-ptr+) |
(branchimm :gc-isptr) |
(%cmp-type-imm $gc-mem +type-cons+) |
(branchimm :gc-isptr) |
(%cmp-type-imm $gc-mem +type-snoc+) |
(branchimm :gc-isptr) |
(%cmp-type-imm $gc-mem +type-symbol+) |
(branchimm :gc-isptr) |
(%cmp-type-imm $gc-mem +type-function+) |
(branchimm :gc-isptr) |
(%cmp-type-imm $gc-mem +type-builtin+) |
(branchimm :gc-isptr) |
(jump-imm :gc-nexttrans) |
|
:gc-isptr |
;; check that these branches work |
;; OK for mem>=from-spacesize og mem<from |
(%sub* $gc-temp $gc-from $gc-spacesize) |
(%cmp-datum $gc-mem $gc-temp) |
(%branch* $zero :gc-nexttrans N) |
(%cmp-datum $gc-mem $gc-from) |
(%branch* $zero :gc-nexttrans (not N)) |
|
;; calculate gcspace+val%spacesize, put in val |
(%cpy $gc-val $gc-mem) |
(%sub $gc-val $gc-baseaddr) |
(%add $gc-val $gc-gcspace) |
|
; (%div* $gc-temp $gc-val $gc-spacesize) |
; (%mul $gc-temp $gc-spacesize) |
; (%sub* $gc-temp2 $gc-val $gc-temp) |
; (%add* $gc-val $gc-temp2 $gc-gcspace) |
(%load $gc-temp2 $gc-val 0) |
(%set-datum $gc-mem $gc-temp2) |
(%store $gc-mem $gc-vi 0) |
|
:gc-nexttrans |
(%add $gc-vi $one) |
(%cmp-datum $gc-vi $gc-to) |
(branchimm-false :gc-noto) |
(%cpy $gc-vi $gc-from) |
:gc-noto |
(%cmp-datum $gc-vi $gc-gcspace) |
(branchimm-false :gc-transloop2) |
|
;; done with one block, increase base address |
(%add $gc-baseaddr $gc-spacesize) |
|
:gc-noconvert |
|
(%cmp-datum $gc-from $gc-gcspace) |
(branchimm-false :gc-copyloop) |
|
;; whee, gc is finished and we have a new address where |
;; free space starts |
(%cpy $gc-firstfree $gc-to) |
(message-str-no-nl ":") |
(ret) |
;; End of garbage collection subroutine |
|
|
:call-error |
(message-str "ERR:CALL") |
(%halt) |
:ret-error |
(message-str "ERR:RET") |
(%halt) |
)) |
|
|
(defun write-register-file () |
(with-open-file (s |
"/tmp/regfile" |
:element-type 'character |
:direction :output |
:if-does-not-exist :create |
:if-exists :supersede) |
(let ((symbols-start #x100)) |
(format s "size ~X~%" +n-regs+) |
;; initialize some general registers: |
(format s "addr 0~%") |
(format s "int 0~%") ; $zero |
(format s "int 1~%") ; $one |
(format s "int 2~%") ; $two |
(format s "addr ~X~%" $list-terminator) |
(format s "snoc ~X~%" %nil) |
(format s "addr ~X~%" $mc-stack-top) |
(format s "int ~X~%" $mc-stack-min) |
(format s "addr ~X~%" $io-mem-addr) |
(format s "int 3FFFF00~%") |
(format s "addr ~X~%" $gc-maxblocks) |
(format s "int ~X~%" +memory-size+) |
(format s "addr ~X~%" $gc-spacesize) |
(format s "int ~X~%" (floor (/ +memory-size+ +gc-spaces+))) |
;; write symbol strings in compressed form (three characters per |
;; register): |
(format s "addr ~X~%" symbols-start) |
(loop for v in (compress-symbols (make-symbols)) |
do (format s "int ~X~%" v)) |
;; initialize registers used by initialization: |
(format s "addr ~X~%" $init1) |
(format s "nil~%") ; init1 |
(format s "t~%") ; init2 |
(format s "none~%") ; init3 |
(format s "int ~X~%" symbols-start) ; init-counter |
(format s "int 0~%") ; init-counter2 |
(format s "int 10~%") ; init-shift1 |
(format s "int 8~%") ; init-shift2 |
(format s "int FF~%") ; init-char-mask |
(format s "int ~X~%" %area-chars) ; init-chars-start |
(format s "int 2~%") ; init-symbol-addr |
(format s "int ~X~%" %area-strings) ; init-symbol-str-addr |
(format s "int ~X~%" %area-strings) ; init-symbol-char-addr |
(format s "array 0~%") ; init-symbol-array |
))) |
|
(defun make-symbols () |
(let ((symbols "%IF |
%QUOTE |
%LAMBDA |
%PROGN |
%CONS |
%CAR |
%CDR |
%EVAL |
%APPLY |
%TYPE |
%MAKE-ARRAY |
%ARRAY-SIZE |
%ARRAY-GET |
%ARRAY-SET |
%MAKE-SYMBOL |
%SYMBOL-TO-STRING |
%CHAR-TO-INT |
%INT-TO-CHAR |
%GET-CHAR |
%PUT-CHAR |
%NUM-DEVICES |
%DEVICE-TYPE |
%SET-ADDRESS |
%GET-ADDRESS |
%ERROR |
%ADD |
%SUB |
%MUL |
%DIV |
%BITWISE-AND |
%BITWISE-OR |
%BITWISE-NOT |
%BITWISE-SHIFT |
%CURRENT-ENVIRONMENT |
%MAKE-EVAL-STATE |
%EVAL-PARTIAL |
%DEFINE |
%UNDEFINE |
%EQ? |
%NUM-EQ? |
%CHAR-EQ? |
%LESS-THAN? |
%MOD |
%SET! |
%SET-CAR! |
%SET-CDR! |
%FUNCTION-DATA |
%BUILTIN-NAME |
%DEVICE-SIZE |
%DEVICE-STATUS |
|
|
|
|
|
|
|
|
|
|
|
%SYMBOL-TABLE |
%PHASE-EVAL |
%PHASE-EVAL-ARGS |
%PHASE-APPLY |
%PHASE-EVAL-IF |
%PHASE-INITIAL |
%PHASE-ENV-LOOKUP |
%PHASE-ENV-LOOKUP-LOCAL |
%PHASE-APPLY-FUNCTION |
%PHASE-BIND-ARGS |
%PHASE-EVAL-PROGN |
%PHASE-EVAL-ARGS-TOP |
%PHASE-EVAL-ARGS-CDR |
%PHASE-EVAL-ARGS-CONS |
%PHASE-EVAL-SYMBOL |
%PHASE-SET! |
|
%TIMEOUT |
%ERR-INVALID-PHASE |
%ERR-UNBOUND-SYMBOL |
%ERR-INVALID-PARAM-LIST |
%ERR-TOO-FEW-ARGS |
%ERR-TOO-MANY-ARGS |
%ERR-INVALID-STATE |
%ERR-INVALID-ARG-LIST |
%ERR-TYPE-ERROR |
%ERR-NOT-A-LIST |
%ERR-NOT-A-FUNCTION |
%ERR-INVALID-FUNCTION |
%ERR-MALFORMED-FORM |
%ERR-INVALID-BUILTIN |
%ERR-INVALID-ARRAY-INDEX |
%ERR-INVALID-ENV |
%ERR-NOT-A-PAIR |
%ERR-IO-ERROR |
%ERR-DIVISION-BY-ZERO |
%ERR-OVERFLOW |
")) |
(loop for ch across symbols |
collect (if (char= ch #\Newline) |
0 |
(char-int ch))))) |
|
(defun compress-symbols (char-list) |
(if char-list |
(let* ((c1 (car char-list)) |
(l1 (cdr char-list)) |
(c2 (if l1 (car l1) 0)) |
(l2 (if l1 (cdr l1) nil)) |
(c3 (if l2 (car l2) 0)) |
(l3 (if l2 (cdr l2) nil))) |
(cons (logior (ash c1 16) |
(ash c2 8) |
c3) |
(compress-symbols l3))) |
nil)) |
/microprogram_assembler/rewrite.lisp
0,0 → 1,35
;;; |
;;; with-assembly rewrite routines |
;;; |
|
(in-package #:mcasm) |
|
;; Check if argument is a label |
(defun labelp (a) |
(typep a 'keyword)) |
|
;; Add a label to the assembly data |
(defun make-label (label) |
(when (eq *assembler-state* :gather) |
(setf (gethash label *assembler-labels*) *assembler-position*))) |
|
; Do instruction rewrite |
(defun rewrite-instruction-inst (inst state) |
(loop for arg in (cdr inst) |
for i from 1 |
when (eq (argument-to-type arg) 'label) |
do (setf (nth i inst) |
(if (eq state :gather) |
0 |
`(if (gethash ,arg *assembler-labels*) |
(gethash ,arg *assembler-labels*) |
(error "Unknown label: ~A" ,arg))))) |
inst) |
|
;; Rewrite an assembly instruction |
;; :label => (make-label :label) |
(defun rewrite-instruction (inst state) |
(typecase inst |
(list (rewrite-instruction-inst inst state)) |
(keyword `(make-label ,inst)) |
(t (error "Unknown instruction type: ~A" (type-of inst))))) |
/microprogram_assembler/sexptomem.lisp
0,0 → 1,264
;;; |
;;; Sexp to memory file |
;;; |
|
(defpackage #:sexptomem |
(:use #:cl)) |
|
(in-package #:sexptomem) |
|
(defvar *symbolinfo*) |
(defvar *symbolinfopos*) |
(defvar *datastartpos* #x1000) |
(defvar *symbolstartpos* (+ *datastartpos* 2)) |
|
(defun listify (list) |
(if (listp list) |
list |
(list list))) |
|
(defun handle-integer (x) |
(values nil |
(format nil "int ~X" x) |
1)) |
|
(defvar *character-start-position* #x200) |
(defun char-position (char) |
(+ *character-start-position* (char-code char))) |
|
(defun handle-string (str) |
(let ((len (length str))) |
(values |
nil |
(concatenate 'list |
(list (format nil "array ~X" len)) |
(loop for ch across str |
collect (format nil "ptr ~X" (char-position ch))) |
(list "snoc 0")) |
(+ 2 len)))) |
|
(defun handle-special-list (op cons) |
t) |
|
(defun handle-cons (cons) |
(if (eq cons nil) |
(values t 0 0) |
(if (eq (type-of (car cons)) 'keyword) |
(handle-special-list (car cons) (cdr cons)) |
(handle-list cons)))) |
|
(defun handle-list (cons) |
(if (not cons) |
(values t 0 0) |
(multiple-value-bind (carinplace cars carp) |
(sexp-to-memory-fun (car cons)) |
(multiple-value-bind (cdrinplace cdrs cdrp) |
(handle-list (cdr cons)) |
(let ((list (concatenate 'list |
(list |
(if carinplace |
(format nil "cons ~X" cars) |
(format nil "cons +~X" 2))) |
(list (if (not (cdr cons)) |
(format nil "snoc 0") |
(if cdrinplace |
(format nil "snoc ~X" cdrs) |
(format nil "snoc +~X" (1+ (if carinplace 0 carp)))))) |
(listify (if carinplace () cars)) |
(listify (if cdrinplace () cdrs))))) |
(values nil list |
(+ 2 (if carinplace 0 carp) (if cdrinplace 0 cdrp)))))))) |
|
(defun handle-symbol (sym) |
(let ((res (assoc sym *symbolinfo*))) |
(if (not res) |
(progn |
(setf *symbolinfo* (append *symbolinfo* (list (cons sym *symbolinfopos*)))) |
(incf *symbolinfopos*) |
(handle-symbol sym)) |
(values t (cdr res) 0)))) |
|
(defun handle-character (char) |
; (values nil (format nil "char ~X ~A" (char-code char) char) 1)) |
(values t (char-position char) 0)) |
|
(defun sexp-to-memory-fun (body) |
(typecase body |
(list (handle-cons body)) |
(string (handle-string body)) |
(integer (handle-integer body)) |
(symbol (handle-symbol body)) |
(character (handle-character body)) |
(t (error "Unknown type: ~A~%" (type-of body))))) |
|
(defun rewrite-sexp-expr-list-to-cons (list) |
(if list |
`(%cons ,(rewrite-sexp-expr (car list)) |
,(rewrite-sexp-expr-list-to-cons (cdr list))) |
'%nil)) |
|
(defun rewrite-sexp-expr-list (list) |
(cond ((eq (car list) '%%list) |
(rewrite-sexp-expr-list-to-cons (cdr list))) |
((eq (car list) 'quote) |
(cons '%quote (cdr list))) |
((eq (car list) 'let) |
`((%lambda anonymous (,(caaadr list)) |
(%progn |
,@(mapcar #'rewrite-sexp-expr (cddr list)))) |
,(rewrite-sexp-expr (cadr (caadr list))))) |
((eq (car list) 'defun) |
(when (< (length list) 4) |
(error "Malformed DEFUN ~A" list)) |
(let ((name (cadr list)) |
(params (caddr list)) |
(body (if (= (length list) 4) |
(rewrite-sexp-expr (cadddr list)) |
`(%progn ,@(mapcar #'rewrite-sexp-expr |
(cdddr list)))))) |
`(%define (%quote ,name) |
(%lambda ,name ,params ,body)))) |
((eq (car list) 'dolist) |
(let ((elm (cadr list)) |
(in-list (rewrite-sexp-expr (caddr list))) |
(body (rewrite-sexp-expr (cadddr list)))) |
`((%lambda |
dolist |
(_rec in-list) |
(_rec in-list)) |
(%lambda dolist-rec (lst) |
(if lst |
((%lambda inder-rec (,elm) |
(%progn |
,body |
(_rec (cdr lst))))) |
nil)) |
,in-list))) |
(t (mapcar #'rewrite-sexp-expr list)))) |
|
(defun rewrite-sexp-expr (body) |
(typecase body |
(list (rewrite-sexp-expr-list body)) |
(t body))) |
|
(defmacro sexp-to-memory* (&body body) |
`(sexp-to-memory |
,(car body) |
|
,@(loop for a in (cdr body) |
collect (rewrite-sexp-expr a)))) |
|
|
(defmacro sexp-to-memory (&body body) |
(let ((sexpvar (gensym))) |
`(let* ((*symbolinfopos* 0) |
(outlist ()) |
(symbols (loop for sym in ',(car body) |
for i from 0 |
do (setf *symbolinfopos* i) |
collect (cons sym i)))) |
(setf *symbolinfopos* *symbolstartpos*) |
(with-open-file (out |
"/tmp/initmem" |
:element-type 'character |
:direction :output |
:if-does-not-exist :create |
:if-exists :supersede) |
(let ((pos 0) |
(*symbolinfo* symbols)) |
(loop for ,sexpvar in ',(cdr body) |
do (cond ((keywordp ,sexpvar) |
(let ((addr (parse-integer (format nil "~A" ,sexpvar) :radix 16))) |
(setf outlist (append outlist (list (format nil "~%addr ~X~%" addr)))) |
(format t "Changing address from 0x~X to 0x~X~%" pos addr) |
(setf pos addr))) |
(t |
(multiple-value-bind (special list num) |
(sexp-to-memory-fun ,sexpvar) |
(declare (ignore special)) |
(incf pos num) |
(setf outlist (append outlist (listify list))))))) |
|
|
(let* ((newsymbols (nthcdr (length ',(car body)) *symbolinfo*))) |
(let* ((sympos (+ *symbolstartpos* (length newsymbols))) |
;; Build symbols and symbol names |
(symbols |
(loop for (sym . pos) in newsymbols |
collect (multiple-value-bind (special b c) |
(sexp-to-memory-fun (format nil "~A" sym)) |
(declare (ignore special)) |
(format t "Increasing sympos by: ~A for ~A~%" c sym) |
(let ((sympos* sympos)) |
(incf sympos c) |
(list b (format nil "symbol ~X ~A" sympos* sym)))))) |
(dataposition sympos) |
(symboltable-start dataposition) |
;; Build symboltable |
(symboltable (multiple-value-bind (special data len) |
(sexp-to-memory-fun (mapcar #'car newsymbols)) |
(declare (ignore special)) |
;; Link it up against the cpu symboltable |
(setf (nth (1- (length data)) data) "snoc E00") |
(incf dataposition (length data)) |
data)) |
(environment-position dataposition) |
;; Build our environment |
(env (let ((env* (list "cons +2" "snoc 0" |
"cons +2" "snoc 0" |
(format nil "cons ~X" (multiple-value-bind (special data len) |
(handle-symbol '%symbol-table) |
(declare (ignore special len)) |
data)) |
(format nil "snoc ~X" symboltable-start)))) |
(incf dataposition (length env*)) |
env*))) |
|
(let ((curpos *datastartpos*)) |
(flet ((printinc () |
;(format out "# Add ~X~%" curpos) |
(incf curpos))) |
|
;; Intial setup, start address. Pointer to expression and environment |
(format out "addr ~X~%" *datastartpos*) |
(format out "start ~X~%" *datastartpos*) |
(printinc) |
(format out "cons ~X~%" dataposition) |
(printinc) |
(format out "snoc ~X~%" environment-position) |
;; Symbols |
(format out "# Symbols~%") |
(dolist (sym (mapcar #'second symbols)) |
(printinc) |
(format out "~A~%" sym)) |
;; Symbol names |
(format out "# Symbol names~%") |
(dolist (name (mapcar #'first symbols)) |
(dolist (elem name) |
(printinc) |
(format out "~A~%" elem))) |
|
;; Symbol table |
(format out "# Symboltable~%") |
(dolist (elem symboltable) |
(printinc) |
(format out "~A~%" elem)) |
|
;; Environment |
(format out "# Environment~%") |
(dolist (elem env) |
(printinc) |
(format out "~A~%" elem)) |
|
;; Program |
(format out "# Program~%") |
(dolist (a outlist) |
(printinc) |
(format out "~A~%" a))))))))))) |
|
|
#| |
(sexp-to-memory |
(nil t if) |
(define read (lambda (str) #\b t))) |
|# |
/microprogram_assembler/some.lisp
0,0 → 1,7
(%LAMBDA (ARGS) |
(%IF ARGS |
(%IF (%EQ? (%QUOTE %.) (%CAR ARGS)) |
(%CAR (%CDR ARGS)) |
(%CONS (%CAR ARGS) |
(REC (%CDR ARGS)))) |
nil)) |
/microprogram_assembler/README
0,0 → 1,32
HOW TO USE THE MICROCODE ASSEMBLER |
|
Start SLIME: |
|
M-x slime |
|
Load the assembler (replace string by correct path): |
|
(push "/home/oystein/ntnu/lispm/lispm/mcasm/" asdf:*central-registry*) |
(asdf:operate 'asdf:load-op :mcasm) |
OR |
(require 'mcasm) [ only for sbcl ] |
|
Enter the MCASM package (in SLIME REPL buffer): |
|
, change-package RET mcasm RET |
OR <RET> |
,!p <RET> mcasm <RET> |
|
Open and load microprogram source file: |
|
C-x C-f microprogram.lisp RET |
C-c C-l RET |
|
Assemble it (from SLIME REPL buffer): |
|
To make a microcode file for the simulator, use: |
(write-microprogram :output-format :simulator) |
|
To make a microcode file for the emulator, use: |
|
(write-microprogram :output-format t) |
/microprogram_assembler/README-asm-emu.txt
0,0 → 1,24
how to do some stuff |
==================== |
|
Generate register file from microprogram: |
|
load microprogram.lisp into emacs, run it with C-c C-l |
in slime-repl buffer, run (write-register-file) |
|
Generate memory file: |
|
load sexptomem.lisp, run it |
load bootprogram.lisp, run it |
|
create a text file "keyboard" with commands |
|
|
in emulator, make run |
|
|
in another window: |
|
tail -f screen |
|
to view the output |
microprogram_assembler/README-asm-emu.txt
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property