4,887,235 213 214 (definst1 %net-wakeup no-operand (wakeup-net-service)) (defucode initialize-net (phys-mem-read (a-constant (get 'net-address-1 'virtual-address))) (assign %net-address-1 memory-data) (phys-mem-read (a-constant (get 'net-address-2 'virtual-address))) (parallel (return) (assign %net-address-2 memory-data))) ;; This is separate, since we dont have an extra cycle (defmicro wakeup-receive-end-service () '(parallel (assign service-task-requests (logior service-task-requests (b-constant (byte-mask %%service-receive-end)))) (wakeup-task %device-service-task) )) ;;; This is the receive end of the network (defmicro check-packet-end () '(if lbus-dev-cond (parallel (wakeup-receive-end-service) (jump net-dma-dead)) (drop-through))) (defucode net-receive-dma ;; Starts with %net-block-pointer pointing to the dest-high (parallel (receive-dma %net-block-pointer) (check-packet-end)) (parallel (extra-time-to-drive-lbus) (set-net-status %net-micro-status-receiving)) ;; Task switch (parallel (receive-dma %net-block-pointer nil) (check-packet-end)) ;; Rewind pointer to dest-high (parallel (extra-time-to-drive-lbus) (assign %net-block-pointer (- %net-block-pointer (b-constant 2)))) (parallel (start-memory read physical %net-block-pointer) (assign %net-block-pointer (1+ %net-block-pointer))) (parallel (start-memory read physical %net-block-pointer) (assign %net-block-pointer (1+ %net-block-pointer))) ;; net-dma-temp is the first address word (assign net-dma-temp memory-data) (if (not (equal-fixnum (ldb memory-data 20 0) %net-address-2)) (goto address-miss) (drop-through)) (if (not (equal-fixnum net-dma-temp %net-address-1)) (goto address-miss) (goto net-accept-packet))) ;;; Here address comparison failed, check for broadcast or promiscuity ;;; net-dma-temp is the first address word (defucode address-miss (if (ldb-bit-test net-dma-temp 7) (goto net-accept-packet) (drop-through)) ;; Here cneck for promiscuity and goto NET-ACCEPT-PACKET (jump net-ignore-packet)) (defucode net-ignore-packet (net-control nil t t) (set-net-status %net-micro-status-ignoring) ;; Task Switch (increment %net-ignored) (terminate-net-dma %net-micro-status-idle)) (defucode net-accept-packet (net-control nil t) (jump net-header-loop)) ;;; Transfer the header into the packet block (defucode net-header-loop (parallel (receive-dma %net-block-pointer) (assign %net-block-pointer (1+ %net-block-pointer)) (check-packet-end)) (parallel (extra-time-to-drive-lbus) (assign %net-word-count (1- %net-word-count)) (if (not (minus-fixnum obus)) (goto net-header-loop) ;; After the header, the rev blocks follow directly (goto net-block-fetch-loop)))) ;;; Fetch next block pointer end count, and dma one word into it. ;;; If there are no blc~cks left, return with data-overflow error (defucode net-block-fetch-loop (parallel (start-memory read physical %net-block-pointer) (assign %net-block-pointer (1+ %net-block-pointer))) (parallel (start-memory read physical %net-block-pointer) (assign %net-block-pointer (1+ %net-block-pointer))) (parallel (assign %net-memory-address memory-data) (if (minus-fixnum memory-data) 4,887,235 215 216 (goto net-data-overflow) (drop-through))) (parallel (assign %net-word-count (1- memory-data)) (jump net-block-loop))) ;;; Transfer in all the words in this block until packet end (defucode net-block-loop (parallel (receive-dma %net-memory-address) (assign %net-memory-address (1+ %net-memory-address)) (check-packet-end)) (parallel (extra-time-to-drive-lbus) (assign %net-word-count (1- %net-word-count)) (if (not (minus-fixnum obus)) (goto net-block-loop) (goto net-block-fetch-loop)))) ;; Store additional-flags, in packet we have not dismissed by this point (defucode net-data-overflow ;; Increment a meter (terminate-net-dma %net-micro-status-idle t)) (defucode net-dma-dead (net-control nil t) (jump net-dma-dead)) ;;; Transmit side ;: This is separate, since we dont have an extra cycle (defmicro wakeup-transmit-collision-service () '(parallel (assign service-task-requests (logior service-task-requests (b-constant (byte-mask %%service-transmit-collision)))) (wakeup-task %device-service-task) )) (defmicro check-transmit-collision () '(if lbus-dev-cond (wakeup-transmit-collision-service) (drop-through))) (defucode net-transmit-dma (start-memory read physical %net-control-address) (io-board-bug-delay) (assign %net-memory-address (+ %net-packet-being-transmitted (b-constant (field-word-offset 'ether-packet-dest-high)))) (if (field-bit memory-data %%nsr-not-transmitting) (goto switch-to-receive) (drop-through)) (parallel (transmit-dma %net-memory-address) (assign %net-memory-address (1+ %net-memory-address)) (check-transmit-collision)) (set-net-status %net-micro-status-transmitting) ;; Task switch (assign %net-block-pointer (+ %net-packet-being-transmitted (b-constant (field-word-offset 'ether-packet-xmt-0-address)))) (parallel (start-memory read physical %net-block-pointer) (assign %net-block-pointer (1+ %net-block-pointer))) ;; 4 words, but 1 already done, = 3 - 1 = 2 (assign %net-word-count (b-constant 2)) ;; net-dma-temp is the address of the first users block (parallel (assign net-dma-temp memory-data) (jump net-transmit-block-loop))) (defucode net-transmit-next-block ;; Read this blocks count and the next blocks address (parallel (start-memory read physical %net-block-pointer) (assign %net-block-pointer (1+ %net-block-pointer))) (parallel (start-memory read physical %net-block-pointer) (assign %net-block-pointer (1+ %net-block-pointer))) (assign %net-word-count (1- memory-data)) (parallel (assign net-dma-temp memory-data) (jump net-transmit-block-loop))) (defucode net-transmit-block-loop (parallel (transmit-dma %net-memory-address) (assign %net-memory-address (1+ %net-memory-address)) (check-transmit-collision)) (parallel (assign %net-word-count (1- %net-word-count)) (if (not (minus-fixnum obus)) (goto net-transmit-block-loop) (drop-through))) (parallel (assign %net-memory-address net-dma-temp) (if (minus-fixnum net-dma-temp) (goto net-transmitted-last-word) (goto net-transmit-next-block)))) (defucode net-transmitted-last-word ;; When started here, the last data word is in the shift register, we want ;; to cause it to go to state CRC after this word (parallel (transmit-dma %net-memory-address t t) (check-transmit-collision)) 4,887,235 217 218 (nop) ;; Task switch ;; Here the CRC is in the output shift register so check for collision (set-net-status %net-micro-status-transmit-done) (parallel (transmit-dma %net-memory-address t) (check-transmit-collision)) (parallel (wakeup-net-service) (jump net-dma-dead))) ;; here we want to switch to receive mode if possible (defucode switch-to-receive ;; Change to receive mode (parallel (start-memory write physical %net-control-address) (assign memory-data (b-constant (get '%nsr-receive-start 'sysconstant)))) (parallel (assign %net-block-pointer (+ (b-constant (field-word-offset 'ether-packet-dest-high)) %net-packet-being-received)) (if (minus-fixnum %net-packet-being-received) (jump net-ignore-packet) (drop-through))) ;XXXbrad next 3 lines really sketchy (assign %net-word-count (1- (b-constant 2))) ;; and wait for first receive data (net-control nil t) (parallel (set-net-status %net-micro-status-receive-wait) (jump net-receive-dma))) ;;; %net-backoff-count has the count to back off (units are 12.8 usec) ;;; Check to see if packet is coming in (defucode backoff-timer (start-memory read physical %net-control-address) (io-board-bug-delay) (nop) (if (field-bit memory-data %%nsr-data-valid) (goto switch-to-receive) (drop-through)) (net-control nil t) (parallel (assign %net-backoff-count (1- %net-backoff-count)) (if (minus-fixnum obus) (drop-through) (goto backoff-timer))) ;; Here backoff has expired (terminate-net-dma %net-micro-status-idle)) ;;: This is logically part of the device service stuff (defucode net-service-loop (if (bit %%service-receive-end) (parallel (assign %%servics-receive-end (b-constant 0)) (jump net-receive-completion)) (drop-through)) (if (bit %%service-transmit-collision) (parallel (assign %%service-transmit-collision (b-constant 0)) (jump net-transmit-collision)) (drop-through)) (if (bit %%service-net) (dispatch-after-this net-micro-status (assign %%service-net (b-constant 0)) ;; These are all functionally equivalent, keep hands off dma task ((%net-micro-status-transmit-wait %net-micro-status-receiving %net-micro-status-transmitting %net-micro-status-ignoring %net-micro-status-backing-off) (jump device-service-end)) ((%net-micro-status-idle) (goto service-net-idle)) ((%net-micro-status-reset) (assign %net-backoff-count (b-constant -1)) (assign %net-packet-being-received (b-constant -1)) (parallel (assign %net-packet-being-transmitted (b-constant -1)) (jump reset-net-dma))) ((%net-micro-status-receive-wait) ;; If we have a packet to transmit, try to (if (minus-fixnum %net-transmit-list) (jump device-service-end) ;; Otherwise, reset and go to idle (goto reset-net-dma))) ((%net-micro-status-transmit-done) (goto service-net-transmit-done)) ) (drop-through)) (jump device-service-end)) (defucode reset-net-dma (parallel (start-memory write physical %net-control-address) (assign memory-data (b-constant (get '%nsr-error-clear 'sysconstant)))) (for-effect (service-net-control t)) (parallel (set-net-status %net-micro-status-idle) (jump service-net-idle))) (defucode service-net-idle (parallel (start-memory write physical %net-control-address) (assign memory-data (b-constant (get '%nsr-error-clear 'sysconstant)))) ;; Always prepare a pacKet to be received into (if (minus-fixnum %net-packet-being-received) 4,887,235 219 220 (parallel (assign %net-packet-being-received %net-free-list) (if (not (minus-fixnum %net-free-list)) (sequential (phys-mem-read %net-free-list) (assign %net-free-list memory-data)) (drop-through))) (drop-through)) ;; If we can transmit, try to (if (minus-fixnum %net-packet-being-transmitted) (parallel (assign %net-packet-being-tranmitted %net-transmit-list) (if (minus-fixnum %net-transmit-list) (drop-through) (sequential (parallel (phys-mem-read %net-transmit-list) (assign %net-next-backoff (b-constant (1- (lsh 1 2))))) (parallel (assign %net-transmit-list memory-data) (jump start-net-transmitter))))) (goto start-net-transmitter)) ;; Otherwise start receiver if we can (if (minus-fixnum %net-packet-being-received) (jump device-service-end) (drop-through)) (set-net-status %net-micro-status-receive-wait) (assign %net-block-pointer (+ %net-packet-being-received (b-constant (field-word-offset 'ether-packet-dest-high)))) (assign %net-word-count (1- (b-constant 2))) (parallel (start-memory write physical %net-control-address) (assign memory-data (b-constant (get '%nsr-receive-start 'sysconstant)))) (parallel (start-net-dma net-receive-dma) (jump device-service-end))) (defucode start-net-transmitter (if (minus-fixnum %net-backoff-count) (drop-through) (goto start-net-backoff)) (set-net-status %net-micro-status-transmit-wait) (parallel (start-memory write physical %net-control-address) (assign memory-data (b-constant (get '%nsr-transmit-start 'sysconstant)))) (parallel (start-net-dma net-transmit-dma) (jump device-service-end))) ;;; Sequencer special functions ;Halt the machine after executing this eicroinstructicn (defmicro halt (reason) reason ;ignored '(microinstruction spec halt)) ;Pop a word off of the control stack and put it into NPC (defmicro popj-into-npc () '(microinstruction sequencer pop-npc spec npc-magic magic 3 magic-mask 3)) ;Read the top of the control stack and pop it (also puts it into NPC) ;Read the input to the NPC (taken from the control stack) onto the Lbus ;and do a microdevice read from a nonexistent device to get the Lbus into ;the datapath. Use the FEP board subdevice 1 as the nonexistent device ;(this drives bus dev cond from the page tags, but doesn't drive lbus data). (defmicro pop-control-stack () '(parallel (read-lbus-dev 36 1) (microinstruction spec npc-magic magic 1 magic-mask 3 sequencer pop-npc speed very-slow))) ;Write NPC from Obus; use task-dispatch in next cycle to branch there. ;The spec does all the work, but we also need to do a bogus microdevice write ;in order to make bus scheduling happen properly. ;Use subdevice 7 in the FEP board (only subdevices 0-2 exist). (defmicro long-dispatch (data) (paralyze (get-to-obus32 data) (selectq *machine-version* ((sim proto) '(microinstruction spec npc-magic magic 2 magic-mask 3 write-lbus obus lbus-dev-addr #.(+ 36_5 7))) (otherwise '(microinstruction spec npc-magic magic 2 magic-mask 3 mem microdevice write-lbus obus lbus-dev-addr #.(+ 36_5 7)))))) ;Uses b-temp (defmicro read-csp () (selectq *machine-version* ((sim proto) (retch "Cannot read CSP on old machine")) (otherwise '(sequential (parallel (assign b-temp (read-lbus-dev 36 1)) ;Read dummy device (microinstruction spec npc-magic magic 1 magic-mask 3 speed very-slow)) (ldb b-temp 4 16.))))) ;Uses b-temp 4,887,235 221 222 (defmicro read-cur-task-and-csp () (selectq *machine-version* ((sim proto) (retch "Cannot read CUR-TASK and CSP on old machine")) (otherwise '(sequential (parallel (assign b-temp (read-lbus-dev 36 1)) ;Read dummy device (microinstruction spec npc-magic magic 1 magic-mask 3 speed very-slow)) (ldb b-temp 8 16.))))) ;Write into an Lbus device ;NIL may be specified for the data, which means we don't care what's written (defmicro write-lbus-dev (cord subdevice data) (setq data (microexpand data)) (paralyze (and data (get-to-obus data)) (microexpand `(select-lbus-dev ,card ,subdevice)) (selectq *machine-version* ((sim proto) '(microinstruction write-lbus obus)) ((tmc tmc5) `(microinstruction write-lbus ,(cond ((null data) 'junk) ((and (eq (car data) 'microdata) (eq (cadr data) 'abus) (fieldp (caddr data) 'abus 'memory-data)) 'memory-data) (t 'obus)) mem microdevice)) (otherwise '(microinstruction write-lbus obus mem microdevice))))) ;Read from an Lbus device (defmicro read-lbus-dev (card subdevice) (make-microdata 'abus (paralyze (microexpand `(select-lbus-dev ,card ,subdevice)) (selectq *machine-version* ((sim proto) '(microinstruction abus lbus)) (otherwise '(microinstruction abus lbus mem microdevice speed slow-second-half)))))) ;slow-second-half is because the IO MD latch on the TMC ;does not open until second half, and then the data still ;have to propagate to the OP board and through 8304. ;Need this to avoid GC map parity error. (defmicro select-lbus-dev (card subdevice) (or (and (fixp card) (<= 0 card 37)) (and (symbolp card) (get card 'symbolic-lbus-slot)) (retch "~S illegal slot number" card)) (or (and (fixp subdevice) (<= 0 subdevice 37)) (retch "~S illegal subdevice number" subdevice)) `(microinstruction lbus-dev-addr ,(if (symbolp card) `(,card ,subdevice) (dpb card 0505 subdevice)))) (defmacro define-lbus-card (name) `(eval-when (compile load eval) (defprop ,name t symbolic-lbus-slot))) ;Write the control register on the data path (defmicro write-dp-control (source) (paralyze (get-to-obus32 source) '(microinstruction spec load-control))) (defatomicro lbus-dev-cond (microcondition not-lbus-dev-cond false nil)) ;;; Tasking (defmicro read-cur-task () (selectq *machine-version* ((sim proto) (retch "Cannot read CUR-TASK on old machine")) (otherwise '(sequential (parallel (assign b-temp (read-lbus-dev 36 1)) ;Read dumey device (microinstruction spec npc-magic magic 1 magic-mask 3 speed very-slow)) (ldb b-temp 4 20.))))) (defmicro wakeup-task (n) (setq n (decode-task-number n)) `(microinstruction spec awaken-task magic-mask 3 magic ,(or (find-position-in-list n '(1 2 5 6)) (retch "~S illegal task number here" n)))) (defmicro write-task-state (n value) (setq n (decode-task-number n)) (paralyze (get-to-obus32 value) `(microinstruction spec write-task mem microdevice write-lbus obus lbus-dev-addr #.(+ 36_5 7) force-obus<33-32> ,(ldb 0002 n) force-obus<35-34> ,(ldb 0202 n)))) (defun decode-task-number (n) (and (symbolp n) (get n 'sysconstant) (setq n (get n 'sysconstant))) (or (and (fixp n) (<= 0 n 17)) (retch "~S illegal task number here" n)) 4,887,235 223 224 n) (defmicro dismiss () '(microinstruction sequencer dismiss)) ;Must be used twice in a row to work (defmicro disable-tasking () '(microinstruction spec disable-tasking)) ;cdr-code-insertion hardware (declare (special *cdr-codes*)) ;in SIM (defmicro set-cdr (val cdr) (let ((cdr-code (if (numberp cdr) cdr (find-position-in-list cdr *cdr-codes*)))) (or cdr-code (retch "~S undefined cdr code" cdr)) (make-microdata 'obus `(parallel (get-to-obus ,val) (microinstruction force-obus<35-34> ,cdr-code))))) ;data-type-insertion hardware (declare (special *data-types*)) ;in SIM (defmicro set-type (val dtp) (let ((dtp-code (if (numberp dtp) dtp (find-position-in-list dtp *data-types*)))) (or dtp-code (retch "~S undefined data type" dtp)) (make-microdata 'obus `(parallel ,(get-to-obus32 val) (microinstruction force-obus<33-32> ,(lsh dtp-code -4)) ,(if (not (memq dtp '(dtp-fix dtp-float))) (let ((num (logand 17 dtp-code))) `(microinstruction force-obus<31-28> ,num magic ,num))))))) ;Set-cdr from a 'variable' rather than a 'constant' ;--- This and the next could be changed to allow background on BBus also (defmicro merge-cdr (typed-pointer cdr-background) (make-microdata 'obus (paralyze (get-to-obus typed-pointer) (get-to-abus cdr-background) '(microinstruction force-obus<35-34> abus)))) ;Take low 32 bits from one source and high 4 from another (defmicro merge-high-tag (typed-pointer tag-background) (make-microdata 'obus (paralyze (get-to-obus32 typed-pointer) (get-to-abus tag-background) '(microinstruction force-obus<35-34> abus force-obus<33-32> abus)))) ;Storing into memory ;The type map for normal storing, which simply identifies whether or ;not a pointer is being stored. This is what enables the gc tag hardware. (declare (special *storing-type-map*)) ;in UUX ;Store the contents of the currently-addressed memory location, with ;gc tag enabled, and with the cdr code coming from either a constant ;or the cdr field of another source or the same source (if unspecified). ;This is different from assigning to memory-data, because the ;latter is a lower-level operation which does not turn on the gc tagging. ;Note that the data to be stored is normally assumed to be a typed pointer and ;hence must come from the Abus so that it gets to the data type ;logic. ;The following options may be specified: ; NOT-POINTER - Value is known not to be a pointer, may come from Sbus ; BLOCK - Increment VMA after storing ; car-code-name - set cdr-code to that ; (CDR source) - get cdr code from source (number, cdr-code name, or datum) ; OBUS-AS-GOOD-AS-ABUS - this kiudge says that gc-map looking at abus data ; instead of obus data will not hurt anything ; NO-AMEM - this kludge saus that we won't be writing a mapped-into-amem address (defmicro store-contents (typed-pointer &rest options &aux (cdr nil) (cdr-inst nil) (not-pointer nil) (block nil) (obus-as-good-as-abus nil) (amem t)) ;; Parse Options (dolist (opt options) (cond ((eq opt 'not-pointer) (setq not-pointer t)) ((eq opt 'block) (setq block t)) ((eq opt 'obus-as-good-as-abus) (setq obus-as-good-as-abus t)) ((eq opt 'no-amem) (setq amem nil)) ((memq opt *cdr-codes*) (setq cdr (find-position-in-list opt *cdr-codes*))) ((and (listp opt) (eq (car opt) 'cdr)) ;; Decompose into cdr, the obus cdr-field forcing, and cdr-inst, other code. (setq cdr (cadr opt)) (cond ((numberp cdr)) ((memq cdr *cdr-codes*) (setq cdr (find-position-in-list cdr *cdr-codes*))) ;((eq cdr 'memory-data)) ;this misfeature has been flushed from the hardware ((and (not (atom (setq cdr-inst (microexpand cdr)))) (eq (cor cdr-inst) 'microdata) (memq (cadr cdr-inst) '(abus bbus))) ;abus-only on the proto... (setq cdr (cadr cdr-inst) cdr-inst (caddr cdr-inst))) 4,887,235 225 226 (t (retch "~S not a data source that can feed cdr field" cdr) (setq cdr nil cdr-inst nil)))) (t (retch "~S not a valid option" opt)))) (paralyze (cond (not-pointer (get-to-obus typed-pointer)) (obus-as-good-as-abus (paralyze (get-to-obus typed-pointer) `(microinstruction type-map ,*storing-type-map*))) (t (paralyze (get-to-abus typed-pointer) `(microinstruction type-map ,*storing-type-map* xbus abus alu xbus)))) (and cdr `(microinstruction force-obus<35-34> ,cdr)) cdr-inst (and amem '(microinstruction amem-write-addr (bus-address))) (selectq *machine-version* ((sim proto) (if block (retch "store-contents block option not implemented")) '(microinstruction write-lbus obus lbus-dev-addr write-memory trap-enables (map-miss) mem start-cycle)) (otherwise (microexpand (if (not block) '(start-memory write) '(start-memory write block))))))) ;ALU operations ;You get 16 functions of each kind ;Things depend on XBUS and ALUB not being weird (defconst normal-alu-functions '(xbus alub X+1 X-1 X+Y X-Y X+Y+1 X-Y-1 and ior xor)) ;5 spares (defconst weird-alu-functions '(X+1-overflow X-1-overflow X+Y-overflow X-Y-overflow X-Y-signed X-Y-1-signed nand andcy)) ;8 spares (defun alu-microinstruction (func) (cond ((memq func normal-alu-functions) `(microinstruction alu ,func)) ((memq func weird-alu-functions) `(microinstruction alu ,func spec arithmetic-trap-enb magic 4)) (t (retch "~S undefined ALU function" func)))) ;Define 1-operand ALU function ;Hair so that ybus operands work, too. (defmacro defaluop1 (name field ycode &optional other-code) `(defmicro ,name (x-opnd) (setq x-opnd (microexpand x-opnd)) (paralyze (if (memq (cadr x-opnd) '(ybus alub)) (microexpand (subst x-opnd 'y ',ycode)) (make-microdata 'obus (alu-paralyze (get-to-xbus x-opnd) (alu-microinstruction ',field)))) ',other-code))) ;Define 2-operand ALU function (optional third operand is constant 1) ;If one-operand? is specified it is code for the one-operand case ;otherwise require 2 or 3 operands. (defmacro defaluop2 (name field &optional commutative? third-operand? one-operand? other-code) `(defmicro ,name (x-opnd ,@(if one-operand? '(&optional)) y-opnd ,@(if third-operand? (if (not one-operand?) '(&optional one) '(one)))) ,(if third-operand? `(or (null one) (equal one 1) (retch "Third operand to ~S must be 1, not ~S" ',name one))) ,(let ((two-op-code `(make-microdata 'obus (alu-paralyze ,@(if commutative? '((get-to-xbus-and-alub x-opnd y-opnd)) '((get-to-xbus x-opnd) (get-to-alub y-opnd))) (alu-microinstruction ;XXXbrad - '` ? ,(if (not third-operand?) `',field `(if one ',third-operand? ',field))))))) (if (null other-code) (if (not one-operand?) two-op-code `(if u-opnd ,two-op-code (subst x-opnd 'arg ',one-operand?))) ``(parallel ,,(if (not one-operand?) two-op-code `(if y-opnd ,two-op-code (subst x-opnd 'arg ',one-operand?))) 4,887,235 227 228 ,',other-code))))) (defaluop1 1+ X+1 (xbus-constant-hack X+Y 1 y)) (defaluop1 I- X-1 (xbus-constant-hack X+Y -1 y)) (defaluop2 + X+Y t X+Y+1) (defaluop2 - X-Y nil X-Y-1 (xbus-constant-hack X-Y 0 arg)) (defaluop2 commutative-diff X-Y t X-Y-1) (defaluop2 logand and t) (defaluop2 lognand nand t) (defaluop2 logior ior t) (defaluop2 logxor xor t) (defaluop2 andc2 andcy nil) (defaluop1 inc-checking-overflow X+1-overflow (xbus-constant-hack X+Y-overflow 1 y) (microinstruction trap-enables (overflow))) (defaluop1 dec-checking-overflow X-1-overflow (xbus-constant-hack X+Y-overflow -1 y) (microinstruction trap-enables (overflow))) (defaluop2 add-checking-overflow X+Y-overflow t nil nil (microinstruction trap-enables (overflow))) (defaluop2 sub-checking-overflow X-Y-overflow nil nil nil (microinstruction trap-enables (overflow))) ;Used internally: ALU can also feed through xbus or alub ;This piece of hair generates an ALU operation with a constant on ;the xbus and an argument on the alub. The hair is to decide which ;memory to put the constant in. (defmicro xbus-constant-hack (alu-op constant y-opnd) (setq y-opnd (get-to-alub y-opnd)) (make-microdata 'obus (alu-paralyze y-opnd (get-to-xbus (if (uses-bbus y-opnd) `(a-constant ,constant) '(b-constant constant))) `(microinstruction alu ,alu-opb)))) (defun uses-bbus (instruction) (cond ((eq (car instruction) 'microsequence) (uses-bbus (car (last instruction)))) ((eq (car instruction) 'microinstruction) (loop for (field value) on (cdr instruction) thereis (eq field 'bbus))) ((eq (car instruction) 'microdata) (uses-bbus (caddr instruction))) (t (retch "uses-bbus: What da fuck is dis? -- ~S" instruction)))) (defun alu-paralize1 (inst) (selectq (car mint) ((microinstruction) (and (memq (get inst 'alu) '(X+Y X-Y X+Y+1 X-Y-1 X+Y-overflow X-Y-overflow X-Y-signed X-Y-1-signed)) (selectq (get inst 'ybus) (abus (selectq (get inst 'abus) ((amem) (let ((a (get inst 'amem-read-addr))) (or (atom a) (neq (car a) 'constant)))) ((memory-data memory-data-force lbus map) t) (otherwise nil))) ;bases, vma, pc are fast (bbus (selectq (get inst 'bbus) ((bmem) (let ((a (get inst 'bmem-read-addr))) (or (atom a) (neq (car a) 'constant)))) (otherwise nil)))) ;macro-immediate's are fast (setq inst (paralyze inst '(microinstruction speed slow-second-half)))) inst) ((microsequence) (cons 'microsequence (mapcar #'alu-paralyze1 (cdr mint)))) (otherwise (retch "~S not a microinstruction" inst)))) ;;; Support for byte fields (defmacro byte-mask (ppss) (dpb -1 (cond ((numberp ppss)) ((not (get ppss 'byte-field)) (retch "~S not a defined byte field" ppss)) ((car (get ppss 'byte-field)))) 0)) (defun byte-pp (ppss) (lsh ppss -6)) (defun byte-ss (ppss) (logand 77 ppss)) 4,887,235 229 230 (defun byte-pp-reflected (ppss) (logand 37 (- 40 (byte-pp ppss)))) (defun byte-numbers-to-ppss (n-bits bits-over) (+ (lsh bits-over 6) n-bits)) (defmacro defatomic-byte-field (name byte-specifier register) (let ((*backtrace* (cons `((defatomic-byte-field ,name)) *backtrace*)) (ppss (if (listp byte-specifier) (byte-numbers-to-ppss (first byte-specifier) (second byte-specifier)) (car (get byte-specifier 'byte-field))))) (or ppss (ferror nil "~S not defined as a system byte" byte-specifier)) `(eval-when (compile load eval) (defprop ,name (,ppss ,register) byte-field) (defatomicro ,name ,(make-microdata 'alub (paralyze (get-to-ybus register) `(microinstruction byte-func (ldb ,(byte-pp-reflected ppss) ,(byte-ss ppss))))))))) (defmacro def-byte-field (name byte-specifier place) (let ((*backtrace* (cons `((def-byte-field ,name)) *backtrace*)) (ppss (if (listp byte-specifier) (byte-numbers-to-ppss (first byte-specifier) (second byte-specifier)) (car (get byte-specifier 'byte-field))))) (or ppss (ferror nil "~S not defined as a system byte" byte-specifier)) `(eval-when (compile load eval) (defprop ,name (,ppss) byte-field) (defmicro ,name (,place) (make-microdata 'alub (paralyze (get-to-ybus ,place) `(microinstruction byte-func (ldb ,',(byte-pp-reflected ppss) ,',(byte-ss ppss))))))))) ;Use this to define the a-list of symbolic dispatch cues associated with a field (defmacro associate-dispatch-cues (field-name enumerated-type-name) `(eval-when (compile load eval) (defprop ,field-name ,enumerated-type-name enumerated-type-name))) ;Use this to define them as atomicros that are B-constants (defmacro define-enumerated-value-constants (enumerated-type-name) (let ((codes (get enumerated-type-name 'enumerated-type-codes))) (if (null codes) (ferror nil "~S not declared as an enumerated type" enumerated-type-name)) `(progn 'compile . ,(loop for (code . value) in codes collect `(defatomicro ,code (b-constant ,value)))))) ;Similar, for word offsets in a defstorage (defmacro define-storage-word-offset-constants (defstorage-type-name) (let ((fields (get defstorage-type-name 'defstorage-fields))) (if (null fields) (ferror nil "~S not declared as a defstorage type" defstorage-type-name)) `(progn 'compile . ,(loop for field in fields collect `(defatomicro ,field (b-constant ,(field-word-offset field))))))) ;Similar for a single constant defined with defsysconstant (defmacro define-sysconstant (name) (or (get name 'sysconstant) (ferror nil "~S not declared with defsysconstant")) `(defatomicro ,name (b-constant ,(get name 'sysconstant)))) ;;; Micros for more direct access to the shift/mask/merge logic (defmicro rotate (opnd left-amt) (make-microdata 'alub (paralyze (get-to-ybus opnd) `(microinstruction byte-func (ldb ,left-amt 32.))))) (defmicro ldb (cond n-bits bits-over &optional background) (if (equal background 0) (setq background nil)) (validate-byte-specifier n-bits bits-over) (make-microdata 'alub (paralyze (get-to-ybus opnd) `(microinstruction byte-func (ldb ,(selectq bits-over ((byte-r macro) bits-over) (otherwise (logand 37 (- 40 bits-over)))) ,n-bits ,@(if background '(merge)))) (if background (get-to-xbus background))))) (defmicro dpb (opnd n-bits bits-over background) (if (equal background 0) (setq background nil)) (validate-byte-specifier n-bits bits-over) (make-macrodata 'alub 4,887,235 231 232 (paralyze (get-to-ybus opnd) `(microinstruction byte-func (dpb ,bits-over ,n-bits ,@(if background '(merge)))) (if background (get-to-xbus background))))) ;Alternate version of LDB used by certain hacks (sunprimitives) ;Allows uou to take advantage of the fact that bytes split across the ;end of the word work (i.e. it really is a rotate followed by a mask). (defmicro strange-ldb (opnd n-bits bits-over &optional background) (if (equal background 0) (setq background nil)) (make-microdata 'alub (paralyze (get-to-ybus opnd) `(microinstruction byte-func (ldb ,(logand 37 (- 40 bits-over)) ,n-bits ,@(if background (merge)))) (if background (get-to-xbus background))))) ;Ensure that the specified byte lies within the low 32 bits and is otherwise legal. (defun validate-byte-specifier (n-bits bits-over) (or (symbolp n-bits) (<= 1 n-bits 32.) (retch "The number of bits, ~S, is not between 1 and 32." n-bits)) (or (symbolp bits-over) (<= 0 bits-over 31.) (retch "The bit position, ~S, is not between 0 and 31." bits-over)) (or (symbolp n-bits) (symbolp bits-over) (<= (+ n-bits bits-over) 32.) (retch "The byte specified at ~S ~S overlaps the 32-bit word boundary" n-bits bits-over))) ;Invoke special hair in the SHFMSK0 PAL (defmicro complemented-sign-bit (opnd) `(parallel (ldb ,opnd 1 31.) (microinstruction spec alub-sign-hack))) ;Get a byte by name rather than by bits,bits-over. (defmicro ldb-field (operand field-name &optional (background 0)) (multiple-value-bind (n-bits bits-over) (decode-byte-field-specifier field-name) `(ldb ,operand ,n-bits ,bits-over ,background))) (defmicro dpb-field (operand field-name background) (multiple-value-bind (n-bits bits-over) (decode-byte-field-specifier field-name) `(dpb ,operand ,n-bits ,bits-over ,background))) (defmacro ldb-field (operand field-name) (let ((ppss (car (get field-name 'byte-field)))) (or ppss (ferror "~S is not a defined byte field" field-name)) `(ldb ,ppss ,operand))) (defmacro dpb-field (operand field-name background) (let ((ppss (car (get field-name 'byte-field)))) (or ppss (ferror "~S is not a defined byte field" field-name)) `(dpb ,operand ,ppss ,background))) (defmacro field-mask (field-name) (let ((ppss (car (get field-name 'byte-field)))) (or ppss (ferror "~S is not a defined byte field" field-name)) (dpb -1 ppss 0))) (defmicro field-bit (operand field-name) (multiple-value-bind (n-bits bits-over) (decode-byte-field-specifier field-name) (or (= n-bits 1) (retch "~S is not a single-bit field" field-name)) (make-microcondition 'alub-0 'true (paralyze `(microinstruction byte-func (ldb ,(logand 37 (- 40 bits-over)) ,n-bits)) (get-to-ybus operand))))) (defun decode-byte-field-specifier (field-name) (let ((ppss (car (get field-name 'byte-field)))) (or ppss (retch "~S is not a defined byte field" field-name)) (values (logand 77 ppss) ;XXXbrad -6? (lsh ppss -6)))) ;;;Since the proto machine is dead, don't bother checking. (defatomicro byte-s (ldb ybus-crocks-2 5 24.)) (defatomicro byte-r (ldb ybus-crocks-1 5 24.)) ;;; Multiplication ;Reading out the 32-bit signed product of X and Y registers (defatomicro mpy-product (microdata xbus (microinstruction xbus product spec multiply ;XXXbrad magic 4? magic 4 speed very-slow)))