4,887,235
	55	56
APPENDIX
F:>lmach>ucode>BETTER-SPRINTER.LISP.17

;;; -*- Mode:Lisp; Package:Micro; Base:8; Lowercase:yes -*-
;;; (c) Copyright 1982, Symbolics, Inc.

; "If I have seen less far and less clearly than others, it is because
; giants were standing on my shoulders." -- Sir Isaac Oldfield

(defvar *bs-widths*)
(defvar	*bs-sem-miser-widths*)
(defvar *bs-miser-widths*)
(defvar *bs-flatsizes*)
#Q
(defvar *bs-lines* 95.)

(defun better-sprinter (form)
  (terpri)
  (better-sprinter-1 form))

(defun better-sprinter-1 (form)
  (let ((*bs-widths* nil)
	(*bs-semi-miser-widths* nil)
	(*bs-miser-widths* nil)
	(*bs-flatsizes* nil)
	#M (stream (if ^r (car outfiles) tyo)))
    (bs-print form (bs-charpos) #M (line1 stream) #Q *bs-line1*)
    '*))

4,887,235
	57	58
(defun bs-charpos ()
	#M (charpos (if ^r (car outfiles) tyo))
	#Q (funcall standard-output ':read-cursorpos ':character))

(defun bs-flatsize (form &aux tem)
  (cond ((setq tem (assq form *bs-flatsizes*))
	(cdr tem))
	(t (setq tem (flatsize form))
	(push (cons form tem) *bs-flatsizes*)
	tem)))

(defun bs-width (form &aux tem)
  (cond ((atom form) (bs-flatsize form))
	((setq tem (assq form *bs-semi-miser-widths*))
	 (car tem))
	(t (setq tem (bs-width-3 form tem))
	   (push (cons form tem) *bs-semi-miser-widths*)
	   tem)))

(defun bs-semi-miser-width (form &aux tem)
  (cond ((atom form) (bs-flatsize form))
	((setq tem (assq form *bs-semi-miser-widths*))
	 (cdr tem))
	((null (setq tem (bs-format form)))
	 (bs-width form))
	(t (setq tem (bs-width-3 form tem))
	   (push (cons form tem) *bs-semi-miser-widths*)
	   tem)))

(defun bs-miser-width (form &aux tem)
  (cond ((atom form) (bs-flatsize form))
	((setq tem (assq form *bs-miser-widths*))
	 (cdr tem))
	(t (setq tem (bs-width-2 form))
	   (push (cons form tem) *bs-miser-widths*)
	   tem)))

(defun bs-width-2 (form)
  (1+ (loop for l = form then (cdr l) ;1+ for leading open paren or apace
	    when (and (atom l) (not (null l)))
	    maximize (+ (bs-width l) 3) fixnum	;dot sp close
	    while (not (atom l))
	    when (cdr l)
	    maximize (bs-width (car l)) fixnum
	    else maximize (1+ (bs-width (car l))) fixnum)))	;+1i for close

(defun bs-width-1 (form &aux (fmt (bs-format form)))
  (cond ((null fmt)
	 (+ (bs-width (car form)) 2	;2 for open paren and space
	    (loop for l = (cdr form) then (cdr l)
		  when (and (atom l) (not (null l)))
		  maximize (+ (bs-width l) 3) fixnum ;dot sp close
		  while (nor (atom l))
		  when (cdr l)
		  maximize (bs-width (car l)) fixnum
		  else maximize (1+ (bs-width (car l))) ;1+ for close paren
		  fixnum)))
	(t (let ((head (car fmt))
		 (n-per-line (cadr fmt)))
	     (+	(loop for x in form repeat head
		      sum (1+ (bs-flatsize x)) fixnum)
		(if (zerop head) 0 1)
		(loop for l = (nthcdr head form) then ll until (null l)
		      as ll = (nthcdr n-per-line l)
		      maximize (+ (if ll -1 0) ;for close paren
				  (loop for x in l repeat n-per-line))))))))

(defun bs-width-3 (form fmt)
  (let ((head (car fmt))
	(n-per-line (cadr fmt))
	(indentation (caddr fmt)))
    (max (loop for x in form repeat head
	       sum (1+ (bs-flatsize x)) fixnum)
	 (+ indentation
	    (loop for l = (nthcdr head form) then ll until (null l)
		  as ll = (nthcdr n-per-line l)
		  maximize (+ (if ll -1	0) 	;for close paren
			      (loop for	x in l repeat n-per-line
				    sum	(1+ (bs-semi-miser-width x)) fixnum))
		  fixnum)))))

(defun bs-format (form)
  (and (not (atom form))
       (not (dotted-p form))
       (if (symbolp (car form))
	   (get (car form) 'bs-format)
	 '(0 1 1))))	;Good for selectq clauses at least

4,887,235
	59	60
(defun bs-print	(form indent line1)
  (if (atom form) (prin1 form)
    (let ((fmt (bs-format form))
	  (space (- line1 indent)))
	  (cond ((and (or (null fmt) (not (symbolp (car form))))
		      (<= (bs-flatsize form) space))
		 (prin1 form))
		((<= (bs-width form) space)
		 (bs-print-1 form indent line1 fmt))
		((and fmt (<=- (bs-semi-miser-width form) space))
		 (bs-print-3 form indent line1 fmt))
		(t (bs-miser form indent line1))))))

(defun bs-print-1 (form indent line1 fmt)
  (princ "(")
  (cond ((null fmt)
	 (bs-print (car form) (1+ indent) line1)
	 (princ " ")
	 (setq indent (bs-charpos))
	 (loop for l = (cdr form) then (cdr l)
	       when (and (atom l) (not (null l)))
	       do (princ ",  ") (bs-print l (+ indent 2) line1)
	       while (not (atom l))
	       do (bs-print (car l) indent line1)
	       when (cdr l) do (bs-terpri indent)))
	(t (let ((head (car fmt))
		 (n-per-line (cadr fmt)))
	     (bs-row-of form head (1+ indent) line1)
	     (or (zerop head) (princ " "))
	     (setq indent (bs-charpos))
	     (loop for l = (nthcdr head form) then ll until (null l)
		   as ll = (nthcdr n-per-line l)
		   do (bs-row-of l n-per-line indent line1)
		   unless (null ll) do (bs-terpri indent)))))
  (princ ")"))

(defun bs-print-3 (form indent line1 fmt)
  (princ "(")
  (let ((head (car fmt))
	(n-per-line (cadr fmt))
	(indentation (caddr fmt)))
    (bs-row-of form head (1+ indent) line1)
    (setq indent (+ indent indentation))
    (or (zerop head) (null (nthcdr head form)) (bs-terpri indent))
    (loop for l = (nthcdr head form) then ll until (null l)
	  as l = (nthcdr n-per-line l)
	  do (bs-row-of l n-per-line indent line1)
	  unless (null ll) do (bs-terpri indent)))
  (princ ")"))

(defun bs-row-of (list n indent line1)
  (or (zerop n)
      (loop for x in list as i upfrom 1
	    do (bs-print x indent line1)
	    until (= i n)
	    do (princ " ") (setq indent (bs-charpos)))))

(defun bs-terpri (indent)
  (terpri)
  (loop repeat (// indent 8) do (tyo #\tab))
  (loop repeat (\ indent 8) do (tyo #\sp)))

(defun bs-miser (form indent line1)
  (cond ((atom form) (prin1 form))
	(t (princ "(")
	   (setq indent (1+ indent))
	   (loop for l = form then (cdr l)
		 when (and (atom l) (not (null l)))
;XXXbrad end missing!
		 ))))
F:>lmach>ucode>check.lisp.116

;;; -*- Mode:Lisp; Packaqe:Micro: Base:8; Lowercase:yes -*-
;;; (c) Copyright 1982, Symbolics. Inc.

; Microcode Syntax Checking

;This is an alist of all fields.
;car of an entry is the name of the field
;cadr is a list of other fields required: elements are either names
; of fields, or lists of name and acceptable values
;caddr is value checking for this field: nil to accept any value, or
; a predicate which returns t if the v3lue is OK. or a list of valid values.
;Note that some values for some of these fields are redundant with
; the spec and/or magic fields.
(defconst valid-microcode
  '((abus () (amem memory-data frame-pointer stack-pointer lbus
	      memory-data-force vma pc map	;on TMC machine
	      ))
    (amem-read-addr ((abus amem memory-data)) check-amem-addr)
    (bbus () (bmem macro-signed-immediate macro-unsigned-immediate))
4,887,235
	61	62
    (bmem-read-addr ((bbus bmem)) check-bmem-addr)
    (write-amem (amem-write-addr) (obus))
    (amem-write-addr () check-amem-non-constant-addr)
    (write-bmem (bmem-write-addr) (xbus obus))
    (bmem-write-addr (write-bmem) numberp)
    (write-lbus () (obus memory-data junk))
    (lbus-dev-addr () check-lbus-dev-addr)
    (xbus () (abus bbus product))
    (ybus () (abus bbus ybus-crocks-1 ybus-crocks-2))
    (alu () check-alu-func)
    (byte-func () check-byte-func)
    (force-obus<34-34> () (0 1 2 3 abus bbus bbus<7-6>))
    (force-obus<33-32> () (0 1 2 3 abus bbus bbus<5-4>))
    (force-obus<3l-28> () (0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17))
    (type-map () check-type-map)
    (stack-pointer () (increment decrement))
    (spec () (load-byte-r load-byte-s load-stkp load-frmp
			  load-xbas load-control load-special-maps clear-stack-adjustment
			  arthmetic-trap-enb trap-if-type-cond
			  trap-if-type-cond-or-bbus-not-fixnum multiply-and-type-check
			  crocks alub-sign-hack crocks-to-ybus multiply
			  addr-from-abus inhibit-page-tags dma address-phtc
			  check-write-access increment-inst ifu-control
			  arithmetic-trap-with-dispatch halt npc-magic awaken-task
			  write-task disable-tasking))
    (magic () (0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17))
    (magic-mask (magic) (1 2 3 4 5 6 7 10 11 12 13 14 15 16))
    (dispatch (dispatch-table magic)
	      (alub cdr-code abus<31-28> abus<25-22>
		    abus<21-18> abus<2-0> bbus<31-30>-abus<31-30>))
    (mem () (write-vma start-cycle	;proto
		       microdevice start-read start-write write-vma block-read block-write)) ;TMC
    (escape-to-lisp () nil)
    (error-table () nil)
    (declare-memory-timing () nil)
    (condition ()
	       (not-cdr-0 not-cdr-1 not-cdr-2 not-cdr-3
			  type-condition bbus-not-fixnum alub-0 ybus-31
			  not-gc-condemned-temp not-gc-this-stack not-gc-other-stack
			  equal-pointer
			  not-equal-fixnum not-equal-typed-pointer
			  not-greater-pointer not-greater-fixnum-unsigned
			  alu-31 sequence-break trace-flag-1 trace-flag-2
			  not-lbus-dev-cond mc-cond not-ctos-came-from-ifu
			  ))
    (sequencer () (popj next-instruction pushj pop push-npc pop-npc
			dismiss pop-npc-and-cpc-from-npc
			take-dispatch pushj-return-dispatch))
    (trap-enables () check-trap-enables)
    (skip-true-sequence (condition skip-false-sequence)
			check-skip-sequence)
    (skip-false-sequence (condition skip-true-sequence)
			 check-skip-sequence)
    (return-true-sequence (return-false-sequence)
			  check-skip-sequence)
    (return-false-sequence (return-true-sequence)
			   check-skip-sequence)
    (return-skip () (t))
    (jump-sequence () check-next-sequence)
    (next-sequence () check-next-sequence)
    (trap-sequence (trap-enables) check-trap-sequence)
    (dispatch-table (dispatch) check-dispatch-table)
    (arith-trap-dispatch-table (spec trap-enables) check-dispatch-table)
    (unique () (t))
    (speed () (slow-first-half slow-second-half slow very-slow))))

;Each element is a list of (field value) pairs where if the first
;one is present, the others are disallowed.
(defconst microcode-field-conflicts
  '(((xbus abus) (ybus abus) "Xbus and Ybus sources not independently selectable")
    ((xbus bbus) (ybus bbus) "Xbus and Ybus sources not independently selectable")
    ((sequencer next-instruction) (spec ifu-control) "Next inst not ready")
    ((abus vma) (mem start-read start-write block-read block-write)
     "Reading YMA uses ADDR outputs")
    ((abus lbus) (ybus abus)
     "Microdevice read is just too slow, must go into the fast side of the ALU")
))

#M (declare (*expr fieldp))  ;in UU

(declare (special *backtrace*)) ;in UU
(defvar *code*)		;So I can see the microinstruction being checkod

#M
(defun check-loses (format &rest args)
  (declare (special args))
  (let ((^w nil) (^r nil) (^q nil))
    (terpri msgfiles)
    (lexpr-funcall #'format msgfiles format args)
    (format msgfiles "~&;~{~<~%;~:; in ~S~>~)~%" *backtrace*)
    (format msgfiles "~&; Do (PPX *CODE*) to see instruction.")
    (break check-loses)))

4,887,235
	63	64
#Q
(defflavor check-loses (format-string format-args code)
  (sys:no-action-mixin dbg:special-commands-mixin error)
  :initable-instance-variables)
#Q
(defmethod (check-loses :report) (stream)
  (lexpr-funcall #'format stream format-string format-args))
#Q
(defmethod (check-loses :case :special-command :show-failing-microinstruction) ()
  "Pretty-print the microinstruction that failed"
  (ppx code)
  nil) ;NIL means stay in the debugger
#Q
(push '(:show-failing-microinstruction #\c-sh-P) dbg::*special-command-special-keys*)
#Q
(compile-flavor-methods check-loses)
#Q
(defprop check-loses t :error-reporter)
#Q
(defun check-loses (format-string &rest args)
  (signal 'check-loses ':format-string format-string
	  	       ':format-args (copylist args)
		       ':code *code*))

(defun check-conflict (code field1 field2 &optional message)
  (check-loses "~e[~A~%~](~S ~S) conflicts with (~S ~S)"
	       message field1 (get code field1) field2 (get code field2)))

(defun check-amem-addr (addr)
  (if (atom addr)
      (and (eq (typep addr) 'fixnum) (<= 0 addr) (<= addr 3777))
    (selectq (car addr)
      ((frame-pointer stack-pointer xbas) (eq (typep (cadr addr)) 'fixnum))
      (macrocode (null (cdr addr)))
      (constant (valid-constant (cadr addr)))
      (bus-address (null (cdr addr))))))

(defun check-amem-non-constant-addr (addr)
  (if (atom addr)
      (and (eq (typep addr) 'fixnum) (<= 0 addr) (<= addr 3777))
    (selectq (car addr)
      ((frame-pointer stack-pointer xbas) (eq (typep (cadr addr)) 'fixnum))
      (macrocode (null (cdr addr)))
      (bus-address (null (cdr addr))))))

(defun check-bmem-addr (addr)
  (if (atom addr)
      (and (eq (typep addr) 'fixnum) (<= 0 addr) (<= addr 377))
    (and (eq (car addr) 'constant)
	 (valid-constant (cadr addr)))))

(defun valid-constant (val)
  (or (numberp val)
      (and (listp val)
	   (eq (car val) 'build-task-state))))

(defun check-lbus-dev-addr (addr)
  (or (numberp addr)
      ;; Also used to select MC destinations
      (memq addr (selectq *machine-version*
		   ((sim proto) '(write-memory))
		   ((tmc) '(write-phta-and-asn write-vma-and-pc
			    write-lru-map write-map-a write-map-b write-both-maps))
		   ((tmc5 ifu) '(write-phta-and-asn
				 write-map-a write-map-b write-both-maps))))
      ;; Also synbol 0 card slots
      (and (listp addr)	(get (car addr)	'symbolic-lbus-slot))))

(declare (special normal-alu-functions weird-alu-functions))	;in UU

(defun check-alu-func (func)
  (cond ((memq func (if (and (or (fieldp *code* 'spec 'arithmetic-trap-enb)
				 (fieldp *code* 'spec 'arithmetic-trap-with-dispatch))
			     (bit-test 4 (get *code* 'magic)))
			weird-alu-functions
		        normal-alu-functions)))
	((memq func weird-alu-functions)
	 (check-conflict *code* 'alu 'spec
			 "ALU function is wierd, but special function and # not specified")
	 t)
	((memq func normal-alu-functions)
	 (check-conflict *code* 'alu 'spec
			 "ALU function is normal, but spec says /"weird ALU function/"")
	 t)))

(defun check-byte-func (func)
  (or (eq func 'ybus)				;Function 0
      (and (listp func)
	   (memp (first func) '(ldb dpb))	;Other funcs, decided later
	   (let ((rot (secord func)) (mask (third func)))
	     (or (and (eq (typep rot) 'fixnum) (<= 0 rot) (<= rot 37)
4,887,235
	65	66
		      (eq (typep mask) 'fixnum) (<= 1 mask) (<= mask 40))
		 (and (eq rot 'byte-r)
		      (or (eq mask 'byte-s)
			  (eq (typep mask) 'fixnum) (<= 1 mask) (<= mask 40)))
		 (and (eq rot 'macro) (eq mask 'macro))))
	   (or (null (cdddr fund))
	       (eq (cadddr func) 'merge)))))


(declare (special *data-types* *cdr-codes*))	;in SIM

;Check that types are valid, outputs are one of the 8 possible combinations,
;and no types are duplicated
(defconst type-map-possibilities
  '(() (cond) (pointer) (pointer cond)
    (trap-0) (trap-1) (trap-2 pointer) (trap-3 pointer)
    ;Alternate spellings
    (cond pointer) (pointer trap-2 (pointer trap-3)))
;XXXbrad added closing paren - missing?
  )

(defun check-type-map (x)
  (loop for ((types . outputs) . rest) on x
	always (loop for tp in types
		     always (memq tp *data-types*)
		     always (loop for (t2 . o2) in rest
				  never (memq tp t2)))
	always (member outputs type-map-possibilities)))

;This is not one field in the real machine. Some of these are inside the
;type map, also.
(defun check-trap-enables (x)
  (loop for en in x
	always (memq en '(condition-true condition-false any-stack other-stack
					 type-condition bbus-non-fixnum overflow
					 transport map-miss))))

;Try to propogate memory timing through skips.
;This is smart enough to get it in, but too dumb to know how to get it out again
(defun check-skip-sequence (seq memory-timing)
  (cond ((null seq))		;drop-through
	((symbolp seq))		;jump tag
	(t (check-microcode seq 'skip-sequence memory-timing) ;literal code
	   t)))

(defun check-next-sequence (seq)
  (cond ((symbolp seq))				;jump tag
	(t (check-microcode seq 'next-sequence) ;literal code
	   t)))

(defun check-trap-sequence (seq)
  (cond ((symbolp seq))				;jump tag
	(t (check-microcode seq 'trap-sequence)	;literal code
	   t)))

(defun check-dispatch-table (table)
  (setq table (cdr table))			;Ignore field specifier at front
  (if (not (listp table))
      (check-loses "Not table of dispatch clauses: ~S" table)
    (loop for clause in table
	  unless (eq (car clause) 'otherwise)
	  do (loop for cue in (car cause)
		   unless (numberp cue)		;good enough check for now
		   do (check-loses "~S invalid dispatch cue" cue))
	  do (cond ((atom (cadr clause)))	;goto
		   (t (check-microcode (cadr clause)
				       `(dispatch ,(car clause)))))))
  t)

(defun check-microcode (*code* where &optional memory-timing)
  (let ((*backtrace* (cons where *backtrace*)))
    (cond ((and (not (atom *code*)) (eq (car *code*) 'microinstruction))
	   (check-microcode1 *code* memory-timing))
	  ((and (not (atom *code*)) (eq (car *code*) 'microsequence))
	   (push 'microsequence *backtrace*)
	   (loop for x in (cdr *code*)
		 do (if	(and (not (atom x)) (eq (car x) 'microinstruction))
			(let ((*code* x))
			  (setq memory-timing (check-microcode1 x memory-timing)))
		      (check-loses "Invalid microcode: ~S x"))))
	  (t (check-loses "Unrecognizable microcode: ~S" *code*)))))

(defun check-microcode1 (code memory-timing &aux declared-memory-timing)
  ;; First make sure there aren't any misspelled field names, since
  ;; those typically cause spurious other messagee
  (loop for (field value) on (cdr code) by 'cddr
	when (null (assq field valid-microcode))
	do (check-loses "~S invalid microcode field name" field))
  ;; Now check inter-field consistency
  (check-field-conflicts code)
  (check-spec-and-magic-fields code)
  (check-next-address-field-consistency code)
  ;; Check the memory timing for temporary memory control
4,887,235
	67	68
  (if (setq declared-memory-timing (get code 'declare-memory-timing))
      (setq memory-timing declared-memory-timing))
  (and (fieldp code 'abus 'memory-data)
       (not (memq 'data-cycle memory-timing))
       (check-loses "Reading MD but memory is not in data-cycle (it's in ~S)" memory-timing))
  (and (fieldp code 'lbus-dev-addr 'write-memory)
       (not (memq (get code 'mem) '(start-cycle start-write block-write)))
       (check-loses "Storing into memory without starting a cycle"))
  ;; Compute memory-timing value for following cycle
  (let ((next-active (or (member '(next active-cycle) declared-memory-timing)
			 (memq (get code 'mem) '(start-cycle start-read block-read))))
	(next-data (or (member '(next data-cycle) declared-memory-timing)
		       (memq 'active-cycle memory-timing))))
    (setq memory-timing (if next-active
			    (if next-data '(active-cycle data-cycle) '(active-cycle))
			  (if next-data '(data-cycle) nil))))
  ;; On TMC machine, make sure that microdevice read/write is going in the proper
  ;; direction. Using Lbus as the Abus source implies microdevice read.
  (cond ((memq *machine-version* '(tmc tmc5 ifu))
	 (and (get code 'write-lbus)
	      (fieldp code 'abus 'lbus)
	      (check-loses "Lbus as Abus source incompatible with microdevice//VMA write"))
	 (and (get code 'write-lbus)
	      (not (memq (get code 'mem) '(microdevice write-vma)))
	      (check-loses "WRITE-LBUS without MEM// MICRODEVICE or WRITE-VMA"))
	 (and (neq *machine-version* 'ifu)
	      (fieldp code 'write-lbus 'obus)
	      (fieldp code 'abus 'memory-data)
	      (check-loses "WRITE-LBUS from OBUS but ABUS source is MEMORY-DATA;~e
			   TMC machine will write from MD rather than OBUS!"))))
  ;; Now check field values, and successor instructions
  (loop for (field value) on (cdr code) by 'cddr with tem
    as d = (assq field valid-microcode)
    when (null value)
    unless (memq field '(skip-true-sequence skip-false-sequence)) ;drop-thr
    do (check-loses "~S field has NIL value" field)
    do (loop for c in (cadr d)
	     when (atom c)
	     do (or (loop for f in (cdr code) by 'cddr thereis (eq f c))
		    (check-loses "~S field missing when ~S ~S present"
				 c field value))
	     else do (or (member (setq tem (get code (car c))) (cdr c))
			 (check-loses
			  "~S field has value ~S, invalid when ~S ~S present"
			  (car C) tem field value)))
    as checker = (caddr d)
    unless (cond ((null checker))
		 ((symbolp checker)
		  (if (memq field '(skip-true-sequence skip-false-sequence
				    return-true-sequence return-false-sequence))
		      (funcall checker value memory-timing)
		    (funcall checker value)))
		 (t (member value checker)))
    do (check-loses "~S illegal value for ~S field" value field))
  memory-timing)

(defun check-field-conflicts (code)
  (loop for ((f1 v1) (f2 . exclusions) reason) in microcode-field-conflicts
	when (eq (get code f1) v1)
	when (memq (get code f2) exclusions)
	do (check-conflict code f2 f1 reason)))

;If other fields imply values of these, check that they are really there
(defun check-spec-and-magic-fields (code &aux tem tem1)
  (and (setq tem (get code 'force-obus<31-28>))
       (not (fieldp code 'magic tem))
       (check-conflict code force-obus<31-28> 'magic))
  (cond ((or (fieldp code 'ybus 'ybus-crocks-1)
	     (fieldp code 'ybus 'ybus-crocks-2))
	 (or (fieldp code 'spec 'crocks-to-ybus)
	     (check-conflict code 'ybus 'spec))
         ;U AMWA <11> must also be free
	 (if (get code 'stack-pointer)
	     (check-conflict code 'ybus 'stack-pointer "U AMWA <11> conflict"))
	 (if (numberp (get code 'amem-write-addr))
	     (check-conflict code 'ybus 'amem-write-addr "U AMWA <11> conflict"))))
  (cond ((fieldp code 'xbus 'product)
	 (or (fieldp code 'spec 'multiply)
	     (fieldp code 'spec 'multiply-and-type-check)
	     (check-conflict code 'xbus 'spec))
	 (or (= (logand (get code 'magic) 6) 4)
	     (check-conflict code 'xbus 'magic))))
  (cond ((setq tem (get code 'trap-enables))
	 (cond ((memq 'other-stack tem)
		(or (fieldp code 'spec 'crocks)
		    (check-conflict code 'trap-enables 'spec
				    "spec//crocks needed to enable GC traps"))
		(or (equal (get code 'magic) 2)
		    (check-conflict code 'trap-enables 'magic
				    "magic number needed to enable GC traps")))
4,887,235
	69	70
	       ((memq 'any-stack tem)
		(or (fieldp code 'spec 'crocks)
		    (check-conflict code 'trap-enables 'spec
				    "spec//crocks needed to enable GC traps"))
		(or (equal (get code 'magic) 1)
		    (check-conflict code 'trap-enables 'magic
				    "magic number needed to enable GC traps")))
	       ((memq 'type-condition tem)
		(cond ((memq (get code 'spec)
			     '(arithmetic-trap-enb arithmetic-trap-with-dispatch))
		       (or (bit-test 1 (get code 'magic))
			   (check-conflict code 'trap-enables 'magic
					   "Magic number needed to enable type cond trap")))
		      ((memq (get code 'spec)
			     '(trap-if-type-cond
			       trap-if-type-cond-or-bbus-not-fixnum
			       multiply-and-type-check)))
		      (t (check-conflict code 'trap-enables 'spec
					 "Spec needed to enable type cond trap"))))
	       ((memq 'bbus-non-fixnum tem)
		(cond ((memq (get code 'spec)
			     '(arithmetic-trap-enb
			       arithmetic-trap-with-dispatch))
		       (or (bit-test 2 (get code 'magic))
			   (check-conflict code 'trap-enables 'magic
					   "Magic number needed to enable bbus type trap")))
		      ((memq (get code 'spec)
			     '(trap-if-type-cond-or-bbus-not-fixnum
			       multiply-and-type-check)))
		      (t (check-conflict code 'trap-enables 'spec
					 "Spec needed to enable bbus type trap"))))
	       ((memq 'overflow tem) 
		(or (memq (get code 'alu)
			  '(X+1-overflow X-1-overflow X+Y-overflow X-Y-overflow))
		    (check-conflict code 'trap-enables 'alu)))
	       ((memq 'map-miss tem)
		(or (fieldp code 'mem 'start-cycle)
		    (check-conflict code 'trap-enables 'mem
				    "Start-cycle not specified in MEM field"))))))

;; dispatch and magic assumed made consistent at the source
;; Decide how to encode the byte func and check for AMWA conflicts
(multiple-value-bind (byte-func magic)
     (choose-byte-func-encoding code)
  (let ((amem-uses-amwa (and (get code 'write-amem)
			     (setq tem (get code 'amem-write-addr))
			     (not (equal tem '(bus-address))) ;only uses bit 10
			     (or (setq tem1 (get code 'amem-read-addr))
				 (setq tem1 (get code 'abus)))
			     (not (equal tem tem1))))
	(bmem-uses-amwa (and (fieldp code 'spec 'crocks) (fieldp code 'magic 10)))
	(byte-uses-amwa (and (= byte-func 3) (not (bit-test 3 magic))))
	(lbus-uses-amwa (get code 'lbus-dev-addr))
	(stack-pointer-uses-amwa-11 (get code 'stack-pointer))
	(crocks-uses-amwa-11 (fieldp code 'spec 'crocks-to-ybus)))
    (if (and amem-uses-amwa bmem-uses-amwa)
	(check-conflict code 'amem-write-addr 'bmem-write-addr
			"Conflict for AMWA field"))
    (if (and amem-uses-amwa byte-uses-amwa)
	(check-conflict code 'amem-write-addr 'byte-func
			"Conflict for AMWA field"))
    (if (and amem-uses-amwa lbus-uses-amwa)
	(check-conflict code 'amem-write-addr 'lbus-dev-addr
			"Conflict for AMWA field"))
    (if (and bmem-uses-amwa byte-uses-amwa)
	(check-conflict code 'bmem-write-addr 'byte-func
			"Conflict for AMWA field"))
    (if (and bmem-uses-amwa lbus-uses-amwa)
	(check-conflict code 'bmem-write-addr 'lbus-dev-addr
			"Conflict for AMWA field"))
    (if (and byte-uses-amwa lbus-uses-amwa)
	(check-conflict	code 'byte-func 'lbus-dev-addr
			"Conflict for AMWA field"))
    ;; Unfortunately. AMWA<11> conflicts happen all over the place unless
    ;; we allow both parties to specify the same bit value. This means
    ;; that the Amem variables you write into while decrementing the
    ;; stack pointer must go in a specific half of Amem.
    (and amem-uses-amwa crocks-uses-amwa-11
	 (atom (setq tem (get code 'amem-write-addr)))
	 (neg (if (bit-test 4000 tem) 'ybus-crocks-2 'ybus-crocks-1)
	      (get code 'ybus))
	 (check-conflict code 'ybus 'amem-write-addr
			 "Conflict for AMWA <11>"))
    (and amem-uses-amwa stack-pointer-uses-amwa-11
	 (atom (setq tem (get code 'amem-write-addr)))
	 (neq (if (bit-test 4000 tem) 'increment 'decrement)
	      stack-pointer-uses-amwa-11)
	 (check-conflict code 'stack-pointer 'amem-write-addr
			 "Conflict for AMWA <11>")))))

4,887,235
	71	72
;; decide how to encode the byte-func
(defun choose-byte-func-encoding (code &aux tem)
  ;Returns byte-func field, magic field, magic-mask field, cond field, and amwa
  (if (atom (setq tem (get code 'byte-func)))
      (values 0)		;Pass Ybus
      (let ((r (second tem))
	    (s (third tem))	;Really S+1
	    (rm (eq (first tem) 'dpb))
	    (mrg (eq (fourth tem) 'merge))
	    (magic (get code 'magic)))
	(cond ;; Byte function 0 taken care of already (byte-func = ybus)
	  ;; Byte function 2 (S from COND field)
	 ((and (equal r 0) (numberp s) (not mrg) (not (get code 'condition)))
	  (values 2 nil nil (1- s)))
	  ;: Byte function 1, #2=1 case
	 ((and (equal r 20) (equal as20) (not mrg)
	       (or (not magic) (bit-test 4 magic))
	       (or (not magic)
		   (and (or (fieldp code 'spec 'multiply)
			    (fieldp code 'spec 'multiply-and-type-check))
			(not (bit-test 10 magic)))	;#3 free
		   (eq rm (bit-test 10 magic))))
	  (values 1 (if rm 14 4) 14))
	 ;; Byte function 1, #2=0 case
	 ((and (not magic) (not rm) (not mrg) (equal s 40)
	       (member r '(0 1 37)))			;Could add more...
	  (values 1 (cdr (assoc r '((0 . 3) (1 . 2) (37 . 10)))) 17))
	 ;; More of that, kludge for first cycle of multiply. Is there a better way?
	 ((and (equal magic 13) (equal r 20) (equal s 20) rm (not mrg))
	  (values 1 13 17))
	 :; Otherwise use byte function 3. requires magic number field
	 (t (let ((mage (+ (if rm 10 0) (if mrg 4 O)))
		  (cond nil)
		  (amwa nil))
	      (cond ;; Byte function 3, case 0 (R and S from AMWA)
	       ((and (numberp r) (numberp s))
		(setq amwa (dpb (1- s) 0505 r)))
	       ;; Byte function 3, case 1 (R from RREG, S from COND)
	       ((and (eq r 'byte-r) (numberp s))
		(setq cond (1- s) mage (+ mage 1)))
	       ;; Byte function 3. case 2 (R from RREG, S from SREG)
	       ((and (eq r 'byte-r) (eq s 'byte-s))
		(setq mage (+ mage 2)))
	       ;; Byte function 3, case 3 (R,S from macroinstruction,
	       ;; high S bits from COND)
	       ((and (eq r 'macro) (eq s 'macro))
		(setq mage (+ mage 3)
		      cond 'macro))	;Must fill in from opcode
	       (t (check-loses "I can find no way to encode this byte function!")))
	      (and cond (get code 'condition)
		   (check-loses "Unable to encode this byte function without using COND (func 3)"))
	      (and magic (not (= mage magic))
		   (check-loses "Unable to encode this byte function without using MAGIC (func 3)"))
	      (values 3 mage 17 cond amwa)))))))

;Make sure that anything which uses the next-address field has an explicit one
;so that the assembler doesn't try to use it to link to the next instruction
;and knows that it must use NPC instead.
(defun check-next-address-field-consistency (code &aux tem)
  ;; Arithmetic traps require either a single trap routine or a dispatch table
  (and (setq tem (get code 'trap-enables))
       (or (memq 'type-condition tem)
	   (memq 'bbus-non-fixnum tem)
	   (memq 'overflow tem))
       (not (getl code '(trap-sequence arith-trap-dispatch-table)))
       (check-loses "Arithmetic trap enabled but no trap handler specified"))
  ;; Other NAF traps require a single trap routine
  (and (setq tem (get code 'trap-enables))
       (or (memq 'condition-true tem)
	   (memq 'condition-false tem)
	   (memq 'any-stack tem)
	   (memq 'other-stack tem))
       (not (get code 'trap-sequence))
       (check-conflict code 'trap-enables 'trap-sequence
		       "NAF trap enabled but no trap handler specified"))
;; Subroutine calling requires a subroutine (separate from return to .+1)
(and (memq (get code 'sequencer) '(pushj pushj-return-dispatch))
     (not (get code 'jump-sequence))
     (not (get code 'skip-true-sequence)) ;for call-select micro
     (check-conflict code 'sequencer 'jump-sequence
		     "Subroutine call but no subroutine specified"))
;; Look for multiple demands on NAF. Note that skipping can be done
;; to .+1 if necessary (NAF otherwise tied up)
;; next-sequence can always be done by duplicating the target at the
;; next successive control memory location.
(let ((jump (get code 'jump-sequence))
      (trap (get code 'trap-sequence))
      (disp (get code 'dispatch-table))
      (arith (get code 'arith-trap-dispatch-table)))
  (and jump trap
