Advertisement
Guest User

CL UM

a guest
May 24th, 2018
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 5.86 KB | None | 0 0
  1. (defpackage :um
  2.   (:use :cl)
  3.   (:export :start))
  4.  
  5. (in-package :um)
  6.  
  7. ;;; Globals
  8.  
  9. (eval-when (:compile-toplevel :load-toplevel :execute)
  10.   (defvar *operators* (make-hash-table)
  11.     "Holds all the primitive operators defined via `defop'."))
  12.  
  13. (deftype u8  () '(unsigned-byte 8))
  14. (deftype u32 () '(unsigned-byte 32))
  15.  
  16. ;;; Heap
  17.  
  18. (defconstant +heap-initial-size+ 8192)
  19.  
  20. ;;; Macros
  21.  
  22. (defmacro :reg (idx)         `(the u32 (aref %registers% ,idx)))
  23. (defmacro :op  (instruction) `(ldb (byte 4 28) ,instruction))
  24. (defmacro :a   (instruction) `(ldb (byte 3 6) ,instruction))
  25. (defmacro :b   (instruction) `(ldb (byte 3 3) ,instruction))
  26. (defmacro :c   (instruction) `(ldb (byte 3 0) ,instruction))
  27. (defmacro :mem (pos)         `(aref %heap% ,pos))
  28.  
  29. (defmacro mod32 (int)
  30.   `(logand #xFFFFFFFF ,int))
  31.  
  32. (defmacro defop (opcode name &rest body)
  33.   "Lexically defines a primitive operator.
  34.  
  35. The body of the operator is stored in *operators* and
  36. will be lexically inserted inside `fetch-decode-execute'
  37. by having `assemble' create a dispatch table. It will thus
  38. have access to the lexical environment introduced
  39. in `fetch-decode-execute'."
  40.   `(eval-when (:compile-toplevel :load-toplevel :execute)
  41.      (setf (gethash ,opcode *operators*)
  42.            (list ',name '(progn ,@body)))))
  43.  
  44. ;;; Operators
  45.  
  46. (defop 0 CMOV (unless (= (:reg c) 0) (setf (:reg a) (:reg b))))
  47.  
  48. (defop 1 ARRIDX (setf (:reg a) (aref (:mem (:reg b))
  49.                                      (:reg c))))
  50.  
  51. (defop 2 ARRSTOR (setf (aref (:mem (:reg a)) (:reg b))
  52.                        (:reg c)))
  53.  
  54. (defop 3 ADD (setf (:reg a) (mod32 (+ (:reg b) (:reg c)))))
  55.  
  56. (defop 4 MUL (setf (:reg a) (mod32 (* (:reg b) (:reg c)))))
  57.  
  58. (defop 5 DIV (setf (:reg a) (mod32 (truncate (:reg b) (:reg c)))))
  59.  
  60. (defop 6 NAND (setf (:reg a) (mod32 (lognand (:reg b) (:reg c)))))
  61.  
  62. ;; Special operators
  63.  
  64. (defop 7 HALT (setf flags 666))
  65.  
  66. (defop 8 ALLOC
  67.   (unless %free-list%
  68.     (let* ((len (length %heap%))
  69.            (new (make-array (* len 2))))
  70.       (loop :for i :across %heap% :for k :upfrom 0 :do (setf (aref new k) i))
  71.       (loop :for i :from len :to (1- (* len 2)) :do
  72.         (locally (declare (type fixnum i))
  73.           (setf %free-list% (cons i %free-list%))))
  74.       (setf %heap% new)
  75.       (format *error-output* "; Heap: ~A~%" (* len 2))))
  76.   (let ((idx (pop %free-list%))
  77.         (arr (make-array (:reg c) :initial-element 0 :element-type 'u32)))
  78.     (setf (:reg b) idx
  79.           (:mem idx) arr)))
  80.  
  81. (defop 9 FREE
  82.   (setf %free-list% (cons (:reg c) %free-list%)))
  83.  
  84. (defop 10 OUTP
  85.   (write-char (code-char (logand #xFF (:reg c))))
  86.   (force-output))
  87.  
  88. (defop 11 INP
  89.   (setf (:reg c) (handler-case (char-code (read-char))
  90.                    (end-of-file () #xFFFFFFFF))))
  91.  
  92. (defop 12 LOAD
  93.   (setf pc (:reg c))
  94.   (let ((rb (:reg b)))
  95.     (declare (type u32 rb))
  96.     (unless (zerop rb)
  97.       (let ((dup (copy-seq (:mem rb))))
  98.         (setf (:mem 0) dup
  99.               rom dup)))))
  100.  
  101. (defop 13 REGLOAD
  102.   (setf (:reg (ldb (byte 3 25) inst))
  103.         (ldb (byte 25 0) inst)))
  104.  
  105. ;;; Utility functions
  106.  
  107. (defun read-program (program-file)
  108.   (with-open-file (stream program-file :element-type 'u8)
  109.     (let* ((len (truncate (file-length stream) 4))
  110.            (array (make-array len :element-type 'u32)))
  111.       (declare (type (simple-array u32 (*)) array))
  112.       (format t "; Loading..~%")
  113.       (loop :with start = (get-internal-real-time)
  114.             :repeat len
  115.             :for b1 = (read-byte stream) :for b2 = (read-byte stream)
  116.             :for b3 = (read-byte stream) :for b4 = (read-byte stream)
  117.             :for idx :upfrom 0 :do
  118.               (setf (aref array idx)
  119.                     (logior (ash b1 24) (ash b2 16) (ash b3 8) b4))
  120.             :finally
  121.                (format t "; Read ~A bytes in ~A secs from ~A~%"
  122.                        (* len 4)
  123.                        (float (/ (- (get-internal-real-time) start)
  124.                                  internal-time-units-per-second))
  125.                        program-file))
  126.       array)))
  127.  
  128. (defmacro assemble (opc)
  129.   "Create a dispatch table based on the operators we have defined with `defop'."
  130.   `(case ,opc
  131.      ,@(loop
  132.          :with values = '()
  133.          :for op :being :the :hash-keys :in *operators*
  134.          :using (hash-value v)
  135.          :for code = (second v)
  136.          :unless (= op 13)
  137.          :do (push (list op code) values)
  138.          :finally (return (sort values #'< :key #'first)))
  139.      (otherwise (error "Unknown opcode: ~A" ,opc))))
  140.  
  141. (defmacro fetch-decode-execute (program)
  142.   `(let* ((pc 0) (flags 0) (a 0) (b 0) (c 0) (opc 0)
  143.           (inst 0)
  144.           (%free-list% (loop :for i :from 1 :to (1- +heap-initial-size+) :collect i))
  145.           (%registers% (make-array 8 :element-type 'u32 :initial-element 0))
  146.           (%heap% (make-array +heap-initial-size+))
  147.           (rom ,program))
  148.      (declare (type u32 pc inst)
  149.               (type fixnum flags)
  150.               (type (unsigned-byte 3) a b c)
  151.               (type (unsigned-byte 4) opc)
  152.               (type (simple-array u32 (*)) rom)
  153.               (type (simple-array u32 (8)) %registers%)
  154.               (type (simple-array (simple-array u32 1) 1) %heap%)
  155.               ;; try and stack allocate the registers array
  156.               (dynamic-extent %registers%))
  157.      (setf (:mem 0) rom)
  158.      ;; Interpreter loop
  159.      (loop :while (/= flags 666) :do
  160.        (setf inst (aref rom pc)
  161.              opc (:op inst)
  162.              pc (mod32 (1+ pc)))
  163.        (if (= 13 opc)
  164.            ,(second (gethash 13 *operators*))
  165.            (progn (setf a (:a inst)
  166.                         b (:b inst)
  167.                         c (:c inst))
  168.                   (assemble opc))))))
  169.  
  170. ;;; Main
  171.  
  172. (defun start (program-file)
  173.   (declare (optimize (speed 3) (debug 0) (space 0) (safety 1)
  174.            (compilation-speed 0)))
  175.   (let ((data (read-program program-file)))
  176.     (time (fetch-decode-execute data))))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement