4,887,235 413 414 (parallel (nop) (trap-no-save)) ;Cannot call in first cycle alter trap (call fsignum) (if (plus-fixnum top-of-stack) (goto true1) (goto false1))) (defucode fminusp (parallel (nop) (trap-no-save)) ;Cannot call in first cycle after trap (call fsignum) (if (minus-fixnum top-of-stack) (goto true1) (goto false1))) (defucode fzerop (parallel (nop) (trap-no-save)) ;Cannot call in first cycle after trap (call fsignum) (if (zero-fixnum top-of-stack) (goto true1) (goto false1))) (defucode minus-flonum (parallel (trap-no-save) (if (equal-fixnum (ldb-field top-of-stack-a single-expt) (b-constant single-expt-max)) (goto minus-inf-or-nan) (drop-through))) (parallel (newtop (set-type (logxor (b-constant (field-mask single-sign)) top-of-stack-a) dtp-float)) (next-instruction))) F:>lmach>ucode>flavor.lisp.25 ;;; -*- Mode:Lisp; Package:Micro; Base:8; Lowercase:yes -*- ;;; (c) Copyright 1982, Symbolics, Inc. ; Microcode for flavor. ;Get defmicro and all his hosts #M (declare (cond ((not (status feature lmucode)) (load 'udcls)))) (reserve-scratchpad-memory 2452 2460 345 351) ;Data on the most recently used mapping table (an ART-16B array) (defbreg b-cached-mapping-table) (defareg a-cached-mapping-table-address) (defareg a-cached-mapping-table-size) (defatomicro self (amem (frame-pointer 0))) (defatomicro self-mapping-table (amem (frame-pointer 1))) (definst push-instance-variable-ordered unsigned-immediate-operand (parallel (check-arg-type instance self dtp-instance) (memread (+ self macro-unsigned-immediate))) (parallel (transport data) (pushval memory-data) (next-instruction))) (definst movem-instance-variable-ordered (unsigned-immediate-operand needs-stack) (parallel (check-arg-type instance self dtp-instance) (memread (+ self macro-unsigned-immediate))) (parallel (transport write) ;Follow any forwarding pointer (assign a-temp ;Merge new data with old cdr cods (merge-cdr top-of-stack memory-data))) (parallel (store-contents a-temp) ;Now write back the new car (next-instruction))) (definst pop-instance-variable-ordered (unsigned-immediate-operand needs-stack) (parallel (check-arg-type instance self dtp-instance) (assign vma (+ self macro-unsigned-immediate))) (parallel (start-memory read) (assign b-temp top-of-stack)) (for-effect (popval)) (parallel (transport write) ;Follow any forwarding pointer (assign a-temp ;Merge new data with old cdr code (merge-cdr b-temp memory-data))) (parallel (store-contents a-temp) ;Now write back the new car (next-instruction))) (definst1 push-address-instance-variable-ordered unsigned-immediate-operand (check-arg-type instance self dtp-instance) (pushval (set-type (+ self macro-unsigned-immediate) dtp-locative))) ;8 cycles if the mapping table is already encached ;Additional 11 cycles to encache it if necessary ;Would be 7 cycles with no range check and assumed simple array format, thus no encaching 4,887,235 415 416 (definst push-instance-variable unsigned-immediate-operand (parallel (check-arg-type self-mapping-table self-mapping-table dtp-array) (call-select (equal-typed-pointer self-mapping-table b-cached-mapping-table) fast-mapping-table-lookup slow-mapping-table-lookup)) (start-memory read) (nop) (parallel (transport data) (pushval memory-data) (next-instruction))) (definst movem-instance-variable (unsigned-immediate-operand needs-stack) (parallel (check-arg-type self-mapping-table self-mapping-table dtp-array) (call-select (equal-typed-pointer self-mapping-table b-cached-mapping-table) fast-mapping-table-lookup slow-mapping-table-lookup)) (start-memory read) (nop) (parallel (transport write) ;Follow any forwarding pointer (assign a-temp ;Marge new data with old cdr code (merge-cdr top-of-stack memory-data))) (parallel (store-contents a-temp) ;Now write back the new car (next-instruction))) (definst pop-instance-variable (unsigned-immediate-operand needs-stack) (parallel (check-org-type self-mapping-table self-mapping-table dtp-array) (call-select (equal-typed-pointer self-mapping-table b-cached-mapping-table) fast-mapping-table-lookup slow-mapping-table-lookup)) (parallel (start-memory read) (assign b-temp top-of-stack)) (for-effect (popval)) (parallel (transport write) ;Follow any forwarding pointer (assign a-temp ;Merge new data with old cdr code (merge-cdr b-temp memory-data))) (parallel (store-contents a-temp) ;Now write back the new car (next-instruction))) (definst push-address-instance-variable unsigned-immediate-operand (parallel (check-arg-type self-mapping-table self-mapping-table dtp-array) (call-select (equal-typed-pointer self-mapping-table b-cached-mapping-table) fast-mapping-table-lookup slow-mapping-table-lookup)) (parallel (pushval (set-type vma dtp-locative)) (next-instruction))) (defucode slow-mapping-table-lookup (parallel (check-arg-type self-mapping-table self-mapping-table dtp-array) (assign vma self-mapping-table) (assign b-vma sell-mapping-table) (call array-setup-1d-zero)) ;(trap-if (not-zero-fixnum top-of-stack) (signal-error "Index offset not handled")) ;(trap-if (not-equal-fixnum (array-register-dispatch-field (amem (stack-pointer 1))) ; %array-register-dispatch-16-bit) ; (signal-error "Mapping table must be art-16b")) (assign a-cached-mapping-table-address (amem (stack-pointer 2))) (assign a-cached-mapping-table-size (amem (stack-pointer 3))) (assign b-cached-mapping-table self-mapping-table) (parallel (assign top-of-stack top-of-stack-a) (jump fast-mapping-table-lookup))) (defucode fast-mapping-table-lookup ;; Divide the instance-variable number by 2 and access the art-lEb array (assign vma (+ a-cached-mapping-table-address (rotate macro-unsigned-immediate 37))) ;;Range-check the instance-variable number (parallel (start-memory read) (error-if (greater-or-equal-fixnum-unsigned macro-unsigned-immediate a-cached-mapping-table-size) mapping-table-out-of-bounds)) ;; Extract the appropriate halfword, put instance-variable address into VIIA (parallel (check-arg-type instance self dtp-instance) (assign b-temp self) (if (ldb-bit-test macro-unsigned-immediate 0) ;oddp (machine-version-case ((tmc tmc5) (sequential (assign a-temp memory-data) (assign vma (+ b-temp (ldb a-temp 20 20))))) (otherwise (assign vma (+ b-temp (ldb memory-data 20 20))))) (machine-version-case ((tmc tmc5) (sequential (assign a-temp memory-data) (assign vma (+ b-temp (ldb a-temp 20 0))))) (otherwise (assign vma (+ b-temp (ldb memory-data 20 0))))))) ;This could check for instance-variable-number out of range, but that would ;require accessing ancther field in the instance descriptor. The flavor system ;is not supposed to let that happen. But instance variable zero is really ;accessed when an instance variable is deleted or only existed at compile time. (parallel (error-if (equal-pointer vma b-temp) instance-variable-zero-referenced) (return))) 4,887,235 417 418 (define-storage-word-offset-constants instance-descriptor) ;; VMA has the address of an instance. Return its size in a-temp. (defucode instance-size (start-memory read) ;Fetch instance-descriptor (nop) (parallel (transport header) (machine-version-case ((tmc tmc5) (sequential (assign a-temp memory-data) (assign vma (+ a-temp %instance-descriptor-size)))) (otherwise (assign vma (+ memory-data %instance-descriptor-size)))) (call memread)) (parallel (declare-memory-timing data-cycle) (check-arg-type instance-size memory-data dtp-fix) (assign a-temp memory-data) (return))) (definst %instance-ref unsigned-immediate-operand (parallel (check-arg-type instance top-of-stack-a dtp-instance) (assign vma top-of-stack-a) (call instance-size)) (error-if (greater-fixnum-unsigned macro-unsigned-immediate a-temp) illegal-subscript) (parallel (assign vma (+ top-of-stack-a macro-unsigned-immediate)) (jump newtopmem))) (definst %instance-loc unsigned-immediate-operand (parallel (check-arg-type instance top-of-stack-a dtp-instance) (assign vma top-of-stack-a) (call instance-size)) (error-if (greater-fixnum-unsigned macro-unsigned-immediate a-temp) illegal-subscript) (parallel (newtop (set-type (+ top-of-stack-a macro-unsigned-immediate) dtp-locative)) (next-instruction))) (definst %instance-set unsigned-immediate-operand (parallel (check-arg-type instance top-of-stack-a dtp-instance) (assign vma top-of-stack-a) (call instance-size)) (error-if (greater-fixnum-unsigned macro-unsigned-immediate a-temp) illegal-subscript) (parallel (assign vma (+ top-of-stack-a macro-unsigned-immediate)) (decrement-stack-pointer) (jump popmem))) (defareg instance-descriptor) (defareg a-hash-table) (defbreg b-message) (defbreg b-self) (defareg a-hash-table-limit) ;Come here when calling a function that turns out to be an instance (defucode funcall-instance (restart-pc restart-trapped-call-escape-pc) ;in case of page fault (parallel (accept-restart-pc) (assign vma frame-function) ;Get the instance descriptor (assign b-vma frame-function)) (start-memory read) (if (not (bit first-part-done)) (sequential (parallel (transport header) (assign a-instance-descriptor memory-data)) (assign vma (+ a-instance-descriptor %instance-descriptor-bindings)) (parallel (start-memory read) (assign frame-function (set-type b-vma dtp-instance))) ;follow-structure-forwarding (pushval (set-type (a-constant 1) dtp-fix)) ;Index of instance variable slot (parallel (pushval memory-data) ;Bindings list (transport data) (check-arg-type instance-binding-table memory-data dtp-list dtp-nil) (if (data-type? memory-data dtp-list) (parallel (assign frame-misc-data (logior frame-misc-data (b-constant (+ (byte-mask frame-instance-called) (byte-mask first-part-done))))) (clear-stack-adjustment) (jump funcall-instance-binding-loop)) (parallel (assign frame-misc-data (logior frame-misc-data (b-constant (+ (byte-mask frame-instance-called) (byte-mask first-part-done))))) (clear-stack-adjustment) (jump funcall-instance-part-2))))) (parallel (transport header) ;Here when restarting after pclsr (assign a-instance-descriptor memory-data) (jump funcall-instance-binding-loop)))) (defucode funcall-instance-binding-loop (parallel (assign vma top-of-stack-a) 4,887,235 419 420 (if (not (data-type? top-of-stack-a dtp-list)) (goto funcall-instance-part-2) ;Pclsred after binding-loop finished (drop-through))) (start-memory read) (assign b-self frame-function) (parallel (transport) (check-arg-type instance-binding memory-data dtp-fix dtp-locative) (assign b-temp memory-data) (assign a-hash-table memory-data) (if (data-type? memory-data dtp-fix) ;; Skip over some instance variable slots (assign next-on-stack (set-type (+ next-on-stack b-temp) dtp-fix)) ;; Bind this cell (sequential (pushval (set-type (+ b-self next-on-stack) dtp-external-value-cell-pointer)) (parallel (assign vma a-hash-table) (call bind-top-of-stack-closure)) (assign next-on-stack (set-type (1+ next-on-stack) dtp-fix))))) ;; a-hash-table still has the word from memory, check the cdr code to see if we’re done (parallel (newtop (set-type (1+ top-of-stack) dtp-list)) (if (cdr-code? a-hash-table cdr-next) (goto funcall-instance-binding-loop) (parallel (newtop quote-nil) ;Flag that we’re done binding (jump funcall-instance-part-2))))) ;At this point, all of the bindings have been done, two words have been pushed on the ;stack (but their contents is garbage), and first-part-done is set. Find the ;hash table for the flavor, (The non-hash-table case has been punted since ;SELF is not a special variable and would not get bound.) (defucode funcall-instance-part-2 ;; Set a-hash-tamle to the hash table (memread (+ a-instance-descriptor %instance-descriptor-function)) (parallel (transport) (check-arg-type instance-hash-table memory-data dtp-array) (assign a-hash-table memory-data)) ;; Find the first araument (the message keyword), put it in b-message (if (not (bit frame-lexpr-called)) (sequential (error-if (lesser-fixnum-unsigned frame-number-of-args (b-constant 1)) wrong-number-of-arguments) (assign b-temp frame-number-of-args) (assign xbas (- frame-pointer b-temp)) (assign b-message (amem (xbas -5)))) (if (greater-or-equal-fixnum-unsigned frame-number-of-args (b-constant 2)) (sequential (assign b-temp frame-number-of-args) (assign xbas (- frame-pointer b-temp)) (assign b-message (amem (xbas -5)))) (sequential (memread (amem (frame-pointer -6))) (parallel (transport) (assign b-message memory-data))))) ;; The hash-table is a short-leader- array, with a 1-word prefix and a 4-word leader ;; The first 3 elements are: mask, undefined-message-handler, gc-generation-number (assign vma (+ a-hash-table (b-constant 5))) ;Get the mask (start-memory read) (assign a-hash-table (+ a-hash-table (b-constant (+ 1 4 3)))) ;Start of actual hash (parallel (check-arg-type instance-hash-table-entry memory-data dtp-fix) (assign a-temp memory-data) (assign b-temp memory-data)) (assign b-temp-2 (+ a-temp (dpb b-temp 31. 1 0))) ;mask times 3 (assign a-hash-table-limit (+ a-hash-table b-temp-2)) (parallel (assign b-temp (logand b-message a-temp)) ;mask symbol with mask (assign a-temp obus)) (assign b-temp-2 (+ a-temp (dpb b-temp 31. 1 0))) ;multiply that by 3, use as hash (parallel (assign vma (+ a-hash-table b-temp-2)) (assign b-temp obus) (jump funcall-instance-hash-loop))) (defucode funcall-instance-hash-loop (parallel (start-memory read) (trap-if (greater-pointer b-temp a-hash-table-limit) (parallel (trap-no-save) (assign vma a-hash-table) (assign b-temp a-hash-table) (jump funcall-instance-hash-loop)))) (assign b-self frame-function) (parallel (trap-if (data-type? memory-data dtp-nil) (goto funcall-instance-hash-miss)) (assign a-temp memory-data)) (if (equal-typed-pointer a-temp b-message) (goto funcall-instance-hash-win) (parallel (assign vma (+ vma (b-constant 3))) 4,887,235 421 422 (assign b-temp obus) (jump funcall-instance-hash-loop)))) (defucode funcall-instance-hash-miss (parallel (trap-no-save) (assign self-mapping-table quote-nil)) (memread (- a-hash-table (b-constant 2))) ;Get miss handler (parallel (transport) (assign frame-function memory-data)) (assign self b-self) (parallel (assign first-part-done (b-constant 0)) (jump restart-trapped-call))) (defucode funcall-instance-hash-win (memread (1+ vma)) ;Get the mapping table (parallel (transport) (assign self-mapping-table memory-data)) ;; If it pclsrs here, self-mapping-table isn’t a list so it won’t ;; think it’s a binding list and go try to do the bindings (memread (1+ vma)) ;Get the method (parallel (transport) (assign frame-function memory-data)) ;Cannot pclsr any more, finish up (assign self b-self) (parallel (assign first-part-done (b-constant 0)) (jump restart-trapped-call))) F:>lmach>ucode>DIVISION.LISP.34 ;;; -*- Mode:Lisp; Package:Micro; Base:8; Lowercase:yes -*- ;;; (c) Copyright 1982, Symbolics, Inc. ; Microcode for division ;Get defmicro and all his hosts #M (declare (cond ((not (status feature lmucode)) (load 'udcls)))) ;Temporary storage (reserve-scratchpad-memory 2434 2437) (defareg a-positive-divisor) ;Magnitude of divisor (defareg a-negative-divisor) ;2’s-complement of that (defareg a-divide-step-count) ;Number of bits over 2 minus 1 (counts down) (define-b-temps b-high-dividend ;Ends up with remainder b-low-dividend) ;Ends Up with quotient ;Given dividend and divisor on the stack, set up internal variables (defmicro integer-divide-setup (index &optional float-version) `(sequential (parallel (check-binary-arithmetic-operands-fast no-operand ,index nil ,float-version) (assign b-low-dividend next-on-stack) (if (minus-fixnum next-on-stack) (assign b-low-dividend (- next-on-stack)) (drop-through))) (parallel (assign b-high-dividend (b-constant 0)) (call divisor-setup)))) ;TRUNC2 instruction takes dividend and divisor on the stack, ;returns truncated quotient and remainder on the stack. ;--- This code needs to be bummed, it wastes 5 whole cycles (definst trunc2 no-operand (integer-divide-setup %arith-op-divide) (call trunc2-internal) (assign next-on-stack ;Quotient (set-cdr (set-type b-low-dividend dtp-fix) cdr-next)) (parallel (newtop (set-type b-high-dividend dtp-fix)) ;Remainder (next-instruction))) ;;; This is necessary because for floating point calculating remainder is expensive. ;;; Therefore the compiler generates calls to these instructions if possible (definst quotient-stack no-operand (integer-divide-setup %arith-op-divide fdiv) (call trunc2-internal) (parallel (next-instruction dtp-fix)) (definst remainder-stack no-operand (integer-divide-setup %arith-op-remainder) (call trunc2-internal) (parallel (pop2push (set-type b-high-dividend dtp-fix)) (next-instruction))) (defucode trunc2-internal (call divide-subroutine) ;Do the division 4,887,235 423 424 ;Now compute results, using truncate mode (if (plus-or-zero-fixnum next-on-stack) ;Check sign of dividend (if (plus-or-zero-fixnum top-of-stack-a) ; and of divisor (return) (parallel (assign b-low-dividend (- b-low-dividend)) (return))) (sequential (if (plus-or-zero-fixnum top-of-stack-a) (assign b-low-dividend (- b-low-dividend)) (error-if (minus-fixnum b-low-dividend) unimplemented-arithmetic)) ;--- (parallel (assign b-high-dividend (- b-high-dividend)) (return))))) ;Given divisor at the top of the stack, and dividend already set up, ;finish setting up the division. (defucode divisor-setup (parallel (assign a-positive-divisor top-of-stack-a) (if (minus-fixnum top-of-stack-a) (assign a-positive-divisor (- top-of-stack-a)) (drop-through))) (parallel (assign a-negative-divisor (- a-positive-divisor))) (parallel (assign a-divide-step-count (a-constant 15.)) (return))) ;15=32/2-1, see call to divide-routine ;Do 32 divide steps in a loop unrolled n-steps ways, 2 cycles per bit. ;D1VIDE-n-ADD-b is the nth (from the end) step for when we should add, ;because we subtracted too much last time, where b (8 or 1) is the ;next bit to shift in from the low half of the dividend. ;DIVIDE-n-SUB-b is the step for when we should subtract. ;DIVIDE-n-Q1 is the seccnd cycle of the step, with a quotient bit of 1. ;DIVIDE-n-Q0 is the second cycle with a quotient bit of -. (defmacro divide-routine (n-steps) `(progn 'compile . ,(loop for step downfrom n-steps above 0 collect `(defucode ,(fintern "DIVIDE-~D-SUB-0" step) (parallel (assign b-high-dividend (+ a-negative-divisor (dpb b-high-dividend 31. 1 0))) (if (minus-fixnum obus) (goto ,(fintern "DIVIDE-~D-Q0" step)) (goto ,(fintern "DIVIDE-~D-Q1" step))))) collect `(defucode ,(fintern "DIVIDE-~D-SUB-1" step) (parallel (assign b-high-dividend (+ a-negative-divisor (dpb b-high-dividend 31. 1 0) 1)) (if (minus-fixnum obus) (goto ,(fintern "DIVIDE-~D-Q0" step)) (goto ,(fintern "DIVIDE-~D-Q1" step))))) collect `(defucode ,(fintern "DIVIDE-~D-ADD-0" step) (parallel (assign b-high-dividend (+ a-positive-divisor (dpb b-high-dividend 31. 1 0))) (if (minus-fixnum obus) (goto ,(fintern "DIVIDE-~D-Q0" step)) (goto ,(fintern "DIVIDE-~D-Q1" step))))) collect `(defucode ,(fintern "DlVIDE-~D-ADD-1" step) (parallel (assign b-high-dividend (+ a-positive-divisor (dpb b-high-dividend 31. 1 0) 1)) (if (minus-fixnum obus) (goto ,(fintern "DIVIDE-~D-Q0" step)) (goto ,(fintern "DIVIDE-~D-Q1" step))))) collect `(defucode ,(fintern "DIVIDE-~D0-Q0" step) ,@(if (= step 1) `((parallel (assign a-divide-step-count (1- a-divide-step-count)) (if (minus-fixnum obus) (sequential ;Remainder correction (assign b-high-dividend (+ b-high-dividend a-positive-divisor)) (parallel (assign b-low-dividend (dpb b-low-dividend 31. 1 0)) (return))) (drop-through))))) (parallel (assign b-low-dividend (dpb b-low-dividend 31. 1 0)) (if ybus-31 (goto ,(fintern "DIVIDE-~D-ADD-1" (if (> step 1) (1- step) n-steps))) (goto ,(fintern "DIVIDE-~D-ADD-0" (if (> step 1) (1- step) n-steps)))))) 4,887,235 425 426 collect `(defucode ,(fintern "DIVIDE-~D-Q1" step) ,@(if (= step 1) `((parallel (assign a-divide-step-count (1- a-divide-step-count)) (if (minus-fixnum obus) (parallel (assign b-low-dividend (1+ (dpb b-low-dividend 31. 1 0))) (return)) (drop-through))))) (parallel (assign b-low-dividend (1+ (dpb b-low-dividend 31. 1 0))) (if ybus-31 (goto ,(fintern "DIVIDE-~D-SUB-1" (if (> step 1) (1- step) n-steps))) (goto ,(fintern "DIVIDE-~D-SUB-0" (if (> step 1) (1- step) n-steps))))))))) ;For the simulator, make it small and slow (divide-routine 2) ;This does the first step and enterm the loop at the appropriate point ;The first step is different in that the dividend is not shifted beforehand. ;Tne first step is also different in that if it produces a quotient bit of 1 ;there is divide overflow (unsigned quotient doesn’t fit in 32 bits). ;For inteaer division, this only happens when the divisor is zero, ;or when dividing setz by -1 (overflow to bignum) (defucode divide-subroutine (parallel (assign b-high-dividend (+ a-negative-divisor b-high-dividend)) (if (minus-fixnum obus) (parallel (assign b-low-dividend (dpb b-low-dividend 31. 1 0)) (if ybus-31 (goto DIVIDE-2-ADD-1) ;2: see divide-routine macro above (goto DIVIDE-2-ADD-0))) ;.. (signal-error divide-by-zero)))) F:>lmach>ucode>disk.lisp.56 ;;; -*- Mode:Lisp; Package:Micro; Base:8; Lowercase:yeo -*- ;;; (c) Copyright 1982, Symbolics, Inc. ;;; Microcode for the disk ;To do: ; Save control memory by subroutinizing more, including the nops ; Add network to device service task (reserve-scratchpad-memory 2510 2514 351 356) ;Do not use define-b-temps here, since this microprogram runs asynchronously ;with the emulator task ;;; "Hardware" definitions ;%device-service-task -- low-priority task started at device-service-loop ;%disk-dma-task -- high-priority tack started by service task when required (define-lbus-card iob) ;;; Current state of the disk tasks ;This register contains the physical address of the next word to be transferred ;It can be looked at by macrocode (after a disk transfer) ;The sign bit is 0 if this is the last DAP, 1 if more addresses follow (data chaining) (defareg %disk-memory-address) (defatomicro disk-memory-address %disk-memory-address) ;synonym without the % ;This register contains the number of words remaining to be transferred, minus 2. ;before advancing to the next DAP. For the last DAP, this is the number of words ;remainin in the block, minus 3 for a write or read-compare, or 4 for a read. ;Note: this register must be in the top 16 B registers to avoid having to ;make disk-new-dap two cycles slower, which is undesirable since it runs ;in a high-priority task. (defbreg-at-loc disk-word-count 376) (defareg %disk-dcw-address) ;Physical address of the first word in the ;DCW command block currently being executed (defareg disk-dap-address) ;Address from which the next DAP will be fetched (defbreg current-disk-dcw) ;Copy of DCW currently being executed (defbreg current-disk-dcw2) ;Second word of current DCW ;For transfer commands, this is the desired sector header 4,887,235 427 428 (defareg %disk-sector-max-tries (set-type 20. dtp-fix)) (defareg disk-sector-tries) ;Counts header compares to detect "search error", maybe ;due to disk heads being positioned wrong. (defareg %disk-command-address) ;Physical address of disk command register (defareg %disk-status-address) ;Physical address of disk status register (defbreg disk-command-val1) ;First command to issue (search or transfer) ;Also used generally to hold disk status and as temporary (defbreg disk-command-val2) ;Second command to issue (transfer: write or read-compare) (defbreg disk-command-stop) ;Value to store to stop it (no start bit) (defareg disk-temp) ;Temporary for read-disk-status-to-val1 (defareg %disk-wakeup) ;Normally NIL, set to T by wakeup DCW, stop DCW, or error (defareg %disk-micro-status) ;A fixnum which is the state of the microcode tasks ;Used both for intercommunication between the 2 micro ;tasks and for communication with the Lisp-coded driver (defatomic-byte-field disk-micro-status (4 0) %disk-micro-status) (associate-dispatch-cues disk-micro-status *disk-micro-status-codes*) (define-enumerated-value-constants *disk-micro-status-codes*) (asocciate-dispatch-cues %%dcw-micro-command *dcw-micro-commands*) (defareg service-task-requests 0) ;Bits for each function required (defatomic-byte-field %%service-disk (1 0) service-task-requests) ;DMA task done; ready for next DCLI ;;; Regular net service (defatomic-byte-field %%service-net (1 1) service-task-requests) ;;; Receive end service (defatomic-byte-field %%service-receive-end (1 2) service-task-requests ;;; Abnormal transmit termination (defatomic-byte-field %%service-transmit-collision (1 3) service-task-requests) ;Wakeup the disk driver macrocode ;This is called in the service task (defmicro wakeup-driver () `(parallel (assign %disk-wakeup quote-t) (call set-sequence-break))) ;Wakeup the disk service task ;This is called in the DMA task usually, but can also be called by the emulator (defmicro wakeup-disk-service () `(parallel (assign service-task-requests (logior service-task-requests (b-constant (byte-mask %%service-disk)))) (wakeup-task %device-service-task))) ;Set the state of the disk DMA task. Hardware will wake it up. (defmicro start-disk-dma (location) `(write-task-state %disk-dma-task (a-constant `(build-task-state cpc ,location npc (npc-successor ,location) csp 17)))) ;Dismiss in both the CPU and the IOB, when not starting a dma cycle (defmicro dismiss-disk-task () `(parallel (write-lbus-dev iob 4 nil) (dismiss))) ;Same, with task-acknowledge (prevent overrrun) (defmicro dismiss-disk-task-and-ack (&optional end-flag) `(parallel (write-lbus-dev iob ,(if end-flag 6 2) nil) (dismiss))) ;Space-saver (defmicro phys-mem-read (address) `(parallel (start-memory read physical ,address) (call phys-mem-read-delay) (declare-memory-timing (next data-cycle)))) (defucode phys-mem-read-delay (return)) ;Terminate the disk DMA task (called in that task). This is used for ;both normal and error termination. Sets %disk-micro-status to its ;argument, awakens the service task, kills the disk dma task assignment, ;and dismisses (looping a little until the dismiss takes effect). ;This also clears control tag, while leaving the rest of the command ;register, and the error status, intact. We must store into %disk-micro-status ;before awakening the service task, since we might enter this microsequence ;with a dismiss of the DMA task already pending. (defmicro terminate-disk-dma (disk-status-code) `(sequential (parallel (extra-time-to-drive-lbus) ;Needed by many callers, save typing (assign %disk-micro-status (set-type ,disk-status-code dtp-fix))) (parallel (wakeup-disk-service) (jump terminate-disk-dma)))) 4,887,235 429 430 (defucode terminate-disk-dma (parallel (dismiss) (write-lbus-dev iob 5 nil) ;Clear tack assignment, control tag (jump terminate-disk-dma))) ;Keep stabbing until the blood flows ;The IOB is slow to drive the write-data onto the bus ;Put the extra tims in the first half so it occurs before the clock ;We want the ecc bits to be set up at the memory before the clock (write command) (defmicro extra-time-to-drive-lbus () `(microinstruction speed slow-first-half)) ;It’s slow for microdevice reads, too, for the same reason (defatomicro read-disk-buffer (parallel (read-lbus-dev iob 0) (declare-speed slow-first-half))) ;This kludge is to compensate for the fact that the disk status register is not ;synchronized with the Lbus clock. There is no safe way to read a consistent ;set of bits, however we can read whatever we get as long as we don’t put it ;in a place that has parity checking. ;Result ends up in the disk-command-val1 B-register (low 28 bits only) (defmicro read-disk-status-to-val1 () `(parallel (start-memory read physical %disk-status-address) (call read-disk-status-to-val1))) (defucode read-disk-status-to-val1 (parallel (declare-memory-timing active-cycle) (assign disk-temp frame-pointer)) ;Save register while awaiting memory (assign frame-pointer memory-data) ;Capture and synchronize memory data (assign disk-command-val1 frame-pointer) ;Store result (parallel (assign frame-pointer disk-temp) (return))) ;;; Disk DMA task. ;This micro generates the search for sector header at the front of a DMA routine ;Entered the first time with the disk idle, future times with the disk reading ;5 cycles per wakeup if sector not fcund ;1 cycle (plus body) when sector found (defmacro define-disk-search-ucode (tag &body body) (or (eq (car body) 'goto) (setq body `(sequential . ,body))) `(defucode ,tag ;; Stop the disk state machine if it is running (parallel (start-memory write physical %disk-command-address) (assign memory-data disk-command-stop)) ;; Start the hardware searching for the next sector header (parallel (start-memory write physical %disk-command-address) (assign memory-data disk-command-val1)) ;; Dismiss until the header has been read (parallel (dismiss-disk-task) ;; Stop if too many tries without a header match (assign disk-sector-tries (1- disk-sector-tries)) (if (minus-fixnum obus) (terminate-disk-dma %disk-micro-status-search-error) (nop))) ;; Come back here on next wakeup, with header in disk buffer register ;; If header matches, drop through: otherwise keep searching (if (not-equal-fixnum current-disk-dcw2 read-disk-buffer) (goto ,tag) ,body))) ;Call here when a DAP has been exhausted and we need to start transferring ;at a new address. Haven’t dismissed yet after transferring the last word ;in the old DAP’s block of addresses. Dismisses and returns on next wakeup, ;with address and word count set up from new DAP. Skips upon return if ;this was not the last DAP. ;We use up 6 cycles instead of the usual 2 per wakeup. (defucode disk-new-dap (nop) ;Wait for memory to be unbusy (parallel ;Fetch first word of DAP (start-memory read physical disk-dap-address) (assign disk-dap-address (1+ disk-dap-address))) (parallel ;Fetch second word of DAP (start-memory read physical disk-dap-address) (assign disk-dap-address (1+ disk-dap-address))) (parallel (dismiss-disk-task) (assign disk-word-count memory-data)) (parallel (assign disk-memory-address memory-data) (return-skip (minus-fixnum memory-data)))) ;Test chain bit 4,887,235 431 432 ;Read routine. Use this for both 32-bit and 36-bit reads. (define-disk-search-ucode disk-read ;; Wait for first data word in sector (dismiss-disk-task-and-ack) (if (minus-fixnum disk-memory-address) (goto disk-read-loop) (goto disk-read-loop-last))) ;DMA transfer loop, when this is not the last DAP (defucode disk-read-loop ;; First cycle: increment MA, start memory (parallel (start-memory write physical disk-memory-address dma iob 3) (assign disk-memory-address (1+ disk-memory-address)) (dismiss) (if lbus-dev-cond (terminate-disk-dma %disk-micro-status-disk-error) (drop-through))) ;; Second cycle: count down WC. (parallel (extra-time-to-drive-lbus) (assign disk-word-count (1- disk-word-count)) (if (minus-fixnum obus) (parallel ;; First cycle for last word in this DAP. Transfer then fetch next DAP. ;; We don’t check for disk-error here, but if there is one we’ll ;; notice it soon enouch. (start-memory write physical disk-memory-address dma lob 1) (assign disk-memory-address (1+ disk-memory-address)) (call-and-return-skip disk-new-dap disk-read-loop-last disk-read-loop)) (goto disk-read-loop)))) ;DMA transfer loop, when this is the last DAP (defucode disk-read-loop-last ;; First cycle: increment MA, start memory (parallel (start-memory write physical disk-memory-address dma iob 3) (assign disk-memory-address (1+ disk-memory-address)) (dismiss) (if lbus-dev-cond (terminate-disk-dma %disk-micro-status-disk-error) (drop-through))) ;; Second cycle: count down WC. (parallel (extra-time-to-drive-lbus) (assign disk-word-count (1- disk-word-count)) (if (minus-fixnum obus) (goto disk-read-drain) (goto disk-read-loop-last)))) ;Here to read the last 3 words (defucode disk-read-drain ;; Transfer last word with end flag, then 2 more drain words which ;; the disk sends before it stops (parallel (start-memory write physical disk-memory-address dma iob 7) (assign disk-memory-address (1+ disk-memory-address)) (dismiss) (if lbus-dev-cond (terminate-disk-dma %disk-micro-status-disk-error) (drop-through))) (parallel (extra-time-to-drive-lbus) (nop)) (parallel (start-memory write physical disk-memory-address dma iob 7) (assign disk-memory-address (1+ disk-memory-address)) (dismiss) (if lbus-dev-cond (terminate-disk-dma %disk-micro-status-disk-error) (drop-through))) (parallel (extra-time-to-drive-lbus) (nop)) (parallel (start-memory write physical disk-memory-address dma iob 7) (assign disk-memory-address (1+ disk-memory-address)) (dismiss) (if lbus-dev-cond (terminate-disk-dma %disk-micro-status-disk-error) (drop-through))) (parallel (extra-time-to-drive-lbus) (nop)) ;; Wake up here when state machine stops, after reading ECC (terminate-disk-dma %disk-micro-status-end-read)) ;Write routine, Use this for both 32-bit and 36-bit writes. ;6 cycles the first time through (define-disk-search-ucode disk-write ;; Stop the disk state machine (parallel