; Spruce Ethernet "Ear" functions .titl SpruceEarMl ;This module contains two accessible functions providing a very specific, ;minimal, Ethernet "ear" for Spruce. ; ; hostId = ResetEther(mask) ; ;simply resets any current Ethernet activities and enables Ethernet interrupts to use mask ; (disabled if mask is 0, of course). ;It clears EPLoc and sets EHLoc to the program's host Alto's ID, which it also returns. ; ; PollEther() ; ;must be called frequently from other parts of the system. When first called, it turns ;on the receiver to allow receipt of one packet (good or bad). When subsequently ;called, it examines any received packets, records spooling requests, and responds to ;status requests. On receipt of a status request, it starts the transmitter to send a ;pre-packaged packet to the immediate sender of the request, placing the request's ;source port in the reply's destination port. If a packet is in transit, it simply returns. ;In all other cases, it resets the interface then restarts the receiver. If a spool request is ;received, PollEther sets the static knockResult to true. The function will also set knockResult to other ;non-zero values if the ESC key is down during the call. This allows manual suspension of printing. ; ;Specifics: ; status request: Pup, addressed to socket #21, Pup type #200 ; spooling request: Pup, addressed to socket #20, Pup type #30 ; inPacket: external that must point to a 14 word vector ; outPacket: external that must point to a lenOut word vector, whose fleece ; is white... no, which contains an Ether-encapsulated status reply Pup ; (from socket #21, Pup type #201) ; lenOut: external that must contain the length of outPacket ; knockResult: external, cleared with interrupts off by non-interrupt code, set here ; when somebody knocks ; tickCount: if non-zero, receiver will not be restarted after processing interrupt ; PollEther() may be the target of an interrupt channel. After processing each interrupt, it will ; either start the receiver (if tickCount le 0) or the transmitter. Or it may be called directly ; by non-interrupt code ; to determine recent Ether activity. Interleaving both methods is not suggested. ; Ticker() ; Responsible for recording the presence of the "suspend printing" key (currently ESC) ; at 60 hz. intervals; when EarOn(2) has been called, responsible for provoking the Ether Ear ; to restart the receiver (see SpruceUtilsRes), by calling PollEther with tickCount le 0 ; (See SpruceMeasure) if monitoring Dover engine control, record events via TickMeasure on ; every tick. EPLoc = 600 EBLoc = 601 EELoc = 602 ELLoc = 603 EICLoc = 604 EIPLoc = 605 EOCLoc = 606 EOPLoc = 607 EHLoc = 610 .bext PollEther, ResetEther, Ticker .bext inPacket, outPacket, lenOut, knockResult, tickCount, tickCount0 .bext measuring, TickMeasure .srel PollEther: .poll ResetEther: .reset Ticker: .ticker .nrel .ePLoc: EPLoc .eBLoc: EBLoc .eELoc: EELoc .eLLoc: ELLoc .eICLoc: EICLoc .eIPLoc: EIPLoc .eOCLoc: EOCLoc .eOPLoc: EOPLoc .eHLoc: EHLoc .inPacket: inPacket .outPacket: outPacket .lenOut: lenOut .reset: inc 3,3 sta 3,save3 subc 1,1 sta 1,@.eBLoc ;inhibit interrupts while resetting interface mov 0,1 ;save mask lda 0,c3 sio ;reset ether sta 1,@.eBLoc ;enable channel corresponding to mask lda 1,mrh and 1,0 ;rh(startio 3 result) is host sta 0,@.eHLoc subc 1,1 sta 1,@.ePLoc lda 3,@.inPacket sta 1,0,3 jmp @save3 .read: sta 3,save3 lda 0,d14 ;read no more than 2+10+1 (+1?) words sta 0,@.eICLoc lda 3,@.inPacket sta 3,@.eIPLoc subc 0,0 sta 0,@.ePLoc ;clear post location sta 0,0,3 ;zero 1st packet word, as in-progress flag lda 0,c2 sio ;turn on input interface jmp @save3 .write: mknil 0,0 sta 3,save3 lda 3,@.inPacket sta 0,0,3 subc 0,0 sta 0,@.ePLoc sta 0,@.eLLoc lda 0,@.lenOut sta 0,@.eOCLoc lda 0,@.outPacket sta 0,@.eOPLoc mkone 0,0 sio ;write a packet jmp @save3 ; bring into range .ticking: tickCount .tickCount0: tickCount0 .knock: knockResult mrh: m377: 377 save3: 0 c3: 3 c2: 2 c1000: 1000 ; end of range group .poll: inc 3,3 sta 3,1,2 ; will accept input done w/ good status, or input overrun w/ any status lda 0,@.ePLoc lda 1,mlh ands 0,1 ;firmware status lda 3,c2 se 3,1 ;input overrun? jmp ckdone ;no, check all done mknil 0,0 ;overrun flag jmp posted ckdone: snz 0,0 ;has anything been posted? jmp noPost ; no, check input in progress lda 1,m377 sub 1,0,szr ;input done and status ok? jmp restart ; no, forget it posted: sta 0,overrun lda 3,@.inPacket lda 0,1,3 ; packet type lda 1,c1000 se 0,1 ; a pup? jmp restart ; no lda 0,7,3 ; dest socket = 20 or 21? sz 0,0 jmp restart ; no lda 0,10,3 lda 1,c20 se 0,1 ; dest socket = 20? jmp ck21 ; no, check for status request (socket 21) lda 0,3,3 ; pup type = 30? lda 1,mrh and 1,0 lda 1,c30 mknil 3,3 ; resultis true sne 0,1 sta 3,@.knock ;main result: someone knocked jmp restart ck21: inc 1,1 ; (c21) isz overrun ; (input overflow test) se 0,1 ; (dest socket = 21 test) jmp restart ; input overflowed, or dest socket ne 21 lda 0,3,3 ; pup type = 200? lda 1,mrh ; (already loaded) and 1,0 lda 1,c200 se 0,1 jmp restart ; no sta 2,save2 lda 2,@.outPacket lda 0,4,3 ; id of out = id of in sta 0,4,2 lda 0,5,3 sta 0,5,2 lda 0,11,3 ; dest sock of out = source sock of in sta 0,6,2 lda 0,12,3 sta 0,7,2 lda 0,13,3 sta 0,10,2 lda 0,0,3 ; this host,, directly connected host lda 1,mrh ; reject if sender was anonymous and# 1,0,snr jmp load2 movs 0,0 ; directly connected host,, this host and# 1,0,snr ; reject if request was broadcast jmp load2 sta 0,0,2 ; output ether encapsulation jsr .write load2: lda 2,save2 jmp ret ; resultis false noPost: lda 3,@.inPacket lda 0,0,3 sz 0,0 ;input in progress? jmp ret ;yes, just go away ; start or restart receiver unless inhibited by tickCount restart: lda 0,@.ticking negl# 0,0,snc ;sgz -- don't restart if tickCount positive jsr .read ;Read a packet ret: jmp @1,2 c200: 200 c20: 20 d14: 16 c30: 30 mlh: 177400 save2: 0 tsave3: 0 overrun: 0 mb1: 40000 ; ESC is bit 1 kbadr2: 177036 ; address of kbadr+2 .measuring: measuring .TickMeasure: TickMeasure .ticker: sta 3,tsave3 lda 0,@kbadr2 ;if ESC down, record as a "knock" -- should suspend lda 1,mb1 ;mask for bit 1 and# 0,1,snr ;key down == bit 0 dsz @.knock ;will become other than -1 quickly, distinguished from ether kind mov# 0,0 ; in case? lda 0,@.measuring mov# 0,0,snr jmp tickTest jsrii .TickMeasure ;take measurements 0 tickTest: dsz @.ticking ;time to query ether? jmp tQuit ;no, quit jsr .poll ;query, and restart receiver 0 lda 3,@.tickCount0 sta 3,@.ticking tQuit: lda 3,tsave3 ;; sub 0,0 ; reinstate if any question about progress thru interrupt code ;; sta 0,tsave3 jmp 1,3 ;; DCS, September 2, 1977 4:22 PM, created ;; September 6, 1977 9:48 PM, status request -> reply, data packet 0 -> true return ;; May 11, 1978 6:24 PM, modify to allow running at interrupt level (result to knockResult) ;; May 12, 1978 11:20 AM, add tickCount control of ear duty cycle ;; July 23, 1978 3:34 PM, repair bug: status request responses broadcast anonymously! ;; August 28, 1978 4:20 PM, ESC key down during poll yields positive knock response ;; August 28, 1978 8:10 PM, put Ticker in ASM, for .3% print efficiency gain during scan/show ;; September 4, 1978 5:23 PM, ESC key causes non- -1 result -- more urgent ;; March 12, 1979 10:16 PM, calls TickMeasure if measuring, see SpruceMeasure, by Swinehart ;; .end