{File name: IOPPreEtherInitial.mc LastEdited: Sturgis, 4-Oct-83 13:52:22: renamed IOPPreEtherInitial.mc from IOPBoot.mc. Will contain a new command to receive SubBoot value. Last Edited: Jim Frandeen, January 14, 1982 11:39 AM: Comment out registers not used by load U regiser command. Last Edited: Jim Frandeen, December 14, 1981 10:55 AM: Put uDiagnostic back where it was. Last Edited: Jim Frandeen, November 23, 1981 4:58 PM: Check for page cross on first read. Last Edited: Jim Frandeen, November 17, 1981 4:26 PM: Make it smaller Last Edited: Jim Frandeen, August 21, 1981 10:24 AM: changes for new assembler Last Edited: Ogus, July 10, 1981 3:30 PM Last Edited: Jim Frandeen, November 13, 1981 1:12 PM Description: PROM uCode used in starting booting sequence, Author: Ogus, Created: August 25, 1980, } jk20(0,4939)(1,5644)(2,6350)(3,7056)(4,14817)\f1 { COMMANDS: 1 - Read Memory Block 3 - load U registers 4 - set parameters} z20320k40(2,14817)(3,65535)(4,65535)\f1 {Top of the IOP code. The code is started at this point for a new command. IOP Control should be set to InMode.}z20320k40\f1 {Read in first byte from the IOP port and interpret it as a command} SetTask[5]; {IOPStart used only for debugging when port might be in undefined state. The first click of Phase0 sets IOPCtl to zero. The three cycle delay at IOPStart is for the case that the IOP task runs before the emulator task after an exit kernel. During a normal booting sequence, the IOP port will be disabled.} IfEqual[Config,1,SkipTo[NotDebugging],]; StartAddress[IOPStart]; IOPStart: Noop, CANCELBR[$, 0F], c1; {only for debugging} Noop, c2; {wait for IOPCtl_ 0} Noop, c3; SkipTo[Debugging]; NotDebugging! StartAddress[IOPIdle]; Debugging! IOPIdle: CANCELBR[$, 0F], c1; IOPIdlex: Xbus _ IOPIData, XDisp, c2, at[0F,10,NoopRet]; {Load L7 with 9 (Read memory block), 0B (Write U block), or 0C Set Boot parameters)} rIOP _ 0 {For Write Register}, DISP4[IOPCmd, 8], L7 _ 8, c3; {COMMAND 1: Read memory block . . . . IOP Control is in InMode. Format of transfer (bytes): command (4 bits), low addr (10:17), mid. addr (2:9), high addr (0:1), low count-1 (8:15), high count-1 (0:7) => returns: low data, high data}z20320k40\f1 {Read the address. L7 = 9.} CReadMem: rTmp _ IOPIData, CALL[ReadWordx], c1, at [9, 10, IOPCmd]; {Return with real address low in rTmp} rIOP _ rTmp, L7 _ 6, c3, at[9,10,ReadWordRet];z20320k40\f1 {Read the high address into rhIOP.} rhIOP _ IOPIData, CALL[Noop2], c1; { Noop, c2;} { Noop, c3;}z20320k40\f1 {Next comes the count parameter. The value is (count-1) words.}z20320k40\f1 rTmp _ IOPIData, L7_ 5, CALL[ReadWordx], c1, at[6,10,NoopRet]; rTmp _ rTmp {count} + rIOP + 1 {address low}, IOPCtl _ IOPOutMode, c3, at[5,10,ReadWordRet]; z20320k40\f1 {We will wakeup here since the data register is empty, and the port is in OutMode. The IOP task will continue to wakeup until a byte is output to the port. Data is sent to the port high byte first, then low byte. At this point rhIOP is set up with addr[0:1], rTmp with addr[2:17].}z20320k40\f1 {Fetch the first word from the buffer.} SendAddress: MAR _ [rhIOP, rIOP], rIOP _ rIOP + 1, L7 _ 1, c1, at[5,10,NoopRet]; {Assume we start on page boundary, so no page cross here} uBufMax _ rTmp {Save max address+1}, BRANCH[$, RPgCrFirst, 1], c2; rTmp _ MD, L7Disp, CALL[Noop1], c3;z20320k40\f1 {Read Memory Block Inner Loop}z20320k40\f1 { Noop, c1;} RLoByte: {Output Low byte of word.} IOPOData _ rTmp LRot0, c2, at[1,10,NoopRet]; [] _ rIOP xor uBufMax, ZeroBr, c3;z20320k40\f1 {Process the high byte. Check for page crossing as well.} RHi: MAR _ [rhIOP, rIOP], rIOP_rIOP+1, BRANCH[$, RHi2Last], c1; {Read next word} {Output low byte} IOPOData _ rTmp LRot8, BRANCH [$, RPgCross, 1], c2; rTmp _ MD, L7Disp, CALL[Noop1], c3;z20320k40\f1 { Noop, GOTO[RLoByte], c1;} {This byte is the last byte. L7 = 1. The next address might have generated a page crossing, but we don't need to worry about it. Just cancel it, and go back to the top of the loop. } RHi2Last: IOPOData _ rTmp LRot8, L7Disp, CANCELBR[TestLast,2], c2; {Output low byte} { IOPCtl _ IOPInMode, GOTO [IOPIdle], c3;} z20320k40\f1 {The first MAR_ instruction generated a page cross branch. rIOP points to the beginning of this page, instead of at the beginning of the next page. Catch the first memory data, fix up rIOP to the correct address and continue. We will also } RPgCrFirst: rTmp _ MD, GOTO[RPgCr1], c3; {The previous MAR_ instruction generated a page cross branch. rTmp is now pointing to the begining of this page, instead at the beginning of the next page. Catch the last memory data, fix up rTmp to the correct address and continue. We will also put the remap code here later.} RPgCross: rTmp _ MD, c3; {Save memory data} RPgCr1: rIOP _ rIOP + 0FF + 1, GOTO[RLoByte], c1; {COMMAND 3: Write U register block. Format of transfer (bytes): command (4 bits), block, 16 words of data (low byte first)}z20320k40\f1 {writeU: Noop, c1, at[0B, 10, IOPCmd]; Noop, c2;} rhIOP_ IOPIData, CALL[ReadWord], c3, at[0B,10,NoopRet]; IOPCtl_ IOPAWMode, c3, at[0B, 10, ReadWordRet];z20320k40\f1 {Currently, we only write into Register Block 7. Register blocks not used are commented out.} Xbus_ rhIOP, XDisp, c1; []_ rIOP, AltUaddr, DISP4[uBlockWrite], c2; uBlockWrite: { uBlock0_ rTmp, GOTO[NextU], c3, at[0,10,uBlockWrite]; uBlock1_ rTmp, GOTO[NextU], c3, at[1,10,uBlockWrite]; uBlock2_ rTmp, GOTO[NextU], c3, at[2,10,uBlockWrite]; uBlock3_ rTmp, GOTO[NextU], c3, at[3,10,uBlockWrite]; uBlock4_ rTmp, GOTO[NextU], c3, at[4,10,uBlockWrite]; uBlock5_ rTmp, GOTO[NextU], c3, at[5,10,uBlockWrite]; uBlock6_ rTmp, GOTO[NextU], c3, at[6,10,uBlockWrite]; } uBlock7_ rTmp, GOTO[NextU], c3, at[7,10,uBlockWrite]; { uBlock8_ rTmp, GOTO[NextU], c3, at[8,10,uBlockWrite]; uBlock9_ rTmp, GOTO[NextU], c3, at[9,10,uBlockWrite]; uBlockA_ rTmp, GOTO[NextU], c3, at[0A,10,uBlockWrite]; uBlockB_ rTmp, GOTO[NextU], c3, at[0B,10,uBlockWrite]; uBlockC_ rTmp, GOTO[NextU], c3, at[0C,10,uBlockWrite]; uBlockD_ rTmp, GOTO[NextU], c3, at[0D,10,uBlockWrite]; uBlockE_ rTmp, GOTO[NextU], c3, at[0E,10,uBlockWrite]; uBlockF_ rTmp, GOTO[NextU], c3, at[0F,10,uBlockWrite]; } NextU: Noop, c1; rIOP_ rIOP+1, NibCarryBr, c2; TestLast: IOPCtl_ IOPInMode, BRANCH[ReadWord, IOPIdle], c3; {COMMAND 4: set boot parameters, order and size in bytes, in parentheses, of parameters ethernet host address(6) uEHost0, uEHost1, uEHost2 diagnostic flags(1) uDiagnostic boot device(1) bootDevice} {Read word Subroutine} ReadWord: rTmp_ IOPIData, c1, at[0C, 10, IOPCmd]; ReadWordx: rTmp_ rTmp LRot8, {0 Disp}, CALL[Noop1], c2; { Noop, c3;} rTmp_ rTmp or IOPIData, L7Disp, c1, at[0,10,NoopRet]; rTmp_ rTmp LRot8, RET[ReadWordRet], c2; uEHost0_ rTmp, L7_ 2, c3, at[0C, 10, ReadWordRet]; rTmp_ IOPIData, CALL[ReadWordx], c1; uEHost1_ rTmp, L7_ 7, c3, at[2, 10, ReadWordRet]; rTmp_ IOPIData, CALL[ReadWordx], c1; uEHost2_ rTmp, c3, at[7, 10, ReadWordRet]; rTmp_ IOPIData, CALL[Noop2], c1; { Noop, c2;} { Noop, c3;} uDiagnostic_ rTmp, L7 _ 0F, c1, at[7,10,NoopRet]; rTmp_ IOPIData, c2; bootDevice_ rTmp, GOTO[IOPIdle], c3; {Noop Subroutine to use up cycles} Noop2: L7Disp, c*, at[0B, 10, IOPCmd]; Noop1: RET[NoopRet], c*; {Command 7, the new command for PreEtherInitial, IOP supplies a subBoot number, to be used for choosing an ether Initial boot file. It also returns a 9 to the IOP, used by IOP to confirm presence of correct IOP task code.} RegDef[uESubBootX, U, 0DE]; {this does not conflict with anything in apilot100dandelion.df, and must agree with similar definitions in PreEtherIntial and MultiEtherInitial.} SetSubBoot: rTmp _ IOPIData, c1, at[0F, 10, IOPCmd]; IOPCtl _ IOPOutMode, c2; uESubBootX _ rTmp, c3; rTmp _ 9, c1; IOPOData _ rTmp LRot0, c2; IOPCtl _ IOPInMode, GOTO[IOPIdle], c3; z20320k40\f1 177t2 1t0