* EtherLoad.mc * Edit by CPT July 10, 1980 rename CSLoc to avoid conflict with GlobalDefs * Edit by Jim Frandeen March 2, 1980 11:29 AM Delete Includes for Integration Procedure * Edit by HGM on February 4, 1980 11:59 PM TITLE[EtherBoot]; * Tasks Set[OutTask, 2]; Set[InTask, 3]; Set[OutNotifyTask, LSHIFT[OutTask,14]]; Set[InNotifyTask, LSHIFT[InTask,14]]; * Locations Set[EtherPage, 4]; Set[EmStartLoc, OR[LSHIFT[EtherPage,10], 102]]; Set[OutStartLoc, OR[LSHIFT[EtherPage,10], 130]]; Set[InStartLoc, OR[LSHIFT[EtherPage,10], 110]]; * I/O Address Registers for use by the IO Task Set[ReadDeviceID, 0]; Set[ReadHostNumber, 1]; Set[ReadStatus, 2]; Set[ReadData, 3]; Set[WriteState, 0]; Set[WriteData, 1]; * for access from Emulator Task MC[ReadInputDeviceID, OR[LSHIFT[InTask,4],ReadDeviceID]]; MC[ReadOutputDeviceID, OR[LSHIFT[OutTask,4],ReadDeviceID]]; MC[ReadInputHostNumber, OR[LSHIFT[InTask,4],ReadHostNumber]]; MC[WriteInputState, OR[LSHIFT[InTask,4],WriteState]]; MC[WriteOutputState, OR[LSHIFT[OutTask,4],WriteState]]; * Status masks MC[CollisionMask, 10000]; MC[OutputStatusMask, 53000]; MC[InputStatusMask, 124400]; * New Ethernet device IDs (This won't work with old boards - fix them) MC[EtherInputDeviceID, 3400]; MC[EtherOutputDeviceID, 3000]; * State Register command words MC[PurgeThisPacket, 260]; * Enable Input, PurgeMode MC[SendThisPacket, 107]; * Enable Output, OutputEOP, JamEnable MC[EnableOutput, 103]; * Enable Output, JamEnable MC[DisableOutput, 100]; * Constants for things in a packet MC[EtherPup, 1000]; * in second word of packet on an Ethernet MC[OurVersionNumber, 1]; * Used in PupID and socket# MC[MiscServSocket, 4]; * Misc Services socket MC[D0MicrocodeRequest, 264]; * pupType MC[D0MicrocodeAnswer, 265]; MC[PupOverhead, 26]; * pupLength of empty Pup % Encapsulation is: 0 dest,,source (dest is 0 for broadcast) 1 packet type (1000 for pup) Pup body is: 2 length (bytes) (26B is min) 3 ctl,,pupType (ctl is normally 0) 4 first word of pupID 5 second word of pupID 6 dest net,,dest host (0 for broadcast) 7 first word of dest socket 8 second word of dest socket 9 source net,,source host 10 first word of source socket 11 second word of source socket ... body goes here 12 pup checksum (-1 to ignore) % % Macros for generating Notify values Sample usage is: R _ RHNV[task#,loc]; R _ (R) OR (LHNV[task#,loc]); APC&APCTask _ R; RETURN; % MACRO[RHNV,AND[0377,#2]C]; MACRO[LHNV,OR[LSHIFT[#1,14],AND[007400,#2]]C]; * Registers: SETTASK[0]; RV[R0, 0]; RV[Temp, 2]; RV[Count, 3]; RV[DeviceAddress, 4]; RV[ShiftCount, 5]; SETTASK[OutTask]; RV[OutTemp, 41]; RV[OutMask, 42]; RV[BootFileNumber, 43]; SETTASK[InTask]; RV[InTemp, 61]; RV[BytesLeft, 62]; RV[Junk, 63]; RV[Source, 64]; RV[SourceTemp, 65]; RV[Packet, 66]; RV[Checksum, 67]; RV[Word, 70]; RV[xxxCSLoc, 71]; *In globaldefs, CSLoc is an address RV[Base, 72]; RV[BaseHi, 73]; * Task 3 registers referenced by other tasks RV[TimerReg, 76]; RV[Host, 77]; ONPAGE[EtherPage]; SETTASK[0]; * Jump here in Task 0 with error code already in MP. * MP will be bumped once if we can't load things. * BootFile number is in T EtherLoad: BootFileNumber _ T, AT [EmStartLoc]; * I'm not sure if this is really needed * set all device address to zero so stray wakeups won't kill us T _ DeviceAddress _ (ZERO)-1; ShiftCount _ 400C, CALL[Shift]; MC[EtherAddresses, AND[NOT[OR[LSHIFT[OutTask,4],InTask]],377]]; * Load CAddr Register of the first 2 devices T _ DeviceAddress _ EtherAddresses; ShiftCount _ 10C, CALL[Shift]; * Find the EtherNet board Count _ 20C; NextBoard: T _ ReadInputDeviceID; Input[Temp]; LU _ (Temp) XOR (EtherInputDeviceID); GOTO[StartInput,ALU=0], T _ DeviceAddress _ (ZERO)-1; ShiftCount _ 4C, CALL[Shift]; GOTO[NextBoard,R>=0], Count _ (Count) - 1; NoEthernet: GOTO[EmTrouble]; StartInput: Count _ 15C; * This works out to 15 decimal T _ ReadInputHostNumber; Input[Host]; SendAgain: R0 _ AND[0377, InStartLoc]C; R0 _ (R0) OR (OR[InNotifyTask,AND[007400, InStartLoc]]C); APC&APCTask _ R0, CALL[Ret]; * Poke sending process to send the request again R0 _ AND[0377, OutStartLoc]C; R0 _ (R0) OR (OR[OutNotifyTask,AND[007400, OutStartLoc]]C); APC&APCTask _ R0, CALL[Ret]; * This double loop should take about 10 seconds * I used trial and error to get it right TimerReg _ 1000C; More: R0 _ 60000C; * I can't quite get rid of the extra instructions in this tangle NOP; CALL[Ret]; R0 _ (R0)-1, GOTO[.-2,R>=0]; TimerReg _ (TimerReg)-1, GOTO[More,R>=0]; Count _ (Count)-1, GOTO[SendAgain,R>=0]; * Timeout EmTrouble: IncMPanel; GOTO[.]; * Shift the device address registers another step * Args in T, DeviceAddress, and Count Shift: ShiftCount _ (ShiftCount) - 1, GENSRCLOCK; GOTO [.-1,ALU#0], T _ DeviceAddress _ RCY[DeviceAddress, 1]; RETURN; SETTASK[OutTask]; * The Ethernet encapsulation is 2 words and a short Pup is 11 words * That fits into the buffer so there is no need to TASK OutStart: OutMask _ 0C, AT [OutStartLoc]; OutAgain: OutTemp _ DisableOutput; OUTPUT[OutTemp, WriteState]; OutTemp _ EnableOutput, CALL[OutState]; T _ RHMASK[Host]; OutTemp _ T, CALL[OutData]; OutTemp _ EtherPup, CALL[OutData]; OutTemp _ PupOverhead, CALL[OutData]; OutTemp _ D0MicrocodeRequest, CALL[OutData]; OutTemp _ OurVersionNumber, CALL[OutData]; * PupID OUTPUT[BootFileNumber, WriteData]; * PupID2 OutTemp _ 0C, CALL[OutTwice]; * dest PupAddress OutTemp _ MiscServSocket, CALL[OutData]; OUTPUT[Host, WriteData]; * our PupAddress OutTemp _ OurVersionNumber, CALL[OutTwice]; OutTemp _ (ZERO)-1, CALL[OutData]; * checksum OutTemp _ SendThisPacket, CALL[OutState]; INPUT[OutTemp, ReadStatus]; LU _ (OutTemp) AND (CollisionMask); GOTO[OutColl,ALU#0]; OutDone: OutTemp _ DisableOutput, GOTO[OutState]; * Rats, got a collision OutColl: T _ OutMask _ (LSH[OutMask,1])+1, SKIP[R>=0]; GOTO[OutDone]; * Too many collisions, give up NOP; * ARG NOP; OutTemp _ T, CALL[Dally]; T _ (OutTemp)-1, GOTO[.-2,R<0]; GOTO[OutAgain]; OutTwice: OUTPUT [OutTemp, WriteData]; OutData: OUTPUT [OutTemp, WriteData], GOTO[Dally]; OutState: OUTPUT [OutTemp, WriteState]; Dally: NOP; Ret: RETURN; SETTASK[InTask]; InStart: Source _ 0C, AT [InStartLoc]; Packet _ 0C; Checksum _ 0C; Base _ MicrocodeAddress; Base _ (Base) + 1; * eb files don't have version word BaseHi _ 0C; * skip over first packet InPurge: InTemp _ PurgeThisPacket, CALL[InState]; * wait here for next packet to arrive InFilter: T _ EtherPup, Call[InSkip1Check]; INPUT[BytesLeft, ReadData]; * PupLength T _ D0MicrocodeAnswer, CALL[InCheck]; T _ OurVersionNumber, CALL[InCheck]; * PupID T _ Packet, CALL[InCheck]; * PupID2 T _ (Host), CALL[InCheck]; * our PupAddress T _ OurVersionNumber, CALL[InCheck]; T _ OurVersionNumber, CALL[InCheck]; INPUT[SourceTemp,ReadData]; T _ MiscServSocket, CALL[InSkip1Check]; * his PupAddress * We have not checked to see if the packet has ended already * (Probably with bad status because of a collision) * The hope is that some data will mismatch by now * Check that this packet is comming from the right machine. * We can skip this if all the boot servers really send the same version of the microcode. HostCheck: T _ (Source); T _ SourceTemp, SKIP[ALU#0]; Source _ T; LU _ (Source) XOR (T); SKIP[ALU=0]; GOTO[InPurge]; Packet _ (Packet)+1, GOTO[InGo]; * We only get a wakeup if there are at least 4 words in the buffer * so it is safe to skip up to 3 words before checking one InSkip1Check: INPUT[xxxCSLoc, ReadData]; * T has data word to be compared with next input data word * There is no check for short packet * since it will get tested at InLoop before we do anything stupid InCheck: INPUT[InTemp, ReadData]; NOP; * Beware of bypass kludge LU _ (InTemp) XOR (T); GOTO[Ret,ALU=0]; GOTO[InPurge]; InState: OUTPUT [InTemp, WriteState], GOTO[Dally]; InGo: BytesLeft _ (BytesLeft)-(PupOverhead); GOTO[EndMarker,ALU=0]; BytesLeft _ (BytesLeft)-1, CALL[Ret]; InLoop: BytesLeft _ (BytesLeft)-(2C), GOTO[InDone,R<0]; SKIP[NOAtten]; InShort: GOTO[InStart]; * Packet ended early TakeOne: INPUT[Word,ReadData]; T _ Word; Checksum _ (Checksum)+T; PSTORE1[Base,Word,0]; Base _ (Base)+1, RETURN; InDone: INPUT[xxxCSLoc,ReadData]; * Pup Checksum INPUT[xxxCSLoc,ReadData]; * CRC INPUT[InTemp,ReadStatus]; LU _ (InTemp) AND (InputStatusMask); SKIP[ALU=0]; BadStatus: GOTO[InStart]; * Packet got smashed * Reset timer to 2 sec whenever we get a good packet TimerReg _ 140C, GOTO [InPurge]; EndMarker: LU _ Checksum; InTemp _ and[MicrocodeLoadedLoc, 7400]c, SKIP[ALU=0]; GOTO[InStart]; * Checksum didn't match InTemp _ (InTemp) or (and[MicrocodeLoadedLoc, 377]c); APC&APCTask _ InTemp; return; END;(2469)\3200b168B993b71B1493b6B1879b1B707b1B