;;; -*- Mode:LISP; Package:SIM; Base:10; Readtable:ZL -*- ;;; Expansion of K machine symbolic instructions ;;; into Lisp code with calls to simulator functions ;;; (MOVE O2 A3) ;;; (MOVE RETURN A1 CH-RETURN) ;;; (MOVE O0 A1 CH-OPEN) ;;; (ALU L+R a0 A2 A3 CH-OPEN) ;;; (ALU L+R+1 RETURN '0 A1 CH-RETURN) ;;; (TEST BR-EQUAL) ;;; (BRANCH FOO) ;;; (BRANCH FOO (MOVE A0 A1)) ;;; (BRANCH FOO (MOVE A0 A1) CH-OPEN) ;;; (BRANCH FOO (ALU L+R O0 A1 A2) CH-OPEN) ;;; (KCALL FOO '3 A0 (O0 A1) CH-OPEN) ;;; (KCALL FOO '3 O0) ;;; (KOPEN) ;;; (OPEN-CALL CAR '1 O1 (O0 A1)) ;;; (TAIL-CALL FOO '2) ;;; (TAIL-CALL FOO '2 (O1 A2)) ;;; (JUMP FOO) ;;; (JUMP FOO (A0 A1)) (defparameter *statistics-p* t) (defparameter *i-time* 75. "Instruction cycle time in nanoseconds") (defvar *i-count* 0) (defun do-stats () (cond (*statistics-p* `(incf *i-count*)) (t nil))) (defun stats (form) (setq *i-count* 0) (prog1 (eval form) (format t "~&~d Instruction~:p, ~,9f Seconds (~dns//Inst)" *i-count* (* *i-count* *i-time* 1e-9) *i-time*))) (defvar *global-registers* '()) (defmacro defreg (name frame offset) `(progn (pushnew (list ',name ,frame ,offset) *global-registers*) (defvar ,name))) ;;;; Alu Ops (defmacro K:L+R+1 (l r) `(1+ (+ ,l ,r))) (defmacro K:L+R-1 (l r) `(1- (+ ,l ,r))) (defmacro K:L+R (l r) `(+ ,l ,r)) (defmacro K:L-R (l r) `(si:%pointer-difference ,l ,r)) ; `(- ,l ,r)) (defmacro K:SETR (l r) (declare (ignore l)) r) (defmacro K:SETL (l r) (declare (ignore r)) l) (defmacro K:ALU-OR (l r) `(logior ,l ,r)) (defmacro K:ALU-AND (l r) `(logand ,l ,r)) ;;; Optional fields (defvar *default-options* ()) (defmacro def-option (name default arglist &body body) `(progn (pushnew ',default *default-options*) (setf (get ',name 'option-default) ',default) (defmacro ,name ,arglist ,@body))) (defun do-options (options left right) (let ((defaults *default-options*)) `(progn ,(do-stats) ,@(mapcar #'(lambda (option) (setq defaults (remove (get option 'option-default) defaults)) (list option left right)) options) ,@(mapcar #'(lambda (option) (list option left right)) defaults)))) ;;;; Call Hardware (def-option K:CH-NOOP K:CH-NOOP (l r) nil) (def-option K:CH-OPEN K:CH-NOOP (l r) (declare (ignore l r)) `(%k-open)) (def-option K:CH-TAIL-OPEN k:CH-NOOP (l r) (declare (ignore l r)) `(%k-t-open)) ;;; this is done in the dest (def-option K:CH-RETURN K:CH-NOOP (l r) (declare (ignore l r)) nil) ;;;; Branch Conditions ;;; This is not quite right ;;; because it should test TEMP of the last instruction ;;; (before the one with the condition) but either this ;;; instruction or the branch might change TEMP ... (defvar *condition* 'always) (def-option K:BR-NEVER K:BR-NEVER (l r) (setq *condition* 'nil) nil) (def-option K:BR-ALWAYS K:BR-NEVER (l r) (declare (ignore l r)) (setq *condition* 'true) nil) (def-option K:BR-EQUAL K:BR-NEVER (l r) (declare (ignore l r)) (setq *condition* '(zerop temp)) nil) (def-option K:BR-NOT-EQUAL K:BR-NEVER (l r) (declare (ignore l r)) (setq *condition* '(not (zerop temp))) nil) (def-option K:BR-NOT-LESS-THAN K:BR-NEVER (l r) (declare (ignore l r)) (setq *condition* '(not (< temp 0))) nil) (def-option K:BR-NOT-GREATER-THAN K:BR-NEVER (l r) (declare (ignore l r)) (setq *condition* '(not (> temp 0))) nil) (def-option K:BR-NOT-LESS-THAN-OR-EQUAL K:BR-NEVER (l r) (declare (ignore l r)) (setq *condition* '(not (<= temp 0)))) ;;;; Data type checking (defun trap (trap) (error "Trap: ~a" trap)) (def-option K:DT-NOOP K:DT-NOOP (l r) (declare (ignore l r)) nil) (def-option K:DT-BOTH-FIX K:DT-NOOP (l r) `(unless (and (fixp ,l) (fixp ,r)) (trap 'not-both-fix))) ;;;; Sources ;;; specifies a global register (defmacro K:%REGISTER (name frame offset) name) (defmacro K:%VALUE-CELL (name) name) ;;;; Destinations (defvar *functional-destinations* '(K:MD K:VMA)) (defun store-dest (dest options) (cond ((or (member dest *active-registers*) (member dest *open-registers*) (member dest *return-registers*)) `((setq ,dest temp))) ((and (eq dest 'K:RETURN) (member 'K:CH-RETURN options)) `((%k-return temp))) ((eq (car-safe dest) 'K:%REGISTER) (if (memq (cadr dest) *functional-destinations*) `((,(cadr dest) temp)) `((setq ,(cadr dest) temp)))) (t `((,dest temp))))) (defmacro K:GARBAGE (value) (declare (ignore value)) ()) ;---------------------------------------------------------------- ;;;; Instructions ;;; temp represents the value on the output of the ALU ;;; before it gets put in a dest (defmacro K:ALU (op dest left right &rest options) `(progn (setq temp (,op ,left ,right)) ,(do-options options left right) . ,(store-dest dest options))) (defmacro K:MOVE (dest source &rest options) `(K:ALU K:SETR ,dest '0 ,source . ,options)) (defmacro K:KDPB (dest left right ppss &rest options) `(progn (setq temp (dpb ,left ,ppss ,right)) ,(do-options options left right) . ,(store-dest dest options))) (defmacro K:KCALL (tag nargs dret &optional move &rest options) (declare (zl:arglist tag nargs dret (dest source) &rest options)) `(progn ,(if move `(K:MOVE ,(car move) ,(cadr move) . ,options) (do-options options nil nil)) (%k-call #',tag ,(cadr nargs) (locf ,(if (eq dret 'IGNORE) 'temp dret))))) (defmacro K:TAIL-CALL (tag nargs &optional move &rest options) (declare (zl:arglist tag nargs (dest source) &rest options)) `(progn ,(if move `(K:MOVE ,(car move) ,(cadr move) . ,options) (do-options options nil nil)) (%k-t-call #',tag ,(cadr nargs)))) (defmacro K:OPEN-CALL (tag nargs dret &optional move &rest options) (declare (zl:arglist tag nargs dret (dest source) &rest options)) `(K:KCALL ,tag ,nargs ,dret ,move K:CH-OPEN . ,options)) (defmacro K:OPEN-TAIL-CALL (tag nargs &optional move &rest options) (declare (zl:arglist tag nargs (dest source) &rest options)) `(K:TAIL-CALL ,tag ,nargs ,move K:CH-TAIL-OPEN . ,options)) ;;; this is not right (defmacro K:KOPEN () `(progn ,(do-stats) (%k-open))) (defmacro K:TAIL-OPEN () `(progn ,(do-stats) (%k-t-open))) (defmacro K:JUMP (tag &optional move &rest options) (declare (zl:arglist tag (dest source) &rest options)) `(progn ,(if move `(K:MOVE ,(car move) ,(cadr move) . ,options) (do-options options nil nil)) (go ,tag))) (defmacro K:TEST (cond) `(progn ,(do-stats) (,cond nil nil))) (defmacro K:BRANCH (tag &optional alu &rest options) `(progn ,(if alu `(K:ALU ,alu . ,options) (do-options options nil nil)) (if ,*condition* (go ,tag))))