title 'Slave Network I/O System for CP/NET 1.1' page 60 ;*************************************************************** ;*************************************************************** ;** ** ;** S l a v e N e t w o r k I / O S y s t e m ** ;** ** ;*************************************************************** ;*************************************************************** ;/* ; Copyright (C) 1980, 1981, 1982 ; Digital Research ; P.O. Box 579 ; Pacific Grove, CA 93950 ; ; Revised: April 24, 1982 ;*/ false equ 0 true equ not false cpnos equ false ; cp/net system DSC2 equ false DB82 equ false Altos equ true always$retry equ true ; force continuous retries modem equ false ASCII equ false debug equ false CSEG if cpnos extrn BDOS else BDOS equ 0005h endif NIOS: public NIOS ; Jump vector for SNIOS entry points jmp ntwrkinit ; network initialization jmp ntwrksts ; network status jmp cnfgtbladr ; return config table addr jmp sendmsg ; send message on network jmp receivemsg ; receive message from network jmp ntwrkerror ; network error jmp ntwrkwboot ; network warm boot if DB82 slave$ID equ 12h ; slave processor ID number endif if DSC2 slave$ID equ 34h endif if Altos slave$ID equ 56h endif if cpnos ; Initial Slave Configuration Table Initconfigtbl: db 0000$0000b ; network status byte db slave$ID ; slave processor ID number db 84h,0 ; A: Disk device db 81h,0 ; B: " db 82h,0 ; C: " db 83h,0 ; D: " db 80h,0 ; E: " db 85h,0 ; F: " db 86h,0 ; G: " db 87h,0 ; H: " db 88h,0 ; I: " db 89h,0 ; J: " db 8ah,0 ; K: " db 8bh,0 ; L: " db 8ch,0 ; M: " db 8dh,0 ; N: " db 8eh,0 ; O: " db 8fh,0 ; P: " db 0,0 ; console device db 0,0 ; list device: db 0 ; buffer index db 0 ; FMT db 0 ; DID db slave$ID ; SID db 5 ; FNC initcfglen equ $-initconfigtbl endif if not cpnos ; see ntwrkwboot routine for why this defaultmaster equ 00h ; won't go in cp/nos wboot$msg: ; data for warm boot routine db '' db '$' networkerrmsg: db 'Network access failed.' db '$' rcvmsgerrmsg: db 'Illegal RCVMAIL command.' db '$' rcvmsgfailedmsg: db 'Mailbox empty or not logged in to master.' db '$' HexASCIItbl: db '0123456789ABCDEF' endif page DSEG ; Slave Configuration Table configtbl: Network$status: ds 1 ; network status byte ds 1 ; slave processor ID number ds 2 ; A: Disk device ds 2 ; B: " ds 2 ; C: " ds 2 ; D: " ds 2 ; E: " ds 2 ; F: " ds 2 ; G: " ds 2 ; H: " ds 2 ; I: " ds 2 ; J: " ds 2 ; K: " ds 2 ; L: " ds 2 ; M: " ds 2 ; N: " ds 2 ; O: " ds 2 ; P: " ds 2 ; console device ds 2 ; list device: ds 1 ; buffer index db 0 ; FMT db 0 ; DID db Slave$ID ; SID (CP/NOS must still initialize) db 5 ; FNC ds 1 ; SIZ ds 1 ; MSG(0) List number ds 128 ; MSG(1) ... MSG(128) msg$adr: ds 2 ; message address if modem timeout$retries equ 0 ; timeout a max of 256 times else timeout$retries equ 100 ; timeout a max of 100 times endif max$retries equ 10 ; send message max of 10 times retry$count: ds 1 Mailmsg: ; Mail box message area db 0 ; msg.fmt = 0 db $-$ ; msg.did db $-$ ; msg.sid db $-$ ; msg.fnc db $-$ ; msg.siz ds 256 ; msg.msg(0) ... msg.msg(255) FirstPass: db 0ffh ; Network Status Byte Equates ; active equ 0001$0000b ; slave logged in on network rcverr equ 0000$0010b ; error in received message senderr equ 0000$0001b ; unable to send message ; General Equates ; SOH equ 01h ; Start of Header STX equ 02h ; Start of Data ETX equ 03h ; End of Data EOT equ 04h ; End of Transmission ENQ equ 05h ; Enquire ACK equ 06h ; Acknowledge LF equ 0ah ; Line Feed CR equ 0dh ; Carriage Return NAK equ 15h ; Negative Acknowledge conout equ 2 ; console output function print equ 9 ; print string function rcvmsg equ 67 ; receive message NDOS function login equ 64 ; Login NDOS function ; I/O Equates ; if DB82 stati equ 83h mski equ 08h dprti equ 80h stato equ 83h msko equ 10h statc equ 81h mskc equ 20h dprto equ 86h endif if DSC2 if modem stati equ 59h mski equ 02h dprti equ 58h stato equ 59h msko equ 01h dprto equ 58h else stati equ 51h mski equ 02h dprti equ 50h stato equ 51h msko equ 01h dprto equ 50h endif endif if Altos stati equ 1fh mski equ 01h dprti equ 1eh stato equ 1fh msko equ 04h dprto equ 1eh endif page CSEG ; Utility Procedures ; delay: ; delay for c[a] * 0.5 milliseconds mvi a,6 delay1: mvi c,86h delay2: dcr c jnz delay2 dcr a jnz delay1 ret if ASCII Nib$out: ; A = nibble to be transmitted in ASCII cpi 10 jnc nibAtoF ; jump if A-F adi '0' mov c,a jmp Char$out nibAtoF: adi 'A'-10 mov c,a jmp Char$out endif Pre$Char$out: mov a,d add c mov d,a ; update the checksum in D nChar$out: ; C = byte to be transmitted if Altos mvi a,10h out stato endif in stato ani msko jz nChar$out if DB82 in statc ani mskc jz nChar$out endif if DSC2 nop ; these NOP's make DB8/2 & DSC2 nop ; versions the same length - saves nop ; a second listing nop nop nop nop endif mov a,c out dprto ret ; Char$out: call nChar$out if Altos xthl! xthl! xthl! xthl xthl! xthl! xthl! xthl xthl! xthl! xthl! xthl ;delay 54 usec ret else jmp delay ; delay after each Char sent to Mstr ; ret endif if ASCII Nib$in: ; return nibble in A register call Char$in rc ani 7fh sui '0' cpi 10 jc Nib$in$rtn ; must be 0-9 adi ('0'-'A'+10) and 0ffh cpi 16 jc Nib$in$rtn ; must be 10-15 lda network$status ori rcverr sta network$status mvi a,0 stc ; carry set indicating err cond ret Nib$in$rtn: ora a ; clear carry & return ret endif xChar$in: mvi b,100 ; 100 ms corresponds to longest possible jmp char$in0 ;wait between master operations Char$in: ; return byte in A register ; carry set on rtn if timeout if modem mvi b,0 ; 256 ms = 7.76 chars @ 300 baud else if Altos mvi b,3 ; 3 ms = 50 chars @ 125k baud else mvi b,50 ; 50 ms = 50 chars @ 9600 baud endif endif Char$in0: mvi c,5ah Char$in1: if Altos mvi a,0 out stati endif in stati ani mski jnz Char$in2 dcr c jnz Char$in1 dcr b jnz Char$in0 stc ; carry set for err cond = timeout ret Char$in2: in dprti ret ; rtn with raw char and carry cleared Net$out: ; C = byte to be transmitted ; D = checksum mov a,d add c mov d,a if ASCII mov a,c mov b,a rar rar rar rar ani 0FH ; mask HI-LO nibble to LO nibble call Nib$out mov a,b ani 0FH jmp Nib$out else jmp Char$out endif Msg$in: ; HL = destination address ; E = # bytes to input call Net$in rc mov m,a inx h dcr e jnz Msg$in ret Net$in: ; byte returned in A register ; D = checksum accumulator if ASCII call Nib$in rc add a add a add a add a push psw call Nib$in pop b rc ora b else call Char$in ;receive byte in Binary mode rc endif chks$in: mov b,a add d ; add & update checksum accum. mov d,a ora a ; set cond code from checksum mov a,b ret Msg$out: ; HL = source address ; E = # bytes to output ; D = checksum ; C = preamble byte mvi d,0 ; initialize the checksum call Pre$Char$out ; send the preamble character Msg$out$loop: mov c,m inx h call Net$out dcr e jnz Msg$out$loop ret page ; Network Initialization ntwrkinit: if cpnos ; copy down network assignments lxi h,Initconfigtbl lxi d,configtbl mvi c,initcfglen initloop: mov a,m stax d inx h inx d dcr c jnz initloop ; initialize config tbl from ROM else mvi a,slave$ID ;initialize slave ID byte sta configtbl+1 ; in the configuration tablee endif ; device initialization, as required if Altos mvi a,047h out 0eh mvi a,1 out 0eh endif if DSC2 and modem mvi a,0ceh out stato mvi a,027h out stato endif if cpnos call loginpr ; login to a master endif initok: xra a ; return code is 0=success ret page ; Network Status ntwrksts: lda network$status mov b,a ani not (rcverr+senderr) sta network$status mov a,b ret ; Return Configuration Table Address cnfgtbladr: lxi h,configtbl ret page ; Send Message on Network sendmsg: ; BC = message addr mov h,b mov l,c ; HL = message address shld msg$adr re$sendmsg: mvi a,max$retries sta retry$count ; initialize retry count send: lhld msg$adr mvi c,ENQ call Char$out ; send ENQ to master mvi d,timeout$retries ENQ$response: call Char$in jnc got$ENQ$response dcr d jnz ENQ$response jmp Char$in$timeout got$ENQ$response: call get$ACK0 mvi c,SOH mvi e,5 call Msg$out ; send SOH FMT DID SID FNC SIZ xra a sub d mov c,a call net$out ; send HCS (header checksum) call get$ACK dcx h mov e,m inx h inr e mvi c,STX call Msg$out ; send STX DB0 DB1 ... mvi c,ETX call Pre$Char$out ; send ETX xra a sub d mov c,a call Net$out ; send the checksum mvi c,EOT call nChar$out ; send EOT call get$ACK ; (leave these ret ; two instructions) get$ACK: call Char$in jc send$retry ; jump if timeout get$ACK0: ani 7fh sui ACK rz send$retry: pop h ; discard return address lxi h,retry$count dcr m jnz send ; send again unles max retries Char$in$timeout: mvi a,senderr if always$retry call error$return jmp re$sendmsg else jmp error$return endif page ; Receive Message from Network receivemsg: ; BC = message addr mov h,b mov l,c ; HL = message address shld msg$adr re$receivemsg: mvi a,max$retries sta retry$count ; initialize retry count re$call: call receive ; rtn from receive is receive error receive$retry: lxi h,retry$count dcr m jnz re$call receive$timeout: mvi a,rcverr if always$retry call error$return jmp re$receivemsg else jmp error$return endif receive: lhld msg$adr mvi d,timeout$retries receive$firstchar: call xcharin jnc got$firstchar dcr d jnz receive$firstchar pop h ; discard receive$retry rtn adr jmp receive$timeout got$firstchar: ani 7fh cpi ENQ ; Enquire? jnz receive mvi c,ACK call nChar$out ; acknowledge ENQ with an ACK call Char$in rc ; return to receive$retry ani 7fh cpi SOH ; Start of Header ? rnz ; return to receive$retry mov d,a ; initialize the HCS mvi e,5 call Msg$in rc ; return to receive$retry call Net$in rc ; return to receive$retry jnz bad$checksum call send$ACK call Char$in rc ; return to receive$retry ani 7fh cpi STX ; Start of Data ? rnz ; return to receive$retry mov d,a ; initialize the CKS dcx h mov e,m inx h inr e call msg$in ; get DB0 DB1 ... rc ; return to receive$retry call Char$in ; get the ETX rc ; return to receive$retry ani 7fh cpi ETX rnz ; return to receive$retry add d mov d,a ; update CKS with ETX call Net$in ; get CKS rc ; return to receive$retry call Char$in ; get EOT rc ; return to receive$retry ani 7fh cpi EOT rnz ; return to receive$retry mov a,d ora a ; test CKS jnz bad$checksum pop h ; discard receive$retry rtn adr lhld msg$adr inx h lda configtbl+1 sub m jz send$ACK ; jump with A=0 if DID ok mvi a,0ffh ; return code shows bad DID send$ACK: push psw ; save return code mvi c,ACK call nChar$out ; send ACK if checksum ok pop psw ; restore return code ret bad$DID: bad$checksum: mvi c,NAK jmp Char$out ; send NAK on bad chksm & not max retries ; ret error$return: lxi h,network$status ora m mov m,a call ntwrkerror ; perform any required device re-init. mvi a,0ffh ret ntwrkerror: ; perform any required device ret ; re-initialization page ; ntwrkwboot: ; This procedure is called each time the CCP is ; reloaded from disk. This version prints "" ; on the console and then checks for mail at the master, ; but anything necessary for restart can be put here. if not cpnos ; NOTE: The following code will not fit in a ; 4K ROM. Consequently, we do not include it ; in the CP/NOS version CPNIOS.ASM. It would ; fit in 5K if it needs to be included in CP/NOS. mvi c,9 lxi d,wboot$msg call BDOS getmail: lda 0ffh sta firstpass restart: lda configtbl+1 ; get slave ID sta Mailmsg+2 ; Mailmsg.sid = configtbl.slaveID mvi c, defaultmaster dorcvmsg: xra a lxi d, Mailmsg stax d ; MSG.FMT = 0 inx d mov a,c stax d ; msg.did = [xx] inx d inx d mvi a,rcvmsg stax d ; msg.fnc = rcvmsg inx d xra a stax d lxi b,Mailmsg call sendmsg ; send message to network inr a jz networkerr lxi b,Mailmsg call receivemsg ; receive message from network inr a jz networkerr lda Mailmsg+4 ora a jnz displaymsg lda Mailmsg+5 inr a jz rcvmsgfailed displaymsg: lxi h,FirstPass inr m jz noCRLF mvi c,conout mvi e,CR call BDOS mvi c,conout mvi e,LF call BDOS noCRLF: lxi h,Mailmsg mvi m,'[' inx h xchg lda Mailmsg+5 lxi h,HexASCIItbl push psw push h ani 0f0h rrc rrc rrc rrc mov c,a mvi b,0 dad b mov a,m stax d inx d pop h pop psw ani 0fh mov c,a dad b mov a,m stax d xchg inx h mvi m,']' inx h mov e,m mvi m,' ' inx h mvi m,'"' inx h mvi d,0 dad d mvi m,'"' inx h mvi m,'$' mvi c,print lxi d,Mailmsg call BDOS jmp restart rcvmsgfailed: lda FirstPass inr a jnz Exit lxi d,rcvmsgfailedmsg jmp prntmsg networkerr: lxi d,networkerrmsg jmp prntmsg rcvmsgerr: lxi d,rcvmsgerrmsg prntmsg: mvi c,print call BDOS ; jmp Exit endif Exit: ret page if cpnos ; ; LOGIN to a Master ; ; Equates ; buff equ 0080h readbf equ 10 active equ 0001$0000b loginpr: mvi c,initpasswordmsglen lxi h,initpasswordmsg lxi d,passwordmsg copypassword: mov a,m stax d inx h inx d dcr c jnz copypassword mvi c,print lxi d,loginmsg call BDOS mvi c,readbf lxi d,buff-1 mvi a,50h stax d call BDOS lxi h,buff mov a,m ; get # chars in the command tail ora a jz dologin ; default login if empty command tail mov c,a ; A = # chars in command tail xra a mov b,a ; B will accumulate master ID scanblnks: inx h mov a,m cpi ' ' jnz pastblnks ; skip past leading blanks dcr c jnz scanblnks jmp prelogin ; jump if command tail exhausted pastblnks: cpi '[' jz scanMstrID mvi a,8 lxi d,passwordmsg+5+8-1 xchg spacefill: mvi m,' ' dcx h dcr a jnz spacefill xchg scanLftBrkt: mov a,m cpi '[' jz scanMstrID inx d stax d ;update the password inx h dcr c jnz scanLftBrkt jmp prelogin scanMstrID: inx h dcr c jz loginerr mov a,m cpi ']' jz prelogin sui '0' cpi 10 jc updateID adi ('0'-'A'+10) and 0ffh cpi 16 jnc loginerr updateID: push psw mov a,b add a add a add a add a mov b,a ; accum * 16 pop psw add b mov b,a jmp scanMstrID prelogin: mov a,b dologin: lxi b,passwordmsg+1 stax b dcx b call sendmsg inr a lxi d,loginfailedmsg jz printmsg lxi b,passwordmsg call receivemsg inr a lxi d,loginfailedmsg jz printmsg lda passwordmsg+5 inr a jnz loginOK jmp printmsg loginerr: lxi d,loginerrmsg printmsg: mvi c,print call BDOS jmp loginpr ; try login again loginOK: lxi h,network$status ; HL = status byte addr mov a,m ori active ; set active bit true mov m,a ret ; ; Local Data Segment ; loginmsg: db cr,lf db 'LOGIN = ' db '$' initpasswordmsg: db 00h ; FMT db 00h ; DID Master ID # db slave$ID ;SID db 40h ; FNC db 7 ; SIZ db 'PASSWORD' ; password initpasswordmsglen equ $-initpasswordmsg loginerrmsg: db lf db 'Illegal LOGIN command.' db '$' loginfailedmsg: db lf db 'LOGIN failed.' db '$' DSEG passwordmsg: ds 1 ; FMT ds 1 ; DID ds 1 ; SID ds 1 ; FNC ds 1 ; SIZ ds 8 ; DAT = password endif end