; file : sboot.40.3.text ; last modified: 01/23/84 ; ; contains utility subroutines: ; c2greet Sendit Getstr C2compr ; c2erprt Strobit C2CVinf ; c2chkdr ClrScrn C2getnm ; encrypt, decrypt Homeup C2getpw ; EndRecv, SetupRecv Gotoxy ; Logon page ; c2greet - write Constellation II greeting message to screen ; ; This procedure writes the Constellation II logon greeting ; message to the display. The prompts for the user name and ; password are not performed here. ; ; c2greet movem.l a4/d0,-(sp) ;store registers tst.b CPextcrt.w ;is external crt? bne.s C2GR10 ;yes bsr clrscrn ;clear screen ; move.w #$1E0C,d0 ;set X=30 Y=12 bsr gotoxy ;position cursor C2GR10 lea c2msg03,a4 ;write Constellation II message to screen bsr messout ; tst.b CPextcrt.w ;is external crt? bne.s C2GR20 ;yes move.w #$1E0D,d0 ;set X=30 Y=13 bsr gotoxy ;position cursor C2GR20 lea c2msg04,a4 ;write message to screen bsr messout ; tst.b CPextcrt.w ;is external crt? bne.s C2GR30 ;yes move.w #$230E,d0 ;set X=35 Y=14 bsr gotoxy ;position cursor C2GR30 lea c2msg05,a4 ;write message to screen bsr messout ; tst.b CPextcrt.w ;is external crt? bne.s C2GR40 ;yes move.w #$2310,d0 ;set X=35 Y=16 bsr gotoxy ;position cursor C2GR40 lea c2msg06,a4 ;write message to screen bsr messout ; tst.b CPextcrt.w ;is external crt? bne.s C2GR50 ;yes move.w #$2312,d0 ;set X=35 Y=18 bsr gotoxy ;position cursor C2GR50 lea bootsrv,a4 ; 3.8 clr.l d0 ; 3.8 move.b (a4),d0 ; 3.8 move.l d0,d1 ; 3.8 divu #10,d0 ; 3.8 mulu #10,d0 ; 3.8 sub.w d0,d1 ; 3.8 divu #10,d0 ; 3.8 addi.w #$30,d0 ; 3.8 addi.w #$30,d1 ; 3.8 lea c2msg08,a4 ; 3.8 move.b d0,(a4) ; 3.8 move.b d1,1(a4) ; 3.8 lea c2msg07,a4 ;write message to screen bsr messout ; ; movem.l (sp)+,a4/d0 ;restore registers rts ;return page ; c2erprt - print a constellation II error message ; ; Output a constellation II error message onto the display ; screen. All error messages are output on the 42nd line ; of the display. ; ; Parameters: ; d0 - error message code ; ; c2erprt movem.l a0-a4/d0,-(sp) ;save registers lea c2erm13,a4 ;load unknown error message string c2er10 cmp.w #er10,d0 ;is this an invalid user name error bne.s c2er11 ;try next error lea c2erm10,a4 ;load error message string address c2er11 cmp.w #er11,d0 ; bne.s c2er12 ;try next error lea c2erm11,a4 ;load error message string address c2er12 cmp.w #er12,d0 ; bne.s c2er13 ;try next error lea c2erm12,a4 ;load error message string address c2er13 cmp.w #er13,d0 ; bne.s c2er14 ;try next error lea c2erm13,a4 ;load error message string address c2er14 cmp.w #er14,d0 ; bne.s c2er15 ;try next error lea c2erm14,a4 ;load error message string address c2er15 cmp.w #er15,d0 ; bne.s c2er16 ;try next error lea c2erm15,a4 ;load error message string address c2er16 cmp.w #er16,d0 ; bne.s c2er20 ;try next error lea c2erm16,a4 ;load error message string address c2er20 cmp.w #er20,d0 ;is this an invalid user name error bne.s c2er21 ;try next error lea c2erm20,a4 ;load error message string address c2er21 cmp.w #er21,d0 ; bne.s c2er22 ;try next error lea c2erm21,a4 ;load error message string address c2er22 cmp.w #er22,d0 ; bne.s c2er23 ;try next error lea c2erm22,a4 ;load error message string address c2er23 cmp.w #er23,d0 ; bne.s c2er24 ;try next error *3.6 lea c2erm23,a4 ;load error message string address c2er24 cmp.w #er24,d0 ; *3.6 bne.s c2er25 ;try next error *3.6 lea c2erm24,a4 ;load error message string address *3.6 c2er25 cmp.w #er25,d0 ; *4.0 bne.s c2ergo ;try next error *4.0 lea c2erm25,a4 ;load error message string address *4.0 c2ergo move.w #$002A,d0 ;set X=0 Y=42 bsr gotoxy ;position cursor bsr messout ;write error message movem.l (sp)+,a0-a4/d0 ;restore registers rts page ; ; ; c2srch - search the table for a particular value. ; ; Parameters: ; a1 - pointer to search control vector ; d7 - return code ; 0 - MATCH FOUND ; 1 - NO MATCH FOUND IN BLOCK ; -1 - END-OF-TABLE ENCOUNTERED ; ; Register usage: ; ; a5 <- pointer to field in table being examined ; a6 <- pointer to search item ; a2 <- pointer to end of table ; a0 <- pointer to beginning of entry ; ; c2srch movem.l a0-a6/d0-d6,-(sp) move.l 08(a1),a6 ;get address of search item move.l 16(a1),a0 ;get address of start of table adda.w 2(a1),a0 ;make starting address in table to begin search ;by adding table offset. this is used mostly for ;the first block of the table... move.l 16(a1),a2 ;making ending address of table adda.w #512,a2 ;a2 <= end of table address c2matl1 move.l a0,a5 ;make address within an entry to begin the ;the actual search comparison adda.w 20(a1),a5 ;d5 <= address within entry of match field move.w 4(a1),d0 ;d0 <= length of search item ; ; test for null ( UNUSED) table entry ; ; cmpi.b #0,(a5) ;look for null table entries beq.s c2null ;null table entry cmpi.b #$FF,(a5) ;look for end-of-table entry beq.s c2eot ;end-of-table found ; ; an entry has been located, determine if entry matches search item ; bsr c2compr ;call string comparision routine tst.w d0 ;do strings match bne.s c2null ;strings can not match ; ; match found ; move.l 12(a1),a2 ;get address of buffer to receive matched entry move.w 6(a1),d2 ;get the length of an individual entry subq.w #1,d2 ;d2 <= entry length adjusted for DBRA c2matl2 move.b (a0)+,(a2)+ ;copy entry from table to match buffer dbra d2,c2matl2 ; sub.l d7,d7 ;MATCH return code is zero (0) bra.s c2matex ; c2null adda.w 6(a1),a0 ;increment pointer to start of next entry cmpa.l a0,a2 ;compare end address to new starting address bne.s c2matl1 ;if not end-of-block branch ; ; end-of-block - entry not found in this block ; moveq #1,d7 ;NO MATCH return code (1) bra.s c2matex ;branch to end of routine ; ; end-of-table encountered - this condition is signalled by a ; $FF found in any constellation field ; for which a search may be performed. ; c2eot move.l #-1,d7 ;END-OF_TABLE return code ( -1 ) c2matex movem.l (sp)+,a0-a6/d0-d6 rts page ; ; ; c2chkdr - determine the number of drives connected to a ; particular disk server/ or disk cluster. This routine ; attempts to read block zero from the drive. If an ; error occurs, this is assumed to be the last drive ; on the network. ; ; Parameters: d0 - (INPUT) - maximum no. of drives to search for ; (OUTPUT) - no. of drives found on cluster ; d1 - (INPUT) - disk server station number. ; ; c2chkdr movem.l a0-a6/d2-d6,-(sp) cmpi.w #1,d0 ;only need to verify one drive beq.s c2drlp4 ;no need to execute program moveq #2,d3 ;d3 <= current drive no. being verified ;start with drive 2 since drive 1 must be boot drive move.l d0,d4 ;d4 <= maximum drive no. subq.l #1,d4 ;subtract one because of DBRA instruction lea bootdrv,a1 ;a1 <= address of boot server no. move.b (a1),-(sp) ;store boot server station number move.b d1,(a1) ;replace boot server station no. with new station no. lea bootsrv,a1 ;a1 <= address of boot drive number move.b (a1),-(sp) ;store boot drive no. move.l #512,d2 ;d2 <= number bytes to read lea iobuf,a0 ;a0 <= input buffer address ; ; loop until last drive is found ; c2drlp1 lea bootdrv,a1 move.b d3,(a1) ;setup new current drive number moveq #DiOfset,d0 ;d0 <= disk block number to read bsr DskRd ;read disk block from drive tst.w d7 ;test disk drive return code bne.s c2drlp2 ;error reading drive ( last drive found ) ; ; see if there are more drives on cluster ; addq #1,d3 ;increment drive no. being verified dbra d4,c2drlp1 ;decrement count of no. of drives, branch to test ; ; maximum drive count reached ; bra.s c2drlp3 ;exit from program branch ; ; no more drives left, decrement drive count by one ; c2drlp2 subq #1,d3 ;decrement drive count c2drlp3 lea bootsrv,a1 ; move.b (sp)+,(a1) ;restore boot drive number lea bootdrv,a1 ; move.b (sp)+,(a1) ;restore boot server number move.l d3,d0 ;setup no. of drives found in d0 c2drlp4 movem.l (sp)+,a0-a6/d2-d6 rts page ; ; ; encrypt ; ; parameters: a0 - ptr to decrypted name ; a1 - ptr to encrypted name ; a2 - ptr to MAPBASE table ; a3 - ptr to MAPINCR table ; d0 - len of string ; - CHARVAL ; d1 - MASKVAL ; d5 - ENCRYPT.C[1] ; d6 - CHARNUM ; ; encrypt movem.l a0-a6/d0-d6,-(sp) move.l d0,d6 ;copy length subq #1,d6 ;adjust length by one sub.l d1,d1 ;MASKVAL := 0 moveq #1,d2 ;CHARNUM := 1 sub.l d5,d5 move.b (a0),d5 ;store first character of encrypt field ; ; FOR CHARNUM := 1 TO LEN ( NAMELEN or PSWLEN) DO ; BEGIN ; enlp1 move.b (a0)+,d0 ;CHARVAL := ORD(DECRIPT.C[CHARNUM]) sub.l d4,d4 ; move.w d1,d4 ;CHARVAL := MASKVAL add.w (a2)+,d4 ;CHARVAL := MASKVAL + MAPBASE[CHARNUM] sub.l d3,d3 ; move.b d0,d3 ;CHARVAL := MASKVAL subi.w #32,d3 ;CHARVAL := (CHARVAL - 32 ) muls (a3)+,d3 ;CHARVAL := (CHARVAL - 32) * MAPINCR[CHARNUM] add.l d3,d4 ;CHARVAL := move.b d4,(a1)+ ;ENCRYPT.C[CHARNUM] := CHR(CHARVAL) cmpi #1,d2 ;IF CHARNUM = 1 THEN bne enlp2 ; subi #32,d5 ;MASKVAL := (ORD(DECRYPT.C[1]-32) ) divs #9,d5 ;MASKVAL := ORD(DECRYPT.C[1] - 32) MOD 9) move.l d5,d4 swap d5 ; move d5,d1 ; enlp2 addq #1,d2 ;CHARNUM := CHARNUM + 1 dbra d6,enlp1 ;END movem.l (sp)+,a0-a6/d0-d6 rts page ; ; ; decrypt ; ; parameters: a0 - ptr to encrypted name ; a1 - ptr to decrypted name ; a2 - ptr to MAPBASE table ; a3 - ptr to MAPINCR table ; d0 - len of string ; - CHARVAL ; d1 - MASKVAL ; d5 - ENCRYPT.C[1] ; d6 - CHARNUM ; ; decrypt movem.l a0-a6/d0-d6,-(sp) move.l d0,d6 ;copy length subq #1,d6 ;adjust length by one sub.l d1,d1 ;MASKVAL := 0 moveq #1,d2 ;CHARNUM := 1 ; ; FOR CHARNUM := 1 TO LEN ( NAMELEN or PSWLEN) DO ; BEGIN ; delp1 move.b (a0)+,d0 ;d0 := ORD(ENCRYPT.C[CHARNUM]) sub.l d3,d3 ; move.b d0,d3 ;d3 := ORD(ENCRYPT.C[CHARNUM]) sub.w d1,d3 ;d3 := " - MASKVAL sub.w (a2)+,d3 ;d3 := " - MAPBASE[CHARNUM] divs (a3)+,d3 ;d3 := " DIV MAPINCR[CHARNUM] sub.l d4,d4 ; move.w d3,d4 ;keep the quotient addi.w #32,d4 ;d4 := d3 (above) + 32 move.b d4,(a1)+ ;DECRYPT.C[CHARNUM] := CHR(CHARVAL) cmpi #1,d2 ;IF CHARNUM = 1 THEN bne.s delp2 ; sub.l d5,d5 move.b d4,d5 ;get first character of decrypt field subi #32,d5 ;MASKVAL := (ORD(DECRYPT.C[1]-32) ) divs #9,d5 ;MASKVAL := ORD(DECRYPT.C[1] - 32) MOD 9) move.l d5,d4 swap d5 ; move.w d5,d1 ; delp2 addq #1,d2 ;CHARNUM := CHARNUM + 1 dbra d6,delp1 ;END movem.l (sp)+,a0-a6/d0-d6 rts page ; ; EndRecv ; ; This subroutine does an EndRecv to clear out the socket used by Const II ; commands. ; ; Register usage: ; {input} A1 - address of data area for transporter commands ; ; A5 - clobbered ; ; {output} D0 - return code (either 0 or NoTrans) ; ; ; Command control block = Trans_Cmd result record = Rcv_Hdr ; +-----------------------+ +-----------------------+ ; | command = $10 | | return code | ; +-----------------------+ +-----------------------+ ; | result msb | ; +--- ___+ ; | record | ; +--- ---+ ; | address lsb | ; +-----------------------+ ; | socket number | ; +-----------------------+ EndRecv move.b #waiting,RHdr(A1) ;initialize result code pea Rcv_Hdr ;load address of result vector move.l (SP)+,TC_PRslt(A1) ; and put four bytes into trans command move.b #EndOp, TC_Op(A1) ;load command code over 1st byte of address move.b #C2_sock, TC_sock(A1) ;load socket number ; ;all set up; now do it lea Trans_Cmd,A5 bsr Strobit cmpi.b #True, D0 ;was strobe successful??? bne CantStrobe ;transporter not responding Elp1 cmpi.b #waiting, RHdr(A1) ;command accepted yet??? beq.s Elp1 clr.w D0 ;success!! rts page ; ; SetupRecv ; ; This subroutine sends a SetupRecv command in preparation for the Where are you ; command. ; ; Register usage: ; {input} A1 - address of data area for transporter commands ; ; A5 - clobbered ; ; {output} D0 - return code (either 0 or NoTrans) ; ; ; Command control block = Trans_Cmd result record = Rcv_Hdr ; +-----------------------+ +-----------------------+ ; | command = $F0 | | return code | ; +-----------------------+ +-----------------------+ ; | result msb | | source host | ; +--- ___+ +-----------------------+ ; | record | | data msb | ; +--- ---+ +--- ___+ ; | address lsb | | length lsb | ; +-----------------------+ +-----------------------+ ; | socket number | ; +-----------------------+ data record = C2x_cmd ; | data msb | +-----------------------+ ; +--- ---+ | protoid = 1 msb | ; | address | +--- ---+ ; +--- ---+ | = $FE lsb | ; | lsb | +-----------------------+ ; +-----------------------+ | msgtype = $10 msb | ; | data msb | +--- ---+ ; +--- ---+ | = 0 lsb | ; | length lsb | +-----------------------+ ; +-----------------------+ | source msb | ; | control length = 0 | +--- ---+ ; +-----------------------+ | lsb | ; +-----------------------+ ; | devtype msb | ; +--- ---+ ; | lsb | ; +-----------------------+ ; | name byte 1 | ; + ... ...+ ; | byte 10 | ; +-----------------------+ SetupRecv move.b #waiting,RHdr(A1) ;initialize result code pea Rcv_Hdr ;load address of result vector move.l (SP)+,TC_PRslt(A1) ; and put four bytes into trans command move.b #RecvOp, TC_Op(A1) ;load command code over 1st byte of address pea C2x_Cmd ;load address of data vector -- it points to move.l (SP)+, TC_PData(A1) ; a My Id is ... message move.b #C2_sock, TC_sock(A1) ;load socket number over 1st byte of data address move.w #C2_Dlen, TC_Dlen(A1) ;load data length move.b #C2_Clen, TC_Hlen(A1) ;load control word length ; ;all set up; now do it lea Trans_Cmd,A5 bsr Strobit cmpi.b #True, D0 ;was strobe successful??? bne.s CantStrobe ;transporter not responding lp1 cmpi.b #waiting, RHdr(A1) ;command accepted yet??? beq.s lp1 ;can't fail clr.w D0 ;success!! rts CantStrobe ;set error code and exit move.w #NoTrans, D0 ;no transporter... rts page ; ; Logon ; ; This subroutine broadcasts the Hello command ; ; Register usage: ; {input} A1 - address of data area for transporter commands ; ; A0, A2, A3, A5, A6 - clobbered ; ; {output} D0 - result (0, TimedOut, or (impossible) transporter error) ; ; Command control block = Trans_Cmd result record = Snd_Hdr ; +-----------------------+ +-----------------------+ ; | command = $40 | | return code | ; +-----------------------+ +-----------------------+ ; | result msb | | unused | ; +--- ___+ +--- ---+ ; | record | | unused | ; +--- ---+ +--- ___+ ; | address lsb | | unused | ; +-----------------------+ +-----------------------+ ; | destination socket=$80| ; +-----------------------+ data record = C2_cmd ; | data msb | +-----------------------+ ; +--- ---+ | protoid = 1 msb | ; | address | +--- ---+ ; +--- ---+ | = $FE lsb | ; | lsb | +-----------------------+ ; +-----------------------+ | msgtype = 0 msb | ; | data msb | +--- ---+ ; +--- ---+ | = 0 lsb | ; | length lsb | +-----------------------+ ; +-----------------------+ | source = this msb | ; | control length = 0 | +--- ---+ ; +-----------------------+ | station lsb | ; | destination host = $FF| +-----------------------+ ; +-----------------------+ | devtype = 0 msb | ; +--- ---+ ; | = $37 lsb | ; +-----------------------+ ; | name=user name byte 1 | ; + ... ...+ ; | byte 10 | ; +-----------------------+ Logon move.b #waiting,SHdr(A1) ;initialize result code pea Snd_Hdr ;load address of result vector move.l (SP)+, TC_PRslt(A1) ; and move into trans command buffer move.b #SendOp, TC_Op(A1) ;load command code over 1st byte of address pea C2_cmd ;load address of data vector -- it points to move.l (SP)+,TC_PData(A1) ; a Hello message that is set up below. move.b #C2_sock, TC_sock(A1) ;load socket number over 1st byte of data address move.w #C2_dlen,TC_Dlen(A1) ;load data length move.b #C2_clen,TC_Hlen(A1) ;load control length move.b #Broadcast,TC_Dest(A1) ;load destination -- a broadcast ; ;now set up the Hello command in C2_cmd move.w #C2_pid,C2_proto(A1) ;load protocol move.w #C2_hello,C2_msgtype(A1);load message type clr.w D0 ;load this Concept's host number move.b CPtprnbr.W, D0 move.w D0, C2_src(A1) move.w #C2_CCwrkstn,C2_devtype(A1);load device type lea C2nmbuf, a5 ;move user name into buffer lea C2_Name(A1), a6 moveq #namelen,d0 Logon1 move.b (a5)+, (a6)+ dbra d0, Logon1 ;have to decrypt the name move.l a1, a5 ;save transporter command address lea C2_Name(A1),a0 ;set up parameters move.l a0, a1 lea nambase,a2 ;encryption tables lea namincr,a3 move.w #Namelen,d0 bsr decrypt move.l a5, a1 ;restore transporter command address ; ; now send the command ; bra.s Send page ; ; SendIt ; ; This subroutine broadcasts the Where are you command that will (hopefully) find the ; user's boot disk server. ; ; Register usage: ; {input} A1 - address of data area for transporter commands ; ; A5 - clobbered ; ; {output} D0 - result (0, TimedOut, or (impossible) transporter error) ; ; Command control block = Trans_Cmd result record = Snd_Hdr ; +-----------------------+ +-----------------------+ ; | command = $40 | | return code | ; +-----------------------+ +-----------------------+ ; | result msb | | unused | ; +--- ___+ +--- ---+ ; | record | | unused | ; +--- ---+ +--- ___+ ; | address lsb | | unused | ; +-----------------------+ +-----------------------+ ; | destination socket=$80| ; +-----------------------+ data record = C2_cmd ; | data msb | +-----------------------+ ; +--- ---+ | protoid = 1 msb | ; | address | +--- ---+ ; +--- ---+ | = $FE lsb | ; | lsb | +-----------------------+ ; +-----------------------+ | msgtype = 3 msb | ; | data msb | +--- ---+ ; +--- ---+ | = 0 lsb | ; | length lsb | +-----------------------+ ; +-----------------------+ | source msb | ; | control length = 0 | +--- ---+ ; +-----------------------+ | lsb | ; | destination host = $FF| +-----------------------+ ; +-----------------------+ | devtype = 00 msb | ; +--- ---+ ; | = $FF lsb | ; +-----------------------+ ; | name=C2_dsbuf byte 1 | ; + ... ...+ ; | byte 10 | ; +-----------------------+ SendIt move.b #waiting,SHdr(A1) ;initialize result code pea Snd_Hdr ;load address of result vector move.l (SP)+, TC_PRslt(A1) ; and move into trans command buffer move.b #SendOp, TC_Op(A1) ;load command code over 1st byte of address pea C2_cmd ;load address of data vector -- it points to move.l (SP)+,TC_PData(A1) ; a Where are you message that is set up below. move.b #C2_sock, TC_sock(A1) ;load socket number over 1st byte of data address move.w #C2_dlen,TC_Dlen(A1) ;load data length move.b #C2_clen,TC_Hlen(A1) ;load control length move.b #Broadcast,TC_Dest(A1) ;load destination -- a broadcast ; ;now set up the where are you command in C2_cmd move.w #C2_pid,C2_proto(A1) ;load protocol move.w #C2_whrru,C2_msgtype(A1);load message type clr.w D0 ;prepare to get source host number move.b CPtprnbr.W, D0 ;get it move.w D0, C2_src(A1) ;load source host number move.w #C2_Anysrv,C2_devtype(A1);response any server of this name *4.0 ;name is already there -- put there by C2verpw ; ; now send the command ; Send lea Trans_Cmd,A5 bsr.s Strobit cmpi.b #True, D0 ;was strobe successful??? bne CantStrobe ;transporter not responding move.w #10000, D0 ;for time out wlp2 cmpi.b #waiting, SHdr(A1) bne.s Wdone ;wait until result changes dbra D0, wlp2 timout move.w #timedOut, D0 rts wdone tst.b Shdr(A1) ;did it work?? bmi Serr ;fatal error clr.w D0 ;success!! rts serr clr.w D0 move.b SHdr(A1), D0 rts ;return the transporter error code Strobit ; this subroutine actually sends the commands to the transporter ; register usage: ; ; {input} A5 - address of transporter command ; ; {output} D0 - transporter error code ; movem.l D1-D3/A1-A2,-(sp) ; save registers move.l A5, D0 ;D0.b2 = cmdadr HI swap D0 ;now D0.b = cmdadr HI move.w A5, D2 ;D2.b = cmdadr LO move.w A5, D1 ;save cmdadr MED lsr.w #8, D1 ;d1.b = cmdadr MED lea StrAdr.l,A2 ;load strobe address bsr.s waitrdy ;is transporter ready??? boff failed ;no move.b D0, (A2) ;strobe address HI bsr.s waitrdy boff failed move.b D1,(A2) ;strobe address MED bsr.s waitrdy boff failed move.b D2,(A2) ;strobe address LO moveq #True, D0 ;success!!! Exit movem.l (sp)+,D1-D3/A1-A2 ; restore registers rts failed moveq #False,D0 ;failed bra.s exit waitrdy move.w #10000, d3 waitlp btst #0, RdyAdr.l dbne d3, waitlp isrdy rts page ; ; Clrscrn - Clear display screen ; ; This procedure moves the clears the display. The cursor is ; left in the home position by the action. The escape sequence ; <'J'> is transmitted to the display driver to perform ; this function. ; ; ; Parameters: ; ; Clrscrn tst.b CPextcrt.w ;don't do if *4.0 bne.s CLRSCex ; external crt *4.0 movem.l a0-a1/d0,-(sp) ;save registers move.l CPdsputc.l,a1 ;get address of display routine moveq #$1B,d0 ;load escape character jsr (a1) ;output escape character moveq #'J',d0 ;load 'J' jsr (a1) ;output 'J' movem.l (sp)+,a0-a1/d0 ;restore registers CLRSCex rts ;return ; ; ; Homeup - Homeup the cursor to top of screen ; ; This procedure moves the cursor to the top of the display ; regardless of the display orientation. The escape sequence ; <'H'> is transmitted to the display driver to perform ; this function. ; ; ; Parameters: ; ; Homeup tst.b CPextcrt.w ;don't do if *4.0 bne.s HOMUPex ; external crt *4.0 movem.l a0-a1/d0,-(sp) ;save registers move.l CPdsputc.l,a1 ;get address of display routine moveq #$1B,d0 ;load escape character jsr (a1) ;output escape character moveq #'H',d0 ;load 'H' jsr (a1) ;output 'H' movem.l (sp)+,a0-a1/d0 ;restore registers HOMUPex rts ;return page ; Gotoxy - position the cursor at a specific point on the display ; ; This procedure move the cursor to a specified position ; on the screen. The coordinates are passed in register ; zero (D0) in the form of graphics mode X-Y coordinates. ; The 'X' coordinated is in the 2nd byte and the 'Y' ; coordinate is in the 3rd byte. ; ; Parameters: D0.W (Right byte is 'X') ; (Left byte is 'Y') ; Gotoxy movem.l a0-a6/d0-d6,-(sp) ;save registers tst.b CPextcrt.w ;don't do if *4.0 bne.s gtOut ; external crt *4.0 move.l d0,d2 ;save X-Y move.l CPdsputc.l,a1 ;get address of display routine ; ; First home the cursor ; bsr.s Homeup ;*4.0 ; ; perform 'X' positioning ; gtXpos move.w d2,d3 ;copy 'X' count lsr.w #8,d3 ;shift 'X' count into counter register tst.w d3 ;Is 'X' count zero beq.s gtYpos ;Yes, already at 'X' position zero ; gtXloop moveq #$0C,d0 ;load CURSOR RIGHT jsr (a1) ;output character subq.w #1,d3 ;substract 1 from 'X' count bne.s gtXloop ;right position ; ; perform 'Y' positioning ; gtYpos move.w d2,d3 ;copy 'Y' count and.w #$00FF,d3 ; tst.w d3 ;Is 'Y' count zero beq.s gtOut ;Yes, already at 'Y' position zero ; gtYloop moveq #$0D,d0 ;load CR-FL character jsr (a1) ;output character subq.w #1,d3 ;substract 1 from 'Y' count bne.s gtYloop ;down again ; gtOut movem.l (sp)+,a0-a6/d0-d6 ;restore registers rts ; return page ; ; Getstr - Get a string of characters from the keyboard ; ; This procedure reads a string of characters from the ; keyboard and stores them in the buffer addressed by ; address register (A0). The maximum length of the ; string is in data register (D0). The number of bytes ; received is returned is D0. The carriage return (CR) ; is not returned as part of the input string. Characters ; are not echoed if the top bit of D0 is 1. ; ; Parameters: ; ; a0 - address of buffer to receive characters ; d0 - (INPUT) maximum no. of characters ; (OUTPUT) no. of characters received ; ; Getstr movem.l a0-a6/d1-d6,-(sp) move.l d0,d1 ; move.l d0,d3 ;copy D0 to use as echo flag moveq #31,d2 ;msb is 31 bclr d2,d1 ;clear top bit of character counter clr.l d2 ;Initialize word counter move.l CPdsputc.l,a2 ;Display input vector loaded move.l CPkbgetc.l,a1 ;Keyboard input vector loaded ; getlp1 jsr (a1) ;Get character from keyboard cmpi.b #$0D,d0 ;Is it a carriage return beq.s gtsout1 ;Yes we have Bananas (CR) cmpi.b #$61,d0 ;convert lower case to upper case blt.s getlp3 ; cmpi.b #$7A,d0 ; bgt.s getlp3 ; subi.b #$20,d0 ;upper case := lower case - $20 ; getlp3 cmpi.b #$08,d0 ;perform backspace operation bne.s getlp4 ; tst.w d2 ;how many characters have we printed beq.s getlp1 ;no more characters to backspace over subq.w #1,d2 ;subtract one from current character count addq.w #1,d1 ;adjust maximum character input count tst.l d3 ;test echo flag blt.s getlp8 ;branch if bit is set ( NO ECHO) ; ; do the actual backspace operation on the ; video screen. ; jsr (a2) ;output backspace character move.b #$20,d0 ; jsr (a2) ;write blank blank character move.b #08,d0 ; jsr (a2) ;write backspace character ; getlp8 subq.w #1,a0 ;adjust current buffer pointer move.b #$20,(a0) ;write blank into buffer backspaced over (WEIRD BUT EFFECTIVE) bra.s getlp1 ; ; getlp4 tst.l d3 ;test echo flag blt.s getlp2 ;branch if bit is set ( NO ECHO) jsr (a2) ;Output character to display ; getlp2 move.b d0,(a0)+ ;Store characters in buffer addq.w #1,d2 ;Increment count of no. of chars input subq.w #1,d1 ;Decrement maximum input count bne.s getlp1 ;Still more to come ; gtsout1 moveq #$0D,d0 ;Output a at end of input if jsr (a2) ;to many characters ; moveq #$0A,d0 ;Output a linefeed at end of input jsr (a2) ; move.l d2,d0 ;Return no. of characters read movem.l (sp)+,a0-a6/d1-d6 rts page ; C2compr - compare the contents of two buffers in memory ; ; Parameters: a5 - address of first string ; a6 - address of second string ; d0 - length of string ; returns 0 - if strings match ; -1 - if strings do not match ; ; c2compr movem.l a5-a6/d7,-(sp) move.l d0,d7 ;copy length of string subq.w #1,d7 ;adjust for dbne instructions move.w #-1,d0 ;initialize match pointer cmploop cmpm.b (a5)+,(a6)+ ;compare strings dbne d7,cmploop ;loop until finished bne.s cmpdone ; not.w d0 ;strings match cmpdone movem.l (sp)+,a5-a6/d7 ;restore registers rts page ; c2CVinf - get corvus volume table information. This procedure ; reads the DRIVE.INFO block from a drive and stores ; the Corvus volume table length and addresses in a ; local program structure.. Address register A1 contains ; the address of this particular structure. ; ; Parameters: d0 - drive number to read ; d1 - Disk server station address ; a1 - address of corvus volume info block ; Returns: d7 - return code from drive (non-negative) or valid chk ($FFFFFFFF) ; ne - error *3.6 ; eq - good *3.6 ; ; c2CVinf movem.l a0-a6/d0-d6,-(sp) lea bootdrv,a2 ;get address of boot drive no. ; move.b (a2),-(sp) ;store current boot drive move.b d0,(a2) ;store new drive number lea bootsrv,a2 ;get address of boot server move.b (a2),-(sp) ;store current server no. move.b d1,(a2) ;store new disk server station address ; move.l #512,d2 ;d2 <= setup block size = 512 bytes lea Iobuf,a0 ;a0 <= general IOBUF as buffer area moveq #DiOfset,d0 ;d0 <= Drive.Info table block address bsr DskRd ;read DRIVE.INFO block *3.6 bne.s c2inf1 ;error reading disk *3.6 bsr Valid8B8 ;validate drive.info block *3.6 bne.s c2inf1 ;invalid *3.6 ; ; ; store corvus volume table addresses and lengths in local ; boot code data locations. ; lea Iobuf,a0 ;a0 <= general IOBUF as buffer area move.l DIDUaof(a0),8(a1) move.l DIDAaof(a0),12(a1) move.l DIDVaof(a0),16(a1) move.l DINUaof(a0),20(a1) move.w DIDUlof(a0),0(a1) move.w DIDAlof(a0),2(a1) move.w DIDVlof(a0),4(a1) move.w DINUlof(a0),6(a1) c2inf1 lea bootsrv,a2 ;get address of boot drive no. move.b (sp)+,(a2) ;restore current boot drive lea bootdrv,a2 ;get address of boot server move.b (sp)+,(a2) ;restore current server no. movem.l (sp)+,a0-a6/d0-d6 tst.w d7 ;set cc *3.6 rts page ; C2getnm - get user name from console ; ; This procedure prompts the operator for the user name ; The user name prompt is output on display line 38. ; The name returned is placed in the buffer address by ; address register 0 ( a0 ). If the name enter is too ; long or no name is entered, an error message is printed ; by this routine. The name returned is blanked filled. ; ; Parameters: ; ; a0 - address of user name buffer ; ; c2getnm movem.l a0-a4/d0,-(sp) lea c2nmad1,a1 move.l a0,(a1) ;store name buffer address c2nmlp1 move.w #$0026,d0 ;position cursor for name prompt bsr gotoxy ; lea c2msg01,a4 ;get address of prompting message bsr messout ;write user name prompting message moveq #Namelen-01,d0 ;setup length of maximum user name field lea c2nmad1,a1 ; move.l (a1),a0 ;restore name buffer address move.l a0,a1 ;copy buffer address c2nmlp2 move.b #' ',(a1)+ ;copy blanks to use name field buffer dbra d0,c2nmlp2 ;terminate when count is zero move.l #80,d0 ;maximum user name length is 80 bsr getstr ;get user name cmpi.w #Namelen,d0 ;is name greater than 10 bgt.s c2nmer1 ;name is too long tst.w d0 ;test for name length less than zero beq.s c2nmer1 ;no name entered move.l a0,a1 ;decode password lea nambase,a2 ; lea namincr,a3 ; move.w #Namelen,d0 ; bsr encrypt ; bra.s c2nmex ;exit program ; c2nmer1 move.w #er10,d0 ;set invalid name error code bsr c2erprt ;print error message routine called bra.s c2nmlp1 ;reprompt for user name c2nmex movem.l (sp)+,a0-a4/d0 rts ; c2nmad1 data.l 0 page ; C2getpw - get user psw from console ; ; This procedure prompts the operator for the user password. ; The user password prompt is output on display line 40. ; The password returned is placed in the buffer address by ; address register 0 ( a0 ). If the password enter is to ; long an error message is printed by this routine and the ; operator is reprompted. The password buffer is blank filled. ; ; Parameters: ; ; a0 - address of user psw buffer ; c2getpw movem.l a0-a4/d0,-(sp) ; lea c2pwad1,a1 ; move.l a0,(a1) ;store address of psw buffer c2pwlp1 move.w #$28,d0 ;set X=0 Y=40 bsr gotoxy ;position cursor lea c2msg02,a4 ;get address of prompting message bsr messout ;write user psw prompting message moveq #Pswlen-01,d0 ;setup length of maximum user name field lea c2pwad1,a1 ; move.l (a1),a0 ;restore address of psw buffer move.l a0,a1 ;copy buffer address c2pwlp2 move.b #' ',(a1)+ ;copy blanks to use psw field buffer dbra d0,c2pwlp2 ;terminate when count is zero move.l #$8000004F,d0 ;maximum user psw length is 80 ;no echo of password by GETSTR if high bit is ON bsr getstr ;get user password cmpi #pswlen,d0 ;is psw greater than 08 bgt.s c2pwer1 ;psw is too long move.l a0,a1 ;decode password lea pswbase,a2 ; lea pswincr,a3 ; move.w #pswlen,d0 ; bsr encrypt ; bra.s c2pwex ;exit program ; c2pwer1 move.w #er11,d0 ;set invalid psw error code bsr c2erprt ;print error message routine called ;;;;; bra.s c2pwlp1 ;reprompt for user name c2pwex movem.l (sp)+,a0-a4/d0 ; rts c2pwad1 data.l 0