;;; -*- Mode:LISP; Package:si; Base:10; -*- ;;; This file contains the definitions for the mini ethernet system ;;; that are specific to the ethernet board hosted on the NuBus. ;;; From the file "NuBus-Basic" ;;; MACROS/FUNCTIONS TO READ & WRITE THE NuBUS ;;; ;;; Copyright (c) 1984 Texas Instruments Incorporated All Rights Reserved ;;; ;;; NOTE - %NuBus-Read & %NuBus-Write read & write 32 bit values. ;;; - SLOT is the upper 8 bits of NuBus address and not just the 4 bit ;;; slot number. ;;; NOTE - Substs are used here for efficiency and convenience. ;;; The calls could just as easily been Macros or Functions. ;;;---------------------------------------------------------------------------- (DefMacro LO-BYTE (word) `(LDB #o0010 ,word)) (DefMacro HI-BYTE (word) `(LDB #o1010 ,word)) (DefMacro SWAP-BYTES (word) `(DPB (lo-byte ,word) #o1010 (hi-byte ,word))) (DefSubst LO-16B-WORD-P (addr) ;; Returns T if ADDR is the low 16 bits of the quad defined by ADDR. ;; I.e T iff bit 1 is a zero. (Zerop (Ldb #o0101 addr))) ;;---------------------------------------------------------------------------- ;; READ AND WRITE NuBUS ;;---------------------------------------------------------------------------- ;; ;;; +++ Note: The NuBus Ethernet controller seems to get NuBus timeout fairly ;;; +++ often so retries are built in at this low level interface. (DefConst *max-nubus-retries* 50.) (DefVar *nubus-references* 0) (DefVar *nubus-retries* 0) (DefSignal Ethernet-NuBus-Error error nil) (Defun Careful-NuBus-Read (slot addr) (Or (%nubus-read-safe slot addr) (Progn (Incf *nubus-references*) (Do ((retries 1 (1+ retries)) (value (%nubus-read-safe slot addr) (%nubus-read-safe slot addr))) ((Or (Not (Null value)) (> retries *max-nubus-retries*)) ;; Return value if successful otherwise signal an error. (Or value (Ferror 'Ethernet-NuBus-Error "NuBus read error"))) (Incf *nubus-retries*)))) ) (Defun Careful-NuBus-Write (slot addr data) (Or (%nubus-write-safe slot addr data) (Progn (Incf *nubus-references*) (Do ((retries 1 (1+ retries)) (value (%nubus-write-safe slot addr data) (%nubus-write-safe slot addr data))) ((Or (Not (Null value)) (> retries *max-nubus-retries*)) ;; Return value if successful otherwise signal an error. (Or value (Ferror 'Ethernet-NuBus-Error "NuBus write error"))) (Incf *nubus-retries*)))) ) ;;; Return the 16bit value from NuBus at ADDR in SLOT-address. (DefSubst NUBUS-READ (slot addr) (Ldb (If (lo-16b-word-p addr) #o0020 #o2020) (Careful-NuBus-Read slot addr))) ;;; Writes a 16 bit value to NuBus. DO NOT DEPEND on the returned value! (DefSubst NUBUS-WRITE (slot addr val) (Careful-NuBus-Write slot addr (Dpb val ;Place value in ... (If (lo-16b-word-p addr) #o0020 #o2020) (Careful-NuBus-Read slot addr) ;...its part of the quad. ))) ;; Define (Setf (NuBus-Read slot adr) val). (Defsetf NuBus-Read NuBus-Write) ;;---------------------------------------------------------------------------- ;; READ & WRITE ETHERNET ADDRESS FIELDS. ;; NOTE - Ethernet addresses must be written in the buffer memory in the order ;; in which they are transmitted and not in the order written on the board. ;;---------------------------------------------------------------------------- ;;; Read the Ethernet address at ADDR in SLOT. (DefSubst ENC-ETHER-ADDRESS (slot addr) (Let ((temp 0)) (Setq temp (deposit-byte temp 0 16. (swap-bytes (NuBus-Read slot (+ 4 addr))))) (Setq temp (deposit-byte temp 16. 16. (swap-bytes (NuBus-Read slot (+ 2 addr))))) (Setq temp (deposit-byte temp 32. 16. (swap-bytes (NuBus-Read slot addr)))) temp)) ;;; Place ethernet addr, ADDRESS, at ADDR reletive to SLOT. (DefSubst SET-ENC-ETHER-ADDRESS (slot addr address) (Nubus-Write slot addr (swap-bytes (ldb #o4020 address))) (Nubus-Write slot (+ addr 2) (swap-bytes (ldb #o2020 address))) (Nubus-Write slot (+ addr 4) (swap-bytes (ldb #o0020 address)))) ;; Define (SETF (ENC-ETHER-ADDRESS s a) value) (Defsetf Enc-Ether-Address Set-Enc-Ether-Address) ;;---------------------------------------------------------------------------- ;; READ & WRITE 24 BIT ADDRESS FIELDS ;;---------------------------------------------------------------------------- ;;; Read a 24 bit Address at ADDR, relative to SLOT, quad aligned. (DefSubst ADDRESS-FIELD (slot addr) (LogAnd #xFFFFFF (Careful-NuBus-Read slot addr))) ;;; Place a 24 bit address, ADDRESS, at ADDR reletive to SLOT, quad aligned. (DefSubst WRITE-ADDRESS-FIELD (slot addr address) (Careful-NuBus-Write slot addr (DPB (LDB #o3010 (Careful-NuBus-Read slot addr)) #o3010 address))) ;; Define (SETF (ADDRESS-FIELD s a) value) (Defsetf Address-Field Write-Address-Field) ;;---------------------------------------------------------------------------- ;; READ & WRITE TO BUFFERS ;;---------------------------------------------------------------------------- ;;; Copies ARRAY (between START & STOP-1) to the NuBus at SLOT, beginning at ADDR. ;;; ARRAY must be art16b, ;;; ADDR must be on quad boundary, START & STOP must be even. (DefSubst XFER-WORDS-TO-NuBUS (slot addr array start stop) (Do ((Nuaddr addr (+ 4 nuaddr)) (I start (+ 2 I))) ((>= i Stop)) (Careful-NuBus-Write slot nuaddr (Dpb (Aref array (1+ I)) #o2020 (Aref array I))))) ;;; Copies into ARRAY (between START & STOP-1) from the NuBus at SLOT, ;;; beginning at ADDR. ;;; ARRAY must be art16b, ADDR must be on quad boundary. ;;; Will *always* copy an EVEN number of bytes, beginning at START ! (DefSubst XFER-WORDS-FROM-NuBUS (slot addr array start stop) (Do (value (Nuaddr addr (+ 4 nuaddr)) (I start (+ 2 I))) ((>= i Stop)) (Setq Value (Careful-NuBus-Read slot nuaddr)) (Aset (Ldb #o0020 value) array i) (Aset (Ldb #o2020 value) array (1+ i)))) ;;-------------------------------------------------------------------- ;; GENERAL PURPOSE MACROS ;; To Make Life Easier ;;-------------------------------------------------------------------- ;;; Round ADDR up to an even number. (DefSubst ROUND-UP-TO-EVEN (addr) (Dpb 0 #o0001 (1+ addr))) ;;; Round ADDR up to an even multiple of 4. (eval-when (eval load compile) (DefSubst ROUND-UP-TO-QUAD (addr) (Dpb 0 #o0002 (+ addr 3)))) (DefMacro ON-OFF (value) `(If (zerop ,value) "Off" "On")) (Defmacro CONVERT-TO-WORDS (nbytes) `(Ash (1+ ,nbytes) -1)) ;;-------------------------------------------------------------------- ;; NuBUS MACROS ;; To Make Life Still Easier Yet ;;-------------------------------------------------------------------- ;; These are compile-time macros used to generate the Functions, etc. in this file. ;; They are not used at run time. ;; The Macros generated by the next two Macros can be used with (SETF (...) ...). ;; The generated MACRO will default the offset field to the System Control Block (SCB). (defmacro DEF-NuFIELD (name field-offset comment) ;;Create a MACRO called NAME to access the field at displacement FIELD-OFFSET. ;;The MACRO take 2 args; the TI-NUBUS-ETHERNET-CONTROLLER and base addr of the block. `(Defmacro ,NAME (enc &optional block-offset) ,comment (if block-offset `(NuBus-Read (ENC-slot ,enc) (+ ,',field-offset ,block-offset)) `(NuBus-Read (ENC-slot ,enc) (+ ,',field-offset (ENC-SCB ,enc))) )) ) ;;; Create a MACRO called NAME to access a byte field, described by BYTE-DESC, ;;; in the field accessed by (WORD ,enc ,base). ;;; The MACRO take 2 args; the TI-NUBUS-ETHERNET-CONTROLLER and the base addr ;;; of the block. (DefMacro Def-NuBYTEF (name word byte-desc comment) `(Defmacro ,NAME (enc &optional block-base) ,comment (If block-base `(Ldb ,',byte-desc (,',word ,enc ,block-base)) `(Ldb ,',byte-desc (,',word ,enc (Enc-SCB ,enc))))) ) ;;; Sends output to STREAM, and uses ENC (controller. (Defmacro PRINT-FLAG-DOC (state flag base-addr) `(When (= ,state (,flag enc ,base-addr)) (terpri stream) (princ (documentation #',flag) stream)) ) ;;; From the file "Nu-Ether-Defs" ;;; ;;; Copyright (c) 1984 Texas Instruments Incorporated All Rights Reserved ;;; ;;-------------------------------------------------------------------- ;; DESCRIPTION OF NuBUS ETHERNET CONTROLLER ;;-------------------------------------------------------------------- (Defvar Nubus-receive-frame-errors 0) (Defvar Nubus-receive-frame-error-list nil) ;; Miscellaneous constants which help define the Ethernet environment (Defconst *MAX-NUMBER-BYTES* 1024. "Max number bytes in a buffer") ;Field allows 16K, we don't have that much space. (Defconst *INTERRUPT-DRIVEN-P* nil "T if interrupt driven, NIL if polled.") ;No interrupt capability yet. ;; Effective size of fields in the buffer memory space (Defconst SCP-SIZE 10 "Bytes in System Configuration Pointer") (Defconst ISCP-SIZE #.(Round-up-to-quad 8) "Bytes in Intermediate System Control Pointer") (Defconst SCB-SIZE #.(Round-up-to-quad 20) "Bytes in System Control Block") (Defconst COMMAND-SIZE #.(Round-up-to-quad 18) "Bytes in a Command Block") (Defconst RECEIVE-BLOCK-SIZE #.(Round-up-to-quad 22) "Bytes in a Receive Frame Descriptor.") (Defconst TBD-SIZE #.(Round-up-to-quad 8) "Bytes in a Transmit Buffer Descriptor") (Defconst RBD-SIZE #.(Round-up-to-quad 10) "Bytes in a Receive Buffer Descriptor") (Defconst DUMP-AREA-SIZE #.(Round-up-to-quad 170) "Bytes required for 586 Dump buffer") ;; Modify following values to change the default description of a NuBus Controller (Defstruct (NUBUS-ETHERNET-CONTROLLER (:conc-name ENC-)) ;; All sizes are in Bytes. (Request-Lock nil) ; Mutual exclusion to use the COMMAND UNIT. ;; You MUST have this lock before alloc a transmit CB or buffer or issuing an action command. (Write-Lock nil) ; Mutual exclusion to Write to controller, not used. (Slot #xFB) ; Slot number of this controller (ISCP 0) ; Address of Intermediate System Contol Pointer (SCB ISCP-Size) ; Offset to the System Control Block (Config-Register 0) ; Last value written to Config Register. (Memory-Size (* 32 1024.)) ; Size of memory buffer. (Transmit-Buffer-Size 504.) ; Size of the transmit buffers. (Transmit-Buffers-Per-Frame 2.) ; Number of buffers per command block. (Receive-Buffer-Size 56.) ; Size of the receive buffers. (Receive-Buffers-Per-Frame 8.) ; Number of buffers / Recv. Frame descriptor. (Last-RBD -1) ; Offset to the last Free RBD. (Last-Free-RFD -1) ; Offset to the last free RFD. ) ;; Computed "slots" in the Defstruct (Defmacro ENC-TRANSMIT-FRAME-SIZE (enc) ; Number bytes / Command Block `(+ COMMAND-SIZE (* (ENC-Transmit-Buffers-Per-Frame ,enc) (+ (ENC-Transmit-Buffer-Size ,enc) TBD-SIZE)))) (Defmacro ENC-RECEIVE-FRAME-SIZE (enc) ; Number of bytes / Recv. Frame Desc. `(+ RECEIVE-BLOCK-SIZE (* (ENC-Receive-Buffers-Per-Frame ,enc) (+ (ENC-Receive-Buffer-Size ,enc) RBD-SIZE)))) (Defmacro ENC-SCP-ADDR (enc) ; location of System Config ptr `(- (ENC-Memory-size ,enc) SCP-SIZE)) ;;; Without interrupts, Ensure that SCB is free, eval BODY to set the command ;;; & issue the Channel-Attention. (Defmacro ISSUE-COMMAND (enc &Body body) `(Do ((i 1 (1+ i)) (INHIBIT-SCHEDULING-FLAG T)) ((zerop (SCB-Command ,enc)) ,@body (Channel-Attention ,enc)) (Setq INHIBIT-SCHEDULING-FLAG nil) (when (> i 1000.) (cerror ':Yes nil nil "Previous command to Ethernet Controller did not clear after ~D PROCESS-ALLOW-SCHEDULE" i) (setq i 1)) (Process-Allow-Schedule) (Setq INHIBIT-SCHEDULING-FLAG T)) ) ;;; +++ I'm not sure this condition handling code works but if we get to it ;;; +++ things have really gone bad (~ 50 retries already). -- Wayne (DefVar NuBUS-ERRORS 0) (DefVar NuBUS-Errors-in-a-Row 0) (DefConst Max-NuBus-Errors 10.) (DefMacro HANDLING-NUBUS-CONDITION (enc &body body) `(Condition-Case (.error.) (progn ,@body) (Ethernet-NuBus-Error (Handle-NuBus-Error ,enc .error.)) (:No-Error (Setq NuBus-Errors-in-a-Row 0) .error.)) ) ;;; Resets the Controller, unless too many errors have occured, then cause an Ferror. (Defun HANDLE-NuBUS-ERROR (enc condition) (Incf NuBUS-ERRORS) (Incf NUBUS-ERRORS-IN-A-ROW) (If (>= NUBUS-ERRORS-IN-A-ROW MAX-NUBUS-ERRORS) (Unwind-Protect (Ferror nil "Unable to Read//Write NuBus Ethernet at Slot ~16R." (Enc-Slot enc)) (Setq NUBUS-ERRORS-IN-A-ROW 0)) (With-Lock ((Enc-Request-Lock enc)) ; Wait for lock to be released? (Initialize enc)) ; Reset the controller board. (EH:Invoke-Resume-Handler condition nil)) ) ;;-------------------------------------------------------------------- ;; BASIC DATA STRUCTURES ;; ;; Note - ALL blocks defined on the following pages MUST start on a Quad ;; boundary. The constructor functions all ASSUME that they are ;; given a valid quad address. They also assume that their other ;; parameters are valid. ;;-------------------------------------------------------------------- ;; HARDWARE CONSTANTS FOR THIS CONTROLLER ;;-------------------------------------------------------------------- ;; Fixed locations within the NuBus Ether Controller memory (DefConst *CHANNEL-ATTENTION-ADDR* #x008000 "Hit this address to assert CA") (DefMacro *CHANNEL-ATTENTION-ADDR* () #x008000) (DefConst *EVENT-ADDRESS-REGISTER* #x00A000 "Contains address for event register") (DefConst *CONFIG-REGISTER* #x00C000 "Address of config register") (DefMacro *CONFIG-REGISTER* () #x00C000) ; "Address of config register" (DefConst *SCP-ADDR* #xFFFFF6 "Address of Sys Config Ptr.") ;; Standard constants for this controller (DefMacro *NULL-STATUS* () 0) ;"A status word with everything set to nil" (DefMacro *NORMAL-FINISH* () #xA000) ;Normal, correct completion. (DefMacro *NULL-COMMAND* () 0) ;A Null command. (DefMacro *NULL-CMD-EOL* () #x8000) ;A Null command with End-Of-List on. (DefMacro *NULL-PTR* () #xFFFF) ;An 82586 nil pointer. ;;-------------------------------------------------------------------- ;; SYSTEM CONFIGURATION POINTER ;;-------------------------------------------------------------------- ;; ;; Note: the SCP always starts at #xFFFFF6 in the chip addr space. ;;; ENC is the address; BIT-WIDTH is bit width of data bus (8 or 16). (Defun SET-SCP-SYSBUS-WIDTH (enc bit-width) (NuBus-Write (Enc-slot enc) (ENC-SCP-ADDR enc) (If (= bit-width 8) 1 0))) (Defun READ-SCP-SYSBUS-WIDTH (enc) (Let ((encoded-width (LDB #o0010 (NuBus-Read (Enc-slot enc) (ENC-SCP-ADDR enc))))) (Selectq encoded-width (0 16) (1 8) (t (print "Invalid width code for NuBus EtherNet controller")))) ) ;;; The address of the ISCP in the System Config. Pointer. (DefSubst ISCP-ADDRESS (enc) (Address-Field (Enc-slot enc) (+ (ENC-SCP-ADDR enc) 6))) ;;; Prints the values in the SCP of ENC on STREAM. (Defun PRINT-SCP (enc &optional (stream terminal-io)) (terpri stream) (princ "System Bus Width (bits) = " stream) (princ (Read-scp-sysbus-width enc) stream) (terpri stream) (princ "ISCP Address = " stream) (princ (iscp-address enc) stream)) ;;-------------------------------------------------------------------- ;; INTERMEDIATE SYSTEM CONTROL POINTER (ISCP) ;;-------------------------------------------------------------------- (Def-NuField SCB-BUSY-WORD 0 "Low Byte is 1 if busy, 0 otherwise.") (Def-NuField SCB-OFFSET 2 "Offset of SCB relative to SCB-BASE.") ;;; Base address (relative to slot) for all blocks in buffer area, except buffers. (DefSubst SCB-BASE (Enc addr) (Address-Field (ENC-slot enc) (+ addr 4))) ;;; Initialize the ISCP to location ADDR. ;;; SCB-POINTER = offset to SCB, the SCB-Base is assumed to be zero. (Defun INIT-ISCP (enc addr SCB-pointer) (Setf (ENC-ISCP enc) addr) ;Save Address of ISCP in slot. (Setf (SCB-BUSY-WORD enc ADDR) #x01) ;Set board busy (Setf (SCB-OFFSET enc ADDR) SCB-Pointer) ;set addr of SCB (Setf (SCB-BASE enc ADDR) 0) ;Base is 0. ) ;;; Returns T if the ISCP BUSY flag is set for controller ENC. (Defun ISCP-BUSYP (enc) (Not (Zerop (LDB #o0010 (SCB-BUSY-WORD enc (ENC-ISCP enc)))))) ;;; Prints the Status of the ISCP of ENC on STREAM. (Defun PRINT-ISCP-STATUS (enc &optional (stream terminal-io)) (terpri stream) (Princ "Initialization: " stream) (princ (If (ISCP-Busyp enc) "In Progress" "Complete") stream)) ;;; Prints the ISCP of ENC on STREAM. (Defun PRINT-ISCP (enc &optional (stream terminal-io)) (Print-ISCP-Status enc stream) (terpri stream) (princ "SCB base address = " stream) (princ (SCB-Base enc (enc-iscp enc)) stream) (terpri stream) (princ "SCB offset address = " stream) (princ (SCB-Offset enc (enc-iscp enc)) stream)) ;;-------------------------------------------------------------------- ;; SYSTEM CONTROL BLOCK DEFINITIONS ;;-------------------------------------------------------------------- ;; Only first 8 words are standard part of the SCB. Rest are added for this application. (Def-NuField SCB-STATUS 0 "SCB Status word (read only).") (Def-NuField SCB-COMMAND 2 "Read SCB Command word.") (Def-NuField SCB-CBL-OFFSET 4 "Ptr to Command Block List.") (Def-NuField SCB-RFA-OFFSET 6 "Ptr to Receive Frame Area.") (Def-NuField SCB-CRCERRS 8 "CRC Error counter.") (Def-NuField SCB-ALNERRS 10. "Misaligned frame counter.") (Def-NuField SCB-RSCERRS 12. "Counter of frames dropped because no buffers available.") (Def-NuField SCB-OVRNERRS 14. "Counter of frames lost to lack of bus availability.") (Def-NuField SCB-FREE-CBL 16. "Ptr to list of free Command Blocks.") (Def-NuField SCB-FREE-TBD 18. "Ptr to list of free Transmit Buffer descriptors.") (Def-NuBytef SCB-INT-FLAGS Scb-Status #o1404 "Interrupt status flags") (Def-NuBytef SCB-CX-FLAG Scb-Status #o1701 "Interrupted command executed?") (Def-NuBytef SCB-FR-FLAG Scb-Status #o1601 "Frame received interrupt") (Def-NuBytef SCB-CNR-FLAG Scb-Status #o1501 "Command unit not ready interrupt") (Def-NuBytef SCB-RNR-FLAG Scb-Status #o1401 "Receive unit not ready interrupt") (Def-NuBytef SCB-COMMAND-UNIT-STATUS Scb-Status #o1003 "Status of command unit") (Def-NuBytef SCB-RECEIVE-UNIT-STATUS Scb-Status #o0403 "status of command unit") (Def-NuBytef SCB-ACK-INT Scb-Command #o1404 "Ack Interrupts command") (Def-NuBytef SCB-ACK-CX Scb-Command #o1701 "Ack CX interrupt") (Def-NuBytef SCB-ACK-FR Scb-Command #o1601 "Ack FR Interrupt") (Def-NuBytef SCB-ACK-CNR Scb-Command #o1501 "Ack CNR Interrupt") (Def-NuBytef SCB-ACK-RNR Scb-Command #o1401 "Ack RNR Interrupt") (Def-NuBytef SCB-CONTROL-COMMAND Scb-Command #o1003 "Control unit command") (Def-NuBytef SCB-RESET Scb-Command #o0701 "Reset the controller chip") (Def-NuBytef SCB-RECEIVE-COMMAND Scb-Command #o0403 "Receive unit command") ;;; Pointer to the current receive-frame for ENC. (DefMacro SCB-CURRENT-RECEIVE-FRAME (enc) `(Command-Link ,enc (Enc-Last-Free-RFD ,enc))) ;; Command and Receive Unit States (DefMacro Idle-State () 0) (DefMacro Suspended-State () 1) (DefMacro Command-Ready () 2) (DefMacro No-Resources () 2) (DefMacro Receive-Ready () 4) ;; Transmit & Receive Unit Commands (DefMacro NOP () 0) (DefMacro START () 1) (DefMacro RESUME () 2) (DefMacro SUSPEND () 3) (DefMacro ABORT () 4) (DefSubst FRAME-RECV-INT-P (enc) (= 1 (SCB-FR-Flag enc))) ;;-------------------------------------------------------------------- ;; INITIALIZE SCB ;;; Make & initialize the SCB for controller described by ENC. ;;; Place SCB at ADDR, initialize CBL to CMD-PTR, and RFA to REC-PTR. (Defun INIT-SCB (enc addr cmd-ptr rec-ptr) (Setf (Enc-SCB enc) addr) ;Remember SCB address. (Setf (SCB-Status enc addr) (*NULL-STATUS*)) (Setf (SCB-Command enc addr) (*NULL-COMMAND*)) ;NOP the command word. (Setf (SCB-CBL-Offset enc addr) (*NULL-PTR*)) (Setf (SCB-RFA-Offset enc addr) rec-ptr) (Setf (SCB-Free-CBL enc addr) cmd-ptr) ;List of free Command Blocks (Setf (SCB-Free-TBD enc addr) (*NULL-PTR*)) (Reset-SCB-Stats enc) ; clear the statistics fields. addr) ;;; Set the Statistics fields for ENC to Zero. (Defun RESET-SCB-STATS (enc) (Setf (SCB-Crcerrs enc) 0) ;Zero CRC errors. (Setf (SCB-Alnerrs enc) 0) ;Zero alignment errors. (Setf (SCB-Rscerrs enc) 0) ;Zero frames lost to "no resources" (Setf (SCB-Ovrnerrs enc) 0) ;Zero frames lost to bus not available ) ;;-------------------------------------------------------------------- ;; PRINT SCB INFO ;;; Print the entire state of the SCB for ENC. (Defun PRINT-SCB-STATE (enc &optional (stream terminal-io)) (Print-SCB-Status enc stream) (Print-CBL-Status enc stream t) ;print status of 1st item on CBL. (Print-RFA-Status enc stream t) (terpri stream) (princ "Free Block: " stream) (princ (SCB-Free-CBL enc) stream) (terpri stream) (princ "Free Buff : " stream) (princ (SCB-Free-TBD enc) stream) (Print-SCB-Stats enc nil stream) ;Don't reset the counts. ) ;;; Print the Status of the SCB for ENC on STREAM. (Defun PRINT-SCB-STATUS (enc &optional (stream terminal-io) &aux (SCB (Enc-SCB enc))) (terpri stream) (princ "Interrupts Pending: " stream) (If (= 0 (SCB-Int-Flags enc scb)) (Princ "None" stream) (If (= 1 (SCB-CX-Flag enc SCB)) (Princ "CX " stream)) (If (= 1 (SCB-FR-Flag enc SCB)) (Princ "FR " stream)) (If (= 1 (SCB-CNR-Flag enc SCB)) (Princ "CNR " stream)) (If (= 1 (SCB-RNR-Flag enc SCB)) (Princ "RNR " stream))) (terpri stream) (princ "Command Unit = ") (princ (select (SCB-Command-Unit-Status enc scb) (((Idle-state)) "Idle") (((Suspended-state)) "Suspended") (((Command-Ready)) "Active") (otherwise "Invalid State")) stream) (terpri stream) (princ "Read Unit = " stream) (princ (select (SCB-Receive-Unit-Status enc scb) (((Idle-state)) "Idle") (((Suspended-State)) "Suspended") (((No-Resources)) "No Resources") (((Receive-Ready)) "Ready") (otherwise "Invalid State")) stream)) ;;; Print the statistics for the SCB at ENC. (Defun PRINT-SCB-STATS (enc &optional reset-p (stream terminal-io)) (terpri stream) (princ "CRC Errors: " stream) (princ (SCB-CRCerrs enc) stream) (terpri stream) (princ "Misaligned Frames: " stream) (princ (SCB-ALNerrs enc) stream) (terpri stream) (princ "Frames lost, no buffers: " stream) (princ (SCB-RscErrs enc) stream) (terpri stream) (princ "Frames lost, no bus: " stream) (princ (SCB-OvrnErrs enc) stream) (if reset-p (Reset-Scb-Stats enc))) ;;-------------------------------------------------------------------- ;; COMMAND BLOCK DEFINITIONS (Def-NuField COMMAND-STATUS 0 "The Status word of a command block") (Def-NuField COMMAND-WORD 2 "The Command word of a command block.") (Def-NuField COMMAND-LINK 4 "Pointer to next command block.") (Def-NuField COMMAND-BUFFER-PTR 6 "Pointer to 1st buffer of frame.") ;;(Def-Nufield COMMAND-DESTINATION-ADDR 8 "Ether address field") (Def-Nufield COMMAND-FRAME-TYPE 14 "Type of frame to transmit.") ;;; Ethernet Destination address of this frame. (DefSubst COMMAND-DESTINATION-ADDR (enc addr) (ENC-ETHER-ADDRESS (enc-slot enc) (+ addr 8))) ;;; PARM-NUMBER (starts at 0) parameter to the command block. (DefSubst BLOCK-PARAMETER (enc offset parm-number) (NuBus-Read (ENC-slot enc) (+ 6 parm-number parm-number offset))) ;; Additional fields of COMMAND-STATUS (Def-NuBytef COMMAND-COMPLETE-FLAG Command-Status #o1701 "Command is complete") (Def-NuBytef COMMAND-BUSY-FLAG Command-Status #o1601 "Controller executing this command.") (Def-NuBytef COMMAND-EXECUTION-STATUS Command-Status #o1602 "State of frame block") (Def-NuBytef COMMAND-STATUS-FIELD Command-Status #o0016 "Command specific status.") (Def-NuBytef COMMAND-ERROR-FLAG Command-Status #o1501 "No error occured during execution.") ;; below are transmit errors (Def-NuBytef COMMAND-ABORT-ERROR Command-Status #o1401 "Command aborted.") (Def-NuBytef COMMAND-DIAGNOSE-FAIL Command-Status #o1301 "586 failed DIAGNOSE test") (Def-NuBytef COMMAND-NO-CARRIER Command-Status #o1201 "Carrier sense lost, xmit failed.") (Def-NuBytef COMMAND-NO-CLEAR-SEND Command-Status #o1101 "Xmit failed, lost Clear to Send.") (Def-NuBytef COMMAND-XMIT-DEFERRED Command-Status #o0701 "Xmit deferred, link activity.") (Def-NuBytef COMMAND-RETRY-ERROR Command-Status #o0501 "Number of retries exhausted.") (Def-NuBytef COMMAND-RETRY-COUNT Command-Status #o0004 "Number of collisions (retries).") (Def-NuBytef COMMAND-END-OF-LIST Command-Word #o1701 "This is last block on list.") (Def-NuBytef COMMAND-SUSPEND-FLAG Command-Word #o1601 "Suspend after this block.") (Def-NuBytef COMMAND-INTERRUPT-FLAG Command-Word #o1501 "Interrupt after this block.") (Def-NuBytef COMMAND-BLOCK-CMD Command-Word #o0003 "Command byte.") ;; VALUES for COMMAND-EXECUTION-STATUS (DefMacro COMMAND-READY-TO-EXECUTE () 0) (DefMacro COMMAND-EXECUTING () 1) (DefMacro COMMAND-COMPLETE () 2) ;;(DefMacro COMMAND-AVAILABLE () 3) ; not used ;; COMMAND Numbers for Command-Block-Cmd field. (DefMacro NOP-COMMAND () "NOP command" 0) (DefMacro ADDRESS-SETUP () "Load Chip with my address" 1) (DefMacro CONFIGURE () "Send Configuration parameters to chip" 2) (DefMacro MULTICAST-SETUP () "Load Chip with Multicast addresses to accept." 3) (DefMacro TRANSMIT () "Transmit a frame" 4) (DefMacro TDR-COMMAND () "Time Domain Reflectometer test" 5) (DefMacro DUMP-STATUS () "Dump Status registers of 586 chip" 6) (DefMacro DIAGNOSE-586 () "Perform diagnostics on the 586 chip" 7) ;;-------------------------------------------------------------------- ;; RECEIVE FRAME DEFINITIONS ;;-------------------------------------------------------------------- ;; First 5 fields are the same as for a Command Block ;;(Def-NuField COMMAND-STATUS 0 "The Status word of a command block") ;;(Def-NuField COMMAND-WORD 2 "The Command word of a command block.") ;;(Def-NuField COMMAND-LINK 4 "Pointer to next command block.") ;;(Def-NuField COMMAND-BUFFER-PTR 6 "Pointer to 1st buffer of frame.") ;;(Defsubst COMMAND-DESTINATION-ADDR (enc addr) ;; "Ethernet Destination address of this frame." ;; (ENC-ETHER-ADDRESS (enc-slot enc) (+ addr 8))) ;;; Ethernet source address of this frame. (Defsubst RECEIVE-SOURCE-ADDR (enc addr) (ENC-ETHER-ADDRESS (enc-slot enc) (+ addr 14))) (Def-Nufield RECEIVE-FRAME-TYPE 20 "Type of frame received.") (Def-NuBytef COMMAND-CRC-ERROR Command-Status #o1301 "CRC error in aligned frame.") (Def-NuBytef COMMAND-ALIGN-ERROR Command-Status #o1201 "CRC error in misaligned frame.") (Def-NuBytef COMMAND-BUFFER-ERROR Command-Status #o1101 "Ran out of buffer space.") (Def-NuBytef COMMAND-DMA-ERROR Command-Status #o1001 "DMA Over(under)run recv (xmit)") (Def-NuBytef COMMAND-TOO-SHORT Command-Status #o0701 "Frame too short.") (Def-NuBytef COMMAND-NO-EOF-ERROR Command-Status #o0601 "No EOF Flag, for bitstuffing only.") ;;-------------------------------------------------------------------- ;; BUFFER DEFINITIONS ;;-------------------------------------------------------------------- (Def-NuField BUFFER-COUNT 0 "Number of data bytes in buffer; & flags") (Def-NuField BUFFER-LINK 2 "Link to next buffer in frame") ;;; Pointer to Buffer. (DefSubst BUFFER-ADDRESS (enc addr) (Address-Field (Enc-slot enc) (+ addr 4))) (Def-NuField BUFFER-SIZE-WORD 8 "Size of buffer in bytes.") ;Receive buffers only. (Def-NuBytef BUFFER-BYTE-COUNT Buffer-Count #o0016 "Number of data bytes in buffer.") (Def-NuBytef BUFFER-FULL Buffer-Count #o1601 "Buffer has been filled.") (Def-NuBytef BUFFER-END-OF-FRAME Buffer-Count #o1701 "This is the last buffer in the frame") (Def-NuBytef BUFFER-END-OF-FBL Buffer-Size-Word #o1701 "End of list marker") (Def-NuBytef BUFFER-SIZE Buffer-Size-Word #o0016 "Size of Buffer in bytes") ;;; Copies ARRAY (an art-16b) to the buffer described at BD. ;;; Returns NIL if ran out of room, else the address of the last buffer desc. used. ;;; Does not change the contents past the length of the array. ;;; *ASSUMES* that WORDS-TO-COPY is <= (Length ARRAY), rounded up to an even number. (Defun ART16b-TO-BUFFER (enc Descriptor array words-to-copy) (Do* ((buff-size (Convert-To-Words (ENC-Transmit-buffer-size enc))) (slot (Enc-Slot enc)) (Prev-BD Descriptor BD) ; the previous value of BD (BD Descriptor (buffer-link enc BD)) ; current buffer descriptor. (i 0 next) ; Where this buffer begins in ARRAY. (next (min words-to-copy buff-size) ; Next value of I. (min words-to-copy (+ next buff-size)))) ((>= i words-to-copy) Prev-BD) ; return last buffer desc. (If (= BD (*NULL-PTR*)) (Return nil)) ; Error, ran out of buffers. (XFER-WORDS-TO-NUBUS slot (buffer-address enc BD) array i next) (Setf (Buffer-Count enc BD) (* 2 (- next i)))) ;also clears EOL flag. ) ;;; Copies the contents of buffer described at DESCRIPTOR to ARRAY (an art-16b). ;;; Returns NIL if ran out of room, else the number of bytes copied. (Defun BUFFER-TO-ART16b (enc descriptor array) (Declare (Return-List num-bytes-in-array)) (Do ((array-length (array-length array)) (i 0 next) ;index into array next ;Next value of I. (BD descriptor (if (= 1 (Buffer-end-of-frame enc BD)) (*NULL-PTR*) ;End of buffer list.)) (Buffer-Link enc BD)))) ((= (*NULL-PTR*) BD) (* 2 i)) ;Return bytes copied. (Setq next (+ i (Convert-To-Words (Buffer-Byte-Count enc BD)))) (When (> (round-up-to-even next) array-length) (Return nil)) ;Error Return (Xfer-words-from-NuBus (ENC-Slot enc) (Buffer-Address enc BD) array i next)) ) ;;-------------------------------------------------------------------- ;; PRINT COMMAND & RECEIVE BLOCK STATUS ;;; Prints the status info common to all frame blocks. ;;; FRAME-ADDRESS is the address of the frame. (Defun PRINT-GENERIC-FRAME-STATUS (enc frame-address &optional (stream terminal-io)) (When (= 0 (Command-execution-status enc frame-address)) (terpri stream) (princ "Block is available" stream)) (Print-Flag-Doc 1 COMMAND-COMPLETE-FLAG frame-address) (Print-Flag-Doc 1 COMMAND-BUSY-FLAG frame-address) (Print-Flag-Doc 1 Command-Error-Flag frame-address)) (Defun PRINT-COMMAND-NAME (enc cmd-block &optional (stream terminal-io)) (princ (documentation (select (Command-block-cmd enc cmd-block) (((nop-command)) 'nop-command) (((address-setup)) 'address-setup) (((configure)) 'configure) (((multicast-setup)) 'multicast-setup) (((transmit)) 'transmit) (((tdr-command)) 'tdr-command) (((dump-status)) 'dump-status) (((diagnose-586)) 'diagnose-586))) stream) ) ;;; Prints the status info for a command block. (Defun PRINT-COMMAND-BLOCK-STATUS (enc cmd-block &optional (stream terminal-io)) (terpri stream) (princ "COMMAND-BLOCK STATUS: Address = " stream) (princ cmd-block stream) (terpri stream) (princ "Command: " stream) (Print-Command-Name enc cmd-block stream) (Print-generic-frame-status enc cmd-block stream) (Print-Flag-Doc 1 Command-Diagnose-Fail cmd-block) (Print-Flag-Doc 1 Command-Abort-Error cmd-block) (Print-Flag-Doc 1 Command-No-Carrier cmd-block) (Print-Flag-Doc 1 Command-No-Clear-send cmd-block) (Print-Flag-Doc 1 Command-DMA-Error cmd-block) (Print-Flag-Doc 1 Command-Xmit-Deferred cmd-block) (Print-Flag-Doc 1 Command-Retry-Error cmd-block) (When (> 0 (Command-Retry-Count enc cmd-block)) (terpri stream) (princ "Frame collisions: " stream) (princ (Command-Retry-Count enc cmd-block) stream))) ;;; Prints the status info for a receive frame block. (Defun PRINT-RECEIVE-FRAME-STATUS (enc frame &optional (stream terminal-io)) (terpri stream) (princ "RECEIVE-FRAME STATUS: Address = " stream) (princ frame stream) (Print-generic-frame-status enc frame stream) (Print-Flag-Doc 1 Command-CRC-Error frame) (Print-Flag-Doc 1 Command-Align-Error frame) (Print-Flag-Doc 1 Command-Buffer-Error frame) (Print-Flag-Doc 1 Command-DMA-Error frame) (Print-Flag-Doc 1 Command-Too-Short frame) (Print-Flag-Doc 1 Command-No-EOF-Error frame)) ;;; Prints the state of the receive Buffer at BUFF. (Defun PRINT-RECEIVE-BUFFER-STATUS (enc buff &optional (stream terminal-io)) (terpri stream) (princ "Receive Buffer Descriptor: " stream) (princ buff stream) (princ ", Buffer: " stream) (princ (Buffer-Address enc buff) stream) (princ ", Size (bytes) = " stream) (princ (Buffer-Size enc buff) stream) (terpri stream) (princ "Actual byte count = " stream) (princ (Buffer-Byte-Count enc buff) stream) (Print-Flag-Doc 1 Buffer-Full buff) (Print-Flag-DOc 1 Buffer-End-of-Frame buff)) ;;; Print the status of the Command-Block List on ENC. (Defun PRINT-CBL-STATUS (enc &optional (stream terminal-io) first-only-p) (terpri stream) (princ "Command Block List (CBL) = " stream) (princ (SCB-CBL-Offset enc (Enc-SCB enc)) stream) (Unless (= (*NULL-PTR*) (SCB-CBL-Offset enc (Enc-SCB enc))) (Do ((CB (SCB-CBL-Offset enc (Enc-SCB enc)) (Command-Link enc CB))) ((or first-only-p (= 1 (Command-End-Of-List enc CB))) (Print-Command-Block-Status enc CB stream)) (Print-Command-Block-Status enc CB stream)))) ;;; Print the status of the Received Frames on ENC. (Defun PRINT-RFA-STATUS (enc &optional (stream terminal-io) first-only-p) (terpri stream) (princ "Receive Frame Area (RFA) = " stream) (princ (SCB-Current-Receive-Frame enc) stream) (Do ((RFD (Command-link enc (Enc-last-free-rfd enc)) (Command-Link enc RFD))) ((or first-only-p (= 1 (Command-End-Of-List enc RFD))) (Print-Receive-Frame-Status enc RFD stream)) (Print-Receive-Frame-Status enc RFD stream))) ;;; Print the status of the Receive Buffers on ENC. (Defun PRINT-ALL-RECV-BUFFERS (enc &optional (stream terminal-io) first-only-p) (Do ((RBD (Buffer-link enc (Enc-Last-RBD enc)) (Buffer-Link enc RBD))) ((or first-only-p (= 1 (Buffer-End-of-FBL enc RBD))) (Print-Receive-Buffer-Status enc RBD stream)) (Print-Receive-Buffer-Status enc RBD stream))) ;;-------------------------------------------------------------------- ;; CHIP CONTROL BITS ;;-------------------------------------------------------------------- ;;; Assert CHANNEL ATTENTION to the NuBus Ethernet Controller for ENC. (DefSubst CHANNEL-ATTENTION (enc) (NuBus-Write (Enc-slot enc) (*CHANNEL-ATTENTION-ADDR*) 1)) (DefStruct (CONFIG-REGISTER (:type :fixnum) (:Conc-name NuBus-)) ((HW-Reset-p #o0001) ;Write Only, Set to 1 to reset board. (Master-Enable-p #o0101) ;NuBus Master Enbabled iff = 1. (Fault-LED-p #o0201) ;1 => LED on (ON at power up) (Loop-Back-p #o1001) ;1 => Loop back test (Error-while-posting-event-p #o2001) ;=1 => Bus error while posting event, Read only ) ) ;;; Turns the Reset line ON, Hardware turns it off automatically. (Defun RESET-HW (enc) (Setf (NuBus-HW-Reset-P (ENC-Config-Register enc)) 1) (Nubus-Write (ENC-Slot enc) (*Config-Register*) (ENC-Config-Register enc)) (Setf (NuBus-HW-Reset-P (ENC-Config-Register enc)) 0)) (DefSubst NUBUS-MASTER-ENABLE (enc) (Nubus-Master-Enable-p (Nubus-Read (ENC-Slot enc) (*Config-Register*)))) (DefSubst SET-MASTER-ENABLE (enc val) (Setf (NuBus-Master-Enable-p (ENC-Config-Register enc)) val) (Nubus-Write (ENC-Slot enc) (*Config-Register*) (ENC-Config-Register enc))) (Defsetf NUBUS-MASTER-ENABLE SET-MASTER-ENABLE) (DefSubst NUBUS-FAULT-LED (enc) (Nubus-Fault-LED-p (Nubus-Read (ENC-Slot enc) (*Config-Register*)))) (DefSubst SET-Fault-LED (enc val) (Setf (NuBus-Fault-LED-p (ENC-Config-Register enc)) val) (Nubus-Write (ENC-Slot enc) (*Config-Register*) (ENC-Config-Register enc))) (Defsetf NUBUS-Fault-LED SET-Fault-LED) (DefSubst NUBUS-LOOP-BACK (enc) (Nubus-LOOP-BACK-p (Nubus-Read (ENC-Slot enc) (*Config-Register*)))) (DefSubst SET-LOOP-BACK (enc val) (Setf (NuBus-LOOP-BACK-p (ENC-Config-Register enc)) val) (Nubus-Write (ENC-Slot enc) (*Config-Register*) (ENC-Config-Register enc))) (Defsetf NUBUS-LOOP-BACK SET-LOOP-BACK) (DefSubst NUBUS-Error-while-posting-event (enc) (Nubus-Error-while-posting-event-p (Nubus-Read (ENC-Slot enc) (*Config-Register*)))) ;; PRINT CONTROL SPACE STATUS ;;; Print the last written and the currently read state of ENC on STREAM. (Defun PRINT-CONTROL-SPACE-STATUS (enc &optional (stream terminal-io)) (Let ((CF (Enc-Config-Register enc))) (terpri stream) (terpri stream) (princ "CONTROL SPACE BITS Current Last-written" stream) (terpri stream) (princ " Master Enabled: " stream) (princ (On-off (Nubus-Master-Enable enc)) stream) (princ " " stream) (princ (On-off (Nubus-master-enable-p CF)) stream) (terpri stream) (princ " Fault LED: " stream) (princ (On-off (Nubus-Fault-led enc)) stream) (princ " " stream) (princ (On-off (Nubus-fault-led-p CF)) stream) (terpri stream) (princ " Loop Back: " stream) (princ (On-Off (NuBus-Loop-Back enc)) stream) (princ " " stream) (princ (On-off (Nubus-Loop-back-p CF)) stream) (terpri stream) (princ "Error Posting Event: " stream) (princ (On-Off (NuBus-error-while-posting-event enc)) stream) )) ;;; Display Status of the NuBus ETHERNET Controller. (Defun PRINT-STATUS (enc &optional (stream terminal-io)) (terpri stream) (terpri stream) (princ "Status of INTEL 82586 ETHERNET Controller on NuBUS" stream) (Print-SCP enc stream) (Print-ISCP-Status enc stream) (Print-SCB-Status enc stream) (Print-Control-Space-Status enc stream) (terpri stream)) ;;; From the file "Nu-Ether" ;;; ;;; Copyright (c) 1984 Texas Instruments Incorporated All Rights Reserved ;;; ;;;------------------------------------------------------------------------ ;;; DRIVER FOR NuBUS/INTEL 82586 ETHERNET CONTROLLER ;;; ;;;------------------------------------------------------------------------ ;;; ;;; This file Implements the Data Link Interface for the NuBus/Intel 82586 Ethernet controller. ;;; ;;; ADVERTISED FUNCTIONS ;;; ;;; INITIALIZE - Creates the buffer memory structures and calls RESET. ;;; RESET - Resets the control on the chip, board, & memory structures. ;;; TRANSMIT-FRAME - Transmits one ethernet frame. ;;; RECEIVE-FRAME - Returns the DEST, SRC, TYPE & DATA values from the next frame. ;;------------------------------------------------------------------------ ;; SYSTEM DEFINITION ;; ;;------------------------------------------------------------------------ (DefVar Controller :unbound) ;NuBus Ethernet controller data. (DefVar my-ethernet-address :unbound) (DefVar *Ether-Recv-Time* 0) (DefConst Controller-Memory 32. "Kbytes of buffer memory") ;;(Defconst Ethernet-Slot (+ #xFB %Sysint-Config-Ethernet)) (DefVar Ethernet-Slot #xF0 "Slot address of NuBus Ethernet controller") (Defun Nubus-Ethernet-Reset () (Declare (Special mini-my-ethernet-address)) ;; find slot of ethernet card to use. (Cond ((Neq si:processor-type-code si:explorer-type-code) (terpri) (princ "Slot number of Ethernet card:") (let ((answer (read))) (terpri) (princ "In slot ") (let ((*read-base* 16.)) (prin1 answer)) (setq Ethernet-Slot answer)))) ;; build controller structure. (Enable-NuBus-Ethernet) (Initialize controller) ;; random line for cold load. OK for non cold load. (Setq mini-my-ethernet-address (GET-ETHERNET-ADDRESS)) ) (Defun ENABLE-NuBUS-ETHERNET () (Unless (boundp 'CONTROLLER) (setq Controller (Make-Nubus-Ethernet-Controller Slot ethernet-slot Memory-Size (* 1024. Controller-Memory)))) ) ;;------------------------------------------------------------------------ ;; INITIALIZATION INTERFACE FOR NuBUS CONTROLLER ;; ;;------------------------------------------------------------------------ ;;; Completely (re)initialize the ENC and Reset the controller. (Defun INITIALIZE (enc) (Handling-NuBus-Condition enc (Create-Control-Structures enc 2) (Reset enc) (Setq NuBUS-Errors-in-a-Row 0)) ) ;;; Reset & initialize the 586 Ethernet Controller, ENC. ;;; Use Hardware or Software Reset mechaninsm, depending on SWQ-RESET-P. (Defun RESET (enc &optional sw-reset-p) (Reset-Chip enc sw-reset-p) (Initialize-Controller enc) ) ;;; Send a command block for command, COMMAND, to the controller ENC. ;;; BODY is the forms to fill the the command-block, ;;; CMD-BLK is the symbol bound to the command block inside BODY. (Defmacro SEND-COMMAND (enc command Cmd-blk &Body Body) ;not yet used `(With-Lock ((Enc-Request-Lock ,enc)) (Handling-NuBus-Condition ,enc (Let ((,cmd-blk (Alloc-CB ,enc t))) ,@body (Queue-Command-for-Execution ,enc ,command ,Cmd-Blk)))) ) ;;;------------------------------------------------------------------------ ;;; ETHERNET DATALINK INTERFACE FOR NuBUS CONTROLLER ;;; ;;;------------------------------------------------------------------------ (Defun NuBus-Transmit-Ethernet-16B-Array (from-ether-host to-ether-host array nwords e-type) from-ether-host ; not needed (Transmit-Frame controller to-ether-host e-type array (* 2 nwords))) ;;; Transmit the DATA-ARRAY (art-16b) to Ether address DEST. ;;; N-BYTES = number words to transmit ;;; TYPE = Ethernet Frame type. (Defun TRANSMIT-FRAME (enc dest type data-array n-bytes) (SEND-COMMAND enc (Transmit) CB (Do ((buff (ALLOC-BUFF enc data-array (Convert-To-Words n-bytes)) (ALLOC-BUFF enc data-array (Convert-To-Words n-bytes)))) ((Not (null buff)) ;; Set up Command Block (Setf (Command-Buffer-Ptr enc cb) buff) (Setf (Command-Destination-Addr enc cb) dest) (Setf (Command-Frame-Type enc cb) type)) (cond ((= (*NULL-PTR*) (SCB-CBL-Offset enc)) ; nothing to deallocate. (Free-CB enc CB) (ferror nil "Attempt to send a frame larger than total buffer space")) (T (Ack-Xmit-Interrupts enc t)))) ; Wait for last command to complete. )) ;;; Receive frame into array. (Defun NuBus-Receive-Ethernet-16B-Array (array) (Multiple-Value-Bind (ignore ignore type data) (Receive-Frame controller array) (Select type (#x408 t) (#x608 ;; address-resolution-type ;; record address; maybe send reply ;; defined back in "ether-mini" (receive-addr-pkt data) nil))) ) ;;; Nubus Ethernet Controller packet available predicate. (Defun NEC-Pkt-Available () (Not (Zerop (Command-Complete-Flag controller (SCB-Current-Receive-Frame controller)))) ) ;;; +++ shouldn't this be a cold-load only function? +++ (Deff Nubus-Mini-Pkt-Available #'NEC-Pkt-Available) ;;; Returns the DESTINATION, SOURCE, TYPE and DATA for the next valid frame. ;;; DATA is returned as an ART16b. (Defun RECEIVE-FRAME (enc into-array) (Declare (return-list Destination Source Type Data N-Bytes)) (Do-Named Receive ((start-time (%fixnum-microsecond-time))) (()) ; Loop until a good frame arrives. (Handling-NuBus-Condition enc (Let* ((RFD (SCB-Current-Receive-Frame enc)) (buff (Command-Buffer-Ptr enc rfd))) (If (Not (Zerop (Command-Complete-Flag enc RFD))) ;Frame is complete? (Unwind-Protect (If (= (Command-Status enc rfd) (*NORMAL-FINISH*)) ;Recv. completed OK? (Let* ((array into-array) ;; (Ethernet:ALLOCATE-BUFFER)) (nbytes (BUFFER-TO-ART16B enc buff array))) (If (Not (Null nbytes)) (Return-From Receive (Values (Command-Destination-Addr enc RFD) (Receive-Source-Addr enc RFD) (Receive-Frame-Type enc RFD) array nbytes)) (Comment "Should record here that frame was too big"))) ;; Error in frame, just clear it. (Incf Nubus-Receive-Frame-Errors) (Push (Command-Status enc rfd) Nubus-receive-frame-error-list)) ;; *ALWAYS* Free the Frame Desc. & buffers & restart the Recv. Unit. (FREE-RFD-AND-BUFFERS enc rfd buff) (Select (SCB-Receive-Unit-Status enc) (((Receive-Ready)) nil) (otherwise (Enable-Read enc))) ;; *** not in cold load *** (Incf *Ether-Recv-Time* (round (time-difference (%fixnum-microsecond-time) start-time) 1000.))) (Process-Wait "Await NuBus frame or enable" #'NUBUS-PROCESS-WAIT-FUNCTION enc) ;; Reset start time. (setq start-time (%fixnum-microsecond-time)) (Ack-Recv-Interrupts enc))))) ) ;;; Return when the Frame-Received-Interrupt is on. (Defun NuBUS-PROCESS-WAIT-FUNCTION (enc) (Handling-NuBus-Condition enc (And CHAOS:ENABLE (FRAME-RECV-INT-P enc)))) ;;------------------------------------------------------------------------ ;; NuBUS ETHERNET CONTROLLER STRUCTURES ;; INITIALIZATION ;;------------------------------------------------------------------------ ;;; Reset the 586 NuBus controller chip. Assumes valid control data on board. ;;; If SW-RESET-P is nil, uses the Control Register line, else uses the SCB. (Defun RESET-CHIP (enc &optional sw-reset-p) (Setf (SCB-Busy-Word enc (ENC-ISCP enc)) 1) (Setf (SCB-Command enc (Enc-SCB enc)) (*NULL-COMMAND*)) (If sw-reset-p (Setf (SCB-Reset enc (Enc-SCB enc)) 1) (Reset-HW enc)) (Channel-Attention enc) (Unless (Clear-Interrupts enc t 600.) (print "Ethernet Controller failed to RESET - Disabling Chaosnet") (*Throw 'Abort-Chaos nil)) ) ;;; Initialize the NuBus Board. Enable Interrupts if *INTERRUPT-DRIVEN-P* is non-NIL. (Defun INITIALIZE-CONTROLLER (enc) (Setf (Enc-Request-Lock enc) nil) (Setf (Enc-Write-Lock enc) nil) (Setf (Nubus-Fault-LED enc) 0) ;Turn off LED (Setf (NuBus-Master-Enable enc) (If *INTERRUPT-DRIVEN-P* 1 0)) ;; also need to set up the Event Address if Interrupts-p is T !!! (Setf (Nubus-Loop-Back enc) 0) ;; Eventually the ether address will be read from the Config ROM, but we don't have one. (Setup-my-address enc (Setq My-Ethernet-Address (Get-Ethernet-Address enc))) (Enable-Read enc)) ;;; Enable the NuBus Ether Controller described by ENC, to receive frames. (Defun ENABLE-READ (enc) (Let ((RFD (Find-1st-Free-RFD enc (ENC-Last-Free-RFD enc))) (buff (Find-1st-Free-RBD enc (ENC-Last-RBD enc)))) (When (and RFD buff) ;Turn Receiver on if there is a buffer & RFD (setf (SCB-RFA-Offset enc) RFD) (setf (Command-Buffer-ptr enc RFD) buff) (Issue-Command enc (Setf (SCB-Receive-Command enc) (START)))))) ;;------------------------------------------------------------------------ ;; NuBUS ETHERNET COMMANDS ;;------------------------------------------------------------------------ ;;; Setup the Ethernet ADDRESS for ENC to receive on. (Defun SETUP-MY-ADDRESS (enc address) (SEND-COMMAND enc (ADDRESS-SETUP) CB (Setf (Enc-Ether-Address (Enc-slot enc) (+ cb 6)) address)) (Ack-Xmit-Interrupts enc t) ) ;;; Magic ethernet base address + magic cold load chaos address. (Defun GET-ETHERNET-ADDRESS (&optional ignore) (+ #x080028010000 (if (and (boundp 'chaos:my-address) (numberp chaos:my-address)) chaos:my-address #o3407))) ;;; >> This implementation places EXACTLY ONE Command Block on the CBL at any one time. << ;;; There is no chaining of command blocks. ;;; The reason is that the controller is fast enough that it should be finished with the ;;; previous Command Block before we can get the new one built, much less queued. ;;; ;;; ** NOTE ** Make the command value be an arg to here. All callers set the command value. ;;; Queue the command, COMMAND, at CMD-BLOCK for execution by the controller. ;;; Sets END-OF-LIST & INTERRUPT to On. Assumes STATUS is already zeroed. (Defun QUEUE-COMMAND-FOR-EXECUTION (enc command cmd-block) (Setf (Command-Word enc cmd-block) command) (Setf (Command-End-of-List enc cmd-block) 1) (Setf (Command-link enc cmd-block) (*NULL-PTR*)) (Setf (Command-Interrupt-Flag enc cmd-block) 1) (Unless (= (*NULL-PTR*) (SCB-CBL-Offset enc)) (Ack-Xmit-Interrupts enc t)) ;Clear the Transmitter if not already done. (Issue-Command enc ;Ensures ACKing doesn't issue Channel-Attention. (Setf (SCB-CBL-Offset enc) cmd-block) (Setf (SCB-Control-Command enc) (START)))) ;;------------------------------------------------------------------------ ;; NuBus ETHERNET INTERRUPT HANDLING ;;------------------------------------------------------------------------ ;; Transmit Interrupts are handled by the transmitting processes. ;; If this function were to be in an interrupt process (either interrupt or polled), ;; the transmitting functions which now call this would have to check for SCB-CBL-Offset ;; to go *NULL-PTR*. ;;; Acks any Command interrupts that occur and frees any transmit frame. (Defun ACK-XMIT-INTERRUPTS (enc &optional wait-for-interrupt-p) ;; ASSERT - Since only One command is queued at a time, If a CX occurs, so must a CNR. ;; And the one & only command MUST be complete. ;; ASSERT - If there is a Complete CB on the CBL, there MUST be a CX pending. (If (And (= 0 (SCB-CX-Flag enc)) (= 0 (SCB-CNR-Flag enc)) wait-for-interrupt-p) (When (Null (Process-Wait-with-timeout "ENC Xmit interrupt" 60. #'(Lambda (enc) (Or (= 1 (SCB-CX-Flag enc)) (= 1 (SCB-CNR-Flag enc)))) enc)) (nubus-ethernet-reset)) ;; Clear the interrupts (Issue-Command enc (Setf (SCB-Ack-CX enc) (SCB-CX-Flag enc)) (Setf (SCB-Ack-CNR enc) (SCB-CNR-Flag enc)) (When (= 1 (SCB-Ack-CX enc)) ; If Command Complete interrupt, (Let ((CB (SCB-CBL-Offset enc))) (When (not (= CB (*NULL-PTR*))) (When (zerop (Command-complete-Flag enc CB)) ;Sanity check on 586. (print "Ethernet board did not mark last command as complete.") (print "Freeing the COMMAND-BLOCK anyway.")) (Free-CB enc CB) ;Free command block (Setf (SCB-CBL-Offset enc) (*NULL-PTR*)))))) ) ) ;;; Acks any Receive interrupts that occur. (Defun ACK-RECV-INTERRUPTS (enc &optional wait-for-interrupt-p) (If wait-for-interrupt-p (When (null (Process-Wait "ENC Recv interrupt" #'(Lambda (enc) (or (= 1 (SCB-FR-Flag enc)) (= 1 (SCB-RNR-Flag enc)))) enc)) (nubus-ethernet-reset)) (Issue-Command enc (Setf (SCB-Ack-FR enc) (SCB-FR-Flag enc)) (Setf (SCB-Ack-RNR enc) (SCB-RNR-Flag enc)))) ) ;;; Acks any interrupts that occur. Returns T if OK, NIL if timed out. (Defun CLEAR-INTERRUPTS (enc &optional wait-for-interrupt-p (time-out 600.)) (When (Or (Not wait-for-interrupt-p) (Process-Wait-With-Timeout "ENC interrupt" time-out #'(lambda (enc) (not (zerop (SCB-Int-Flags enc (Enc-SCB enc))))) enc)) ;Returns nil if timed-out, T otherwise. (Issue-Command enc (Setf (SCB-Ack-Int enc (Enc-SCB enc)) (SCB-Int-Flags enc (Enc-SCB enc)))) T)) ;;------------------------------------------------------------------------ ;; INITIALIZE NuBUS ETHERNET DATA STRUCTURES ;;; Initialize all the NuBus Ethernet data structures. (Defun CREATE-CONTROL-STRUCTURES (enc nxmit-frames) ;; Eventually this needs to have options added to the arg list to vary the constants below. (Init-ISCP enc 0 ;Make ISCP at location 0000 ;; Make SCB following the ISCP (Create-SCB enc ISCP-Size nxmit-frames)) ;; Initialize the SCP (Setf (ISCP-Address enc) 0) ;Intermediate. Sys Control Ptr is at loc zero. (Set-SCP-Sysbus-Width enc 16) ;Chip's bus is word mode. ) ;; INITIALIZE THE SYSTEM CONTROL BLOCK ;;; Initialize the SCB, & Buffers in NuBus Memory for a TI NuBus Ethernet Controller. ;;; ADDR = address of System Control Block in the slot. ;;; NXMIT-FRAMES = number of transmit frames to make. ;;; Rest of memory will be used for receive buffers. (Defun CREATE-SCB (enc addr nxmit-frames) ;; The buffer for the 586 dump immediately follows the SCB (Let* ((next-addr (+ addr SCB-Size Dump-Area-Size)) ;Start address of buffers. (buffer-size ;Number bytes avail for buffers. (- (ENC-Memory-size enc) next-addr SCP-Size)) (xmit-area-bytes ;Number bytes in transmit area (* Nxmit-Frames (ENC-Transmit-Frame-Size enc))) (recv-area-bytes ;Number bytes in receive area (- Buffer-Size Xmit-Area-Bytes)) (Nrecv-Frames ;Number of receive frames to use. (floor Recv-Area-Bytes (ENC-Receive-Frame-Size enc)))) (Init-SCB enc addr (*NULL-PTR*) (*NULL-PTR*)) (Setq next-addr (Create-CBL enc next-addr Nxmit-Frames)) ; Pushes the CB's on Free-List. (Setq next-addr (Create-RFA enc next-addr Nrecv-Frames)) (Setq next-addr (Create-Xmit-Buffers enc next-addr (* NXmit-frames (ENC-Transmit-Buffers-per-frame enc)) (ENC-Transmit-Buffer-Size enc))) ;Holds in ENC (Setq next-addr (Create-Receive-Buffers enc next-addr (* NRecv-frames (ENC-Receive-Buffers-per-frame enc)) (ENC-Receive-Buffer-Size enc))) addr)) ;;------------------------------------------------------------------------ ;; COMMAND BLOCK MANAGEMENT ;;------------------------------------------------------------------------ ;;; Print the free command blocks from the Free-CBL. (Defun Print-Free-CB (enc &optional (stream terminal-io)) (Do ((addr (scb-free-cbl enc) (command-link enc addr))) ((= (*null-ptr*) addr)) ;; Print CB (terpri stream) (princ "Free command block " stream) (princ addr stream) (terpri stream) (princ "Status " stream) (princ (Command-Status enc addr)) (princ ", command word " stream) (princ (Command-Word enc addr) stream) (princ ", link " stream) (princ (Command-Link enc addr) stream) (princ ", buffer " stream) (princ (Command-Buffer-Ptr enc addr))) ) ;;; Initialize the Command Block at ADDR, & push it on the Free-CBL list. ;;; Does not initialize the parameter fields. (DefSubst INIT-CB (enc addr) (Setf (Command-Status enc addr) (*NULL-STATUS*)) (Setf (Command-Word enc addr) (*NULL-COMMAND*)) (Setf (Command-Link enc addr) (SCB-Free-CBL enc)) (Setf (Command-Buffer-Ptr enc addr) (*NULL-PTR*)) (Setf (SCB-Free-CBL enc) addr) addr) ;;; Create COUNT Command-Blocks, starting at START-ADDR. ;;; Returns the next available address in the buffer emeory area. (Defun CREATE-CBL (enc start-addr count) (Do ((size Command-Size) (i 0 (1+ i)) ; loop counter (addr start-addr (+ addr size))) ; address of command block ((= i count) addr) ; return next available address. (Init-CB enc addr))) ;; Free Command Blocks are handled as a stack. ;; CB's are POP'ed to get a free one, and PUSH'ed back on to be returned. ;;; Alloc a free Command block. If HANG-P is not-Nil, hangs til one avail. ;;; Returns the Command Block ptr, or *NULL-PTR* if none. (Defun ALLOC-CB (enc &optional hang-p) (Cond ((not (= (SCB-Free-CBL enc) (*NULL-PTR*))) ;From free list (Without-Interrupts (Prog1 (SCB-Free-CBL enc) (Setf (SCB-Free-CBL enc) (Command-Link enc (SCB-Free-CBL enc)))))) (hang-p ;wait for current CB to complete (Ack-Xmit-Interrupts enc t) (Without-Interrupts (Prog1 (SCB-Free-CBL enc) (Setf (SCB-Free-CBL enc) (Command-Link enc (SCB-Free-CBL enc)))))) (t (*NULL-PTR*))) ) ;;; Frees the command Block CB, and any associated buffers. (Defun FREE-CB (enc CB) (When (= (TRANSMIT) (Command-Block-Cmd enc CB)) (Free-Transmit-Buffers enc (Command-Buffer-Ptr enc CB))) (Init-CB enc CB)) ;;------------------------------------------------------------------------ ;; TRANSMIT BUFFER MANAGEMENT ;;------------------------------------------------------------------------ ;; Buffers are allocated immediatelly following their Buffer Descriptor. ;; Buffers-sizes must be a multiple of four bytes long. ;;; Initialize a Transmit Buffer at ADDR for for controller ENC. ;;; SIZE = number of bytes in buffer, assumes buffer follows TBD. ;;; LINK = Next Buffer in frame. (DefSubst INIT-TBD (enc addr size) (Setf (Buffer-Count enc addr) size) ;also clears End-of-Frame. ) ;;; Create COUNT buffers & descriptors of SIZE bytes, starting at START-ADDR. ;; Returns the address of the first buffer in the list. (Defun CREATE-XMIT-BUFFERS (enc start-addr count size) ;; Allocates each buffer immediately after its descriptor. (Setq size (Round-up-to-Quad size)) (Setf (ENC-Transmit-buffer-size enc) size) (Do ((i 0 (1+ i)) ; loop counter (addr start-addr (+ addr size TBD-size)) ; address of buffer desc. (last-addr (*NULL-PTR*) addr)) ; address of last buffer ((= i count) (Setf (SCB-Free-TBD enc) last-addr) ; Anchor the list. addr) ; Return avail address. (Setf (Buffer-Link enc addr) last-addr) (Setf (Buffer-Address enc addr) (+ addr TBD-Size)) (Init-TBD enc addr size)) ) ;; Free Transmit buffers are handled as a stack. ;; TBD's are POP'ed to get a free one, and PUSH'ed back on to be returned. ;;; Returns the address of the allocated buffer after copying ARRAY into it. ;;; Returns NIL if not enough space. (Defun ALLOC-BUFF (enc array data-length) (Without-interrupts (Let ((Buff (SCB-Free-TBD enc))) ;Buffer pointer (If (= Buff (*NULL-PTR*)) nil ;Buffer not available (Let ((last-buff (ART16B-TO-BUFFER enc buff array data-length))) (If (null last-buff) nil (setf (Buffer-end-of-frame enc last-buff) 1) ;mark EOL (Setf (SCB-Free-TBD enc) (buffer-link enc last-buff)) buff))))) ) ;;; Frees all buffers in the list rooted at the buffer START-BUFF. (Defun FREE-TRANSMIT-BUFFERS (enc start-buff) (When (not (= start-buff (*NULL-PTR*))) (Do ((buff start-buff (Buffer-Link enc buff)) (last-buff nil buff) (size (ENC-Transmit-buffer-size enc)) (EOF 0)) ((or (= EOF 1) (= buff (*NULL-PTR*))) ;;Put buffers back in free list (Setf (Buffer-Link enc last-buff) (SCB-Free-TBD enc)) (Setf (SCB-Free-TBD enc) start-buff)) (Setq EOF (Buffer-end-of-frame enc buff)) ;remember EOF state (Init-TBD enc buff size))) ;free buffer ) ;;------------------------------------------------------------------------ ;; RECEIVE BUFFER MANAGEMENT ;;------------------------------------------------------------------------ ;; Buffers are allocated immediatelly following their Buffer Descriptor. ;; Buffers-sizes must be a multiple of four bytes long. ;;; Initialize the state of the RBD at ADDR. (DefSubst INIT-RBD (enc addr) (Setf (Buffer-Count enc addr) 0) ;also clears EOF & F flags. (Setf (Buffer-End-Of-FBL enc addr) 0)) ;;; Create COUNT buffers & descriptors of SIZE bytes, starting at START-ADDR. (Defun CREATE-RECEIVE-BUFFERS (enc start-addr count size) (Declare (return-list next-avail-addr)) ;; allocates each buffer immediately after its descriptor. (Setq size (Round-up-to-Quad size)) (Setf (Enc-Last-RBD enc) start-addr) ; Init this value (Do ((i 0 (1+ i)) ; loop counter (addr start-addr (+ addr size RBD-size)) ; address of buffer desc. (last-addr (*NULL-PTR*) addr)) ; address of last buffer ((= i count) (Setf (Buffer-Link enc start-addr) last-addr) ;close the list (Setf (Buffer-End-of-FBL enc start-addr) 1) ;make this one the tail (Setf (Enc-Last-RBD enc) start-addr) ;anchor the list addr) ; Return last buffer made. (Setf (Buffer-Link enc addr) last-addr) (Setf (Buffer-Address enc addr) (+ addr RBD-Size)) (Setf (Buffer-Size enc addr) size) ; also clears the End of FBL flag. (Init-RBD enc addr)) ) ;;; Release all buffers starting at FIRST-BUFF for reuse by the controller. ;;; FIRST-BUFF *must* not be NULL. (DefSubst FREE-RECEIVE-BUFFERS (enc first-buff) (Do ((buff first-buff (Buffer-Link enc buff)) ;buffer to release (last-buff nil buff) ;buffer just released (EOF 0)) ;End of frame? ((= 1 EOF) (Setf (Buffer-End-of-FBL enc last-buff) 1) ;new end of FBL (Setf (Buffer-End-of-FBL enc (Enc-Last-RBD enc)) 0) (Setf (Enc-Last-RBD enc) last-buff)) (setq EOF (Buffer-End-of-Frame enc buff)) ;Yes, I know this is an ugly hack (Init-RBD enc buff)) ) ;;; Returns ptr to 1st Free Buffer Desc, NIL if none. Starts at START-RBD. (Defun FIND-1ST-FREE-RBD (enc start-rbd) (Do ((rbd (Buffer-Link enc start-rbd) (Buffer-Link enc rbd))) ((Or (= rbd start-rbd) ;kick out on last RBD (= (Buffer-Count enc rbd) 0)) ;found an unused Buffer. (When (= (Buffer-Count enc rbd) 0) rbd))) ) ;;------------------------------------------------------------------------ ;; RECEIVE FRAME MANAGEMENT ;;------------------------------------------------------------------------ ;;; Initialize the Receive Frame Descriptor at RFD for controller ENC and ;;; Update the List of RFD's and the list pointers. Returns the address of RFD. ;;; Does NOT change the LINK, ADDRESS, or TYPE fields. (DefSubst INIT-RFD (enc RFD) (Setf (Command-Status enc RFD) (*NULL-STATUS*)) ;Enable reuse of this block. (Setf (Command-Word enc RFD) (*NULL-CMD-EOL*)) ;Make this new end of list. (Setf (Command-Buffer-Ptr enc RFD) (*NULL-PTR*)) ;Let go of any buffers ;; Reset the list pointers (Setf (Command-End-of-List enc (Enc-Last-free-RFD enc)) 0) (Setf (Enc-Last-Free-RFD enc) RFD) RFD) ;;; Create COUNT Receive Frame Descriptors, starting at START-ADDR. ;;; Returns the next available address in the buffer memory area. (Defun CREATE-RFA (enc start-addr count &aux size) (Setq size Receive-Block-Size) (Setf (Enc-Last-Free-RFD enc) start-addr) ; Init this value. (Do ((i 0 (1+ i)) ; loop counter (addr start-addr (+ addr size)) ; address of command block (last-addr (*NULL-PTR*) addr)) ; address of last block ((= i count) (Setf (Command-Link enc start-addr) last-addr) ;close the list (Init-RFD enc start-addr) ; Make '1st' RFD be the tail of the list. addr) (Init-RFD enc addr) (Setf (Command-link enc addr) last-addr)) ) ;;; Release the RFD and any buffers it points to. (Defun FREE-RFD-AND-BUFFERS (enc rfd buff) (Unless (= buff (*NULL-PTR*)) (Free-Receive-Buffers enc buff)) (Init-RFD enc rfd)) (Defun FIND-1ST-FREE-RFD (enc start-rfd) ;; This may only be called AFTER at least one RFD has been released. (Do ((rfd (Command-Link enc start-rfd) (Command-Link enc rfd))) ((or (= rfd start-rfd) ;kick out on last RFD (= (Command-Status enc rfd) (*NULL-STATUS*)));found a free RFD (When (= (Command-Status enc rfd) (*NULL-STATUS*)) rfd))) )