title 'LEVEL3.ASM' ;************************************************ ;* * ;* LEVEL3.ASM * ;* * ;* X.25 level 3 (packet) protocol handler * ;* (implements single logical channel DTE * ;* for use in a Virtual Call circuit (VC) * ;* or Permanent Virtual Circuit (PVC)) * ;* * ;* rev 1.30 08/21/84 E. Elizondo * ;* * ;* (c) 1984 E. Elizondo - all rights reserved. * ;* * ;* This program may be used freely for non- * ;* commercial applications. It may not be sold * ;* or used for commercial applications without * ;* written permission of the author. * ;* * ;************************************************ ; maclib Z80 ;DR Z80 macro library ; assembly time options false equ 0 true equ not false debug equ false ;display P(s) value ; design parameters n3 equ 2 ;retry count for level 3 timeout kpack equ 4 ;acknowledgement delay count ; X.25 standard parameters: ; logical group & channel number (para 2.4.1) lchan equ 1 ;logical channel 1 lgroup equ 0 ;logical group 0 ; flow control parameters: wsize equ 2 ;window size (para 4.4.1.2) ; packet type identifiers (table 8/X.25) ; bit # 8765$4321 calrid: equ 0000$1011b ;call request calaid: equ 0000$1111b ;call accepted clrrid: equ 0001$0011b ;clear request clrcid: equ 0001$0111b ;clear confirmation intid: equ 0010$0011b ;interrupt intcid: equ 0010$0111b ;interrupt confirmation rrid: equ 0000$0001b ;RR rnrid: equ 0000$0101b ;RNR rstrid: equ 0001$1011b ;reset request rstcid: equ 0001$1111b ;reset confirmation starid: equ 1111$1011b ;restart request stacid: equ 1111$1111b ;restart confirmation diagid: equ 1111$0001b ;diagnostic ; misc constants cr equ 0dh ;carriage ret lf equ 0ah ;line feed ; hooks for main program ; subroutines public initl3 ;initialize level 3 parameters public txdpk ;transmit data packet if avail public rxpk ;receive packet if available public txintp ;transmit interrupt packet public txstar ;transmit restart packet public txclrr ;transmit clear request packet ; addresses public chstat ;level 3 logical channel state public l3stat ;level 3 flow control flags ; level 3 parameters public ps ;P(s) public pr ;P(r) public lastpr ;last rx P(r) public ltxpr ;last tx P(r) public lrxps ;last rx P(s) public ltxps ;last tx P(s) public pvcmod ;PVC mode flag public laddr ;local DTE address public raddr ;remote DTE address public caddr ;rx calling DTE address public laddrl ;local DTE address length public raddrl ;remote DTE address length public caddrl ;rx calling DTE address length public qbit ;Q bit public dbit ;D bit public chan ;logical channel # public group ;logical group # ; diagnostic counters public txpct ;total tx packets public txfpct ;total tx file data packets public txcpct ;total tx console data packets public ntxbct ;errors due to no free tx buffer ; public rxpct ;total rx packets public rxdpct ;total rx data packets public rbfpct ;total rx bad format packets public rbcpct ;total rx bad channel packets public rbapct ;total rx bad address packets public rbipct ;total rx bad id packets public rbgpct ;total rx bad group packets public rxxpct ;total discarded rx packets ; definition of channel status (chstat) bits ; (note that state r1 (packet level ready) ; corresponds to level 2 link conn) ; bit set condition ; 0 flow control ready state (d1) ; 1 DTE restart request state (r2) ; 2 DTE waiting state (p2) ; 3 DTE reset request state (d2) ; 4 DTE clear request state (p6) ; 5 ready (p1) ; 6 undefined ; 7 undefined ; definition of flow control (l3stat) status bits ; bit set condition ; 0 DTE busy ; 1 DCE busy ; 2 DTE interrupt pending confirmation ; 3 undefined ; 4 undefined ; 5 ualled DTE address error semaphore (internal) ; 6 transmission completed - ready to clear ; 7 outgoing message waiting for call setup ; external subroutines ; from buffers module: extrn inibuf ;initialize all buffers extrn putbuf ;put char in buffer extrn getbuf ;get char from buffer extrn topbuf ;put char at beginning of buffer extrn bpoint ;point to selected bcb extrn rlsrxb ;release rx buffer extrn clrbuf ;clear buffer for new use extrn getbct ;get buffer count extrn getrdy ;get state of buffer ready flag extrn setrdy ;set buffer ready flag extrn clrrdy ;clear ready flag ; from level1 module: extrn t20on ;turn on timer T20 extrn t20off ;turn off timer T20 extrn t21on ;turn on timer T21 extrn t21off ;turn off timer T21 extrn t22on ;turn on timer T22 extrn t22off ;turn off timer T22 extrn t23on ;turn on timer T23 extrn t23off ;turn off timer T23 ; from level2 module: extrn gettxb ;get address of free tx bcb ; from files module extrn gfdata ;get byte from transmit file extrn pfdata ;write file to receive file extrn ctxfil ;close transmit file extrn crxfil ;close receive file ; from xutil module: extrn ilprt ;in line print routine extrn ctype ;print char in extrn pdec ;print in decimal extrn phex ;print in hex extrn phex1 ;print nibble in in hex extrn delay ;wait a bit ; external addresses ; from level 1 module extrn tistat ;timer status flags extrn rxstat ;receive status ; from level 2 module extrn lkstat ;level 2 status flags ; from buffers module extrn rxplst ;A(list of rx packt buffer #'s) extrn rxbtab ;A(table of rx bcb pointers) extrn txbtab ;A(table of tx bcb pointers) extrn ctbcb ;A(bcb for console transmit) extrn crbcb ;A(bcb for console receive) ; from files module extrn fstat ;file status flags ; from x25 module extrn l4stat ;level 4 status flags cseg ;code section ; ************************** ; * initialization section * ; ************************** ; initialize level 3 parameters ; (externally and internally called) ; on entry: no parameters ; on exit: all regs, flags clobbered initl3: mvi a,lchan ;get default channel number sta chan ;and initialize logical channel # mvi a,lgroup ;get default group number sta group ;and initialize logical group # mvi a,0000$0001b ;get modulo 8 general format id sta gfi ;initialize gfi call reset ;reset flow control variables xra a sta qbit ;clear Q bit sta dbit ;clear D bit sta chstat ;clear logical channel state sta l3stat ;channel in ready (p1) state ret ; reset flow control variables ; (internally called) ; on entry: no parameters ; on exit: ,flags clobbered ; all other regs unchanged reset: xra a sta pr ;clear P(r) sta ps ;clear P(s) sta lastpr ;clear last rx P(r) sta ltxpr ;and last tx P(r) mvi a,7 ;initialize last rx P(s) sta lrxps ; / sta ltxps ;and last tx P(s) ret **************************** ; * packet transmit section * ; **************************** ; check and process timeout condition or ; transmit data packet if available and ; a) Level 3 timers not timed out ; b) level 2 link is connected ; c) level 3 in data transfer ready state ; d) DCE not busy ; e) new frame P(s) is within window ; f) free tx buffer available ; and either g) transmit file is open ; or h) console transmit buffer is ready ; (file data takes precedence, as it's ; transmitted as a continuous sequence) ; if no I is available, transmit RR or RNR if any ; received I packets need acknowledgement ; (externally called) ; on entry: no parameters ; on exit: all regs, flags clobbered ; txdpk: lxi h,tistat ;point to timer status flags bit 1,m ;timer T20 timed out? jnz t20to ;yes, service it ; bit 2,m ;timer T21 timed out? jnz t21to ;yes, service it ; bit 3,m ;timer T22 timed out? jnz t22to ;yes, service it ; bit 4,m ;timer T23 timed out? jnz t23to ;yes, service it ; lxi h,lkstat ;point to level 2 status bit 2,m ;link connected? rz ;no, return ; lxi h,chstat ;point back to channel status bit 5,m ;ready state (p1)? jnz setup ;yes, see if we want to call ; bit 0,m ;flow control ready state (d1)? rz ;no, return ; lxi h,l3stat ;point to level 3 status bit 1,m ;DCE busy? rnz ;yes, return ; bit 6,m ;message complete? jnz clear ;yes, see if we want to clear ; ; ; did we transmit data packet already? lda ltxps ;get last tx P(s) mov b,a ;save in lda ps ;get current ps cmp b ;same? jz txackp ;yes, we did ; ; check that P(s) is within window lda lastpr ;get last rx P(r) adi wsize+1 ;calculate just past window ani 7 ;..mod 7 mov b,a ;save in lda ps ;get P(s) cmp b ;is P(s)=past top of window? jz txackp ;yes, don't transmit it yet ; txdp0: lxi h,fstat ;point to file status bit 1,m ;tx file open? jz txcdpk ;no, see if console packet avail ; ; transmit disk file data packet ; (default to category A packet) call gettxb ;else get free tx bcb rc ;return if none avail ; xra a ;clear sta qbit ;clear Q bit sta dbit ;clear D bit call octet1 ;assemble octet 1 in call putbuf ;put octet 1 in tx buffer lda chan ;get logical channel # call putbuf ;put octet 2 in tx buffer call octet3 ;assemble octet 3 in setb 4,a ;set M=1 for now call putbuf ;store octet 3 in tx buffer ; fill up user data field in packet mvi b,128 ;max user data octets in packet txdp1: call gfdata ;get data byte from file jz txdp2 ;exit if end of file call putbuf ;else put in buffer dcr b ;is packet full? jnz txdp1 ;no, keep going ; jmp txdp3 ;else exit ; ; end of file - make into category B packet txdp2: call getbuf ;get octet 1 rc ;exit if not there ; mov b,a ;save in call getbuf ;get octet 2 rc ;exit if not there ; mov c,a ;save in call getbuf ;get octet 3 rc ;exit if not there ; res 4,a ;set M=0 call topbuf ;put back octet 3 mov a,c ;get octet 2 call topbuf ;and put it back mov a,b ;get octet 1 setb 6,a ;set D=1 call topbuf ;and put it back call ctxfil ;close tx file ; common exit routine txdp3: call txgo ;transmit packet lda ps ;P(s)=P(s)+1 mod 7 ; if debug ;if debug mode call prtps ;print P(s) endif ; sta ltxps ;update last tx P(s) inr a ;increment P(s) ani 7 ; / sta ps ;update P(s) lhld txfpct ;increment tx file packet count inx h ; / shld txfpct ; / mvi a,kpack ;initiaize ack delay count sta packct ; / call delay ;and wait a bit ret ; transmit console data packet if available ; (internally called) ; on entry: no parameters ; on exit: all regs, flags clobbered ; txcdpk: lxi h,ctbcb ;point to console transmit bcb call getrdy ;is it ready? jz txackp ;no, see if we want to acknowledge ; call gettxb ;else get free tx bcb rc ;return if none avail ; ; this is a category B packet push h ;save bcb address lxi h,qbit ;point to Q bit res 7,m ;set Q=0 lxi h,dbit ;point to D bit ;*** setb 6,m ;set D=1 (if desired) pop h ;restore bcb address call octet1 ;assemble octet 1 in call putbuf ;put octet 1 in tx buffer lda chan ;get logical channel # call putbuf ;put octet 2 in tx buffer call octet3 ;build octet 3 in with M=0 call putbuf ;store in tx buffer mvi b,128 ;max user data octets in packet ; fill user data fields from console tx buffer xchg ;save in lxi h,ctbcb ;point to console transmit bcb txcdp1: call getbuf ;get data byte from console buffer jc txcdp2 ;exit if end of buffer xchg ;restore tx buffer bcb address call putbuf ;else put into tx buffer xchg ;point back to console xmit bcb dcr b ;is packet full? jnz txcdp1 ;no, keep going ; ; common exit routine txcdp2: call clrrdy ;clear console xmit buffer flag xchg ;point back to tx buffer bcb call txgo ;transmit packet lda ps ;P(s)=P(s)+1 mod 7 ; if debug call prtps ;print P(s) endif ; sta ltxps ;update last tx P(s) inr a ;incrment P(s) ani 7 ; / sta ps ;update P(s) lxi h,l4stat ;point to level 4 status setb 0,m ;signal prompt for next packet lhld txcpct ;increment tx console packet count inx h ; / shld txcpct ; / lxi h,l3stat ;point to flow status res 7,m ;reset message waiting flag mvi a,kpack ;initialize ack delay count sta packct ; / ret ; transmit acknowledgement (RR or RNR) packet ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered txackp: lda ltxpr ;get last tx P(r) mov b,a ;save in lda pr ;get current P(r) cmp b ;same? rz ;yes, nothing to acknowledge ; ; check delay count to see if any data packets are coming lda packct ;get delay count dcr a ;decrement it sta packct ; / rnz ;wait a bit till it's 0 ; ; delay completed, transmit acknowledge packet mvi a,kpack ;initialize delay count sta packct ; / lxi h,l3stat ;point to level 3 flow status bit 0,m ;DTE busy? jnz txrnr ;yes, transmit RNR packet ; jmp txrr ;else transmit RR packet ; print P(s) ; (internally called) ; on entry: =P(s) ; on exit: all flags, regs unchanged prtps: push psw ;save P(s) mvi a,'[' call ctype pop psw ;restore P(s) push psw ;and save it again adi '0' ;convert to ASCII call ctype ;display it mvi a,']' call ctype pop psw ;restore P(s) ret ; set up call if in VC mode ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered setup: lxi h,chstat ;point to channel status bit 2,m ;DTE waiting state (p2)? rnz ;yes, do nothing ; lxi h,l3stat ;point to flow status bit 7,m ;message ready? rz ;no, return ; ; ready to set up call res 7,m ;reset message waiting flag lxi h,chstat ;point back to channel status bit 0,m ;flow control ready state (d1)? rnz ;yes, no setup needed ; jmp txcr ;else transmit call request packet ; clear call if in VC mode ; (internally called) clear: lxi h,l3stat ;point to level 3 status res 6,m ;reset message complete flag lda pvcmod ;get VC/PVC mode flag cpi 2 ;PVC? rz ;yes, do nothing if PVC ; jmp txclrr ;else transmit clear request packet ; transmit call request packet ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered txcr: call gettxb ;get free tx bcb jc enotxb ;error if none available ; mvi c,calrid ;get call request id call put3oct ;put octets 1-3 in tx buffer call putaddr ;put address octets in tx buffer ;*** (no facilities or call user data implemented) mvi a,0 ;facilities length=0 call putbuf ;put octet in tx buffer call txgo ;transmit packet call reset ;reset flow control variables call t21on ;start timer T21 lxi h,chstat ;point to channel status bit 0,m ;flow control ready state? rnz ;yes, all done ; setb 2,m ;else signal DTE waiting state (p2) ret ; transmit call accepted packet ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered txca: call gettxb ;get free tx bcb jc enotxb ;error if none available ; mvi c,calaid ;get call accepted id call put3oct ;put octets 1-3 in tx buffer call putaddr ;put address octets in tx buffer ;*** (no facilities implemented) call txgo ;transmit packet ret ; transmit clear request packet ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered txclrr: call gettxb ;get free tx bcb jc enotxb ;error if none available ; mvi c,clrrid ;get clear request id call put3oct ;put octets 1-3 in tx buffer mvi a,0 ;clearing cause=0 for DTE call putbuf ;put octet 4 in tx buffer call txgo ;transmit packet call reset ;reset flow control variables call t23on ;start timer T23 lxi h,chstat ;indicate DTE clear reqest state (P6) setb 4,m call ctxfil ;close transmit file call crxfil ;and receive file ret ; transmit clear confirmation packet ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered txclrc: call gettxb ;get free tx bcb jc enotxb ;error if none available ; mvi c,clrcid ;get clear confirmation id call put3oct ;put octets 1-3 in tx buffer call txgo ;transmit packet ret ; transmit interrupt packet ; (externally called) ; on entry: =interupt user data for octet 4 ; on exit: all flags, regs clobbered txintp: lxi h,lkstat ;point to level 2 status bit 2,m ;link connected? jnz txint1 ;yes, keep going ; call ilprt ;else tell operator db 'L3: link not connected - ',0 jmp txint5 ;and exit ; txint1: lxi h,chstat ;point to channel status bit 0,m ;flow control ready state? jnz txint2 ;yes, keep going ; call ilprt ;else tell operator db 'L3: link not in data xfer state - ',0 jmp txint5 ;and exit txint2: lxi h,l3stat ;point to level 3 flow status bit 2,m ;interrupt already pending jz txint3 ;no, keep going ; call ilprt ;else tell operator db 'L3: DTE interrupt is pending - ',0 txint5: call ilprt db 'cannot send interrupt',cr,lf,0 ret txint3: call gettxb ;get free tx bcb jc enotxb ;error if none available ; mvi c,intid ;get interrupt id call put3oct ;put octets 1-3 in tx buffer mov a,b ;get interrupt user data call putbuf ;put octet 4 in tx buffer call txgo ;transmit packet lxi h,l3stat ;point to level 3 flow status setb 2,m ;set interrupt pending flag ret ; transmit interrupt confirmation packet ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered txintc: call gettxb ;get free tx bcb jc enotxb ;error if none available ; mvi c,intcid ;get interrupt confirmation id call put3oct ;put octets 1- 3 in tx buffer call txgo ;transmit packet ret ; transmit RR packet ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered txrr: mvi c,rrid ;=RR packet identifier jmp txrcom ;and do common stuff ; transmit RNR packet ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered txrnr: mvi c,rnrid ;=RNR packet identifier ; ; common stuff for RR and RNR ; on entry: =packet identifier txrcom: call gettxb ;get free tx bcb jc enotxb ;error if none available ; xra a ;clear Q and D bits sta qbit ; / sta dbit ; / call octet1 ;assemble octet 1 in call putbuf ;put octet 1 in tx buffer lda chan ;get logical channel # call putbuf ;put octet 2 in tx buffer lda pr ;get P(r) sta ltxpr ;update last tx P(r) rlc ;move to bits 8-6 rlc ; / rlc ; / rlc ; / rlc ; / ani 1110$0000b ;zero other bits ora c ;merge with P(r) call putbuf ;put octet 3 in tx buffer call txgo ;transmit packet ret ; transmit reset request packet ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered txrstr: call gettxb ;get free tx bcb jc enotxb ;error if none available ; mvi c,rstrid ;get reset request id call put3oct ;put octets 1-3 in tx buffer mvi a,0 ;resetting cause=0 for DTE call putbuf ;put octet 4 in tx buffer call txgo ;transmit packet call reset ;reset flow control variables call t22on ;start timer T22 lxi h,chstat ;point to channel status setb 3,m ;signal reset request state ret ; transmit reset confirmation packet ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered txrstc: call gettxb ;get free tx bcb jc enotxb ;error if none available ; mvi c,rstcid ;get reset confirmation id call put3oct ;put octets 1-3 in tx buffer call txgo ;and transmit packet ret ; transmit restart request packet ; (internally & externally called) ; on entry: no parameters ; on exit: all flags, regs clobbered txstar: lxi h,lkstat ;point to level 2 status bit 2,m ;link connected? jnz txstar1 ;yes, keep going ; call ilprt ;else tell operator db 'L3: link not connected',cr,lf,0 ret ; txstar1: call gettxb ;get free tx bcb jc enotxb ;error if none available ; mvi c,starid ;get restart request packet id call txscom ;do common stuff mvi a,0 ;set restarting cause=0 for DTE call putbuf ; / call txgo ;transmit packet call reset ;reset flow control variables lxi h,chstat ;point to channel status setb 1,m ;indicate restart request state call t20on ;start timer T20 call t21off ;and stop all others call t22off ; / call t23off ; / ret ; transmit restart confirmation packet ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered txstac: call gettxb ;get free tx bcb jc enotxb ;error if none available ; mvi c,stacid ;get restart confirmation id call txscom ;do common stuff call txgo ;transmit packet ret ; common stuff for restart request/confirmation ; on entry: =packet id txscom: lda gfi ;get general format identifier rlc ;move to bits 8-5 rlc ; / rlc ; / rlc ; / ani 1111$0000b ;make sure lower bits are all 0 call putbuf ;put octet 1 in tx buffer xra a ;next octet is all 0's call putbuf ;put octet 2 in tx buffer mov a,c ;get packet identifier call putbuf ;put octet 3 in tx buffer ret ; error handling routine for no available free tx buffer ; (internally called) enotxb: lhld ntxbct ;increment error count inx h ; / shld ntxbct ; / ret ; ***************************************** ; * utility routines for tx section * ; ***************************************** ; transmit packet ; (internally called) ; on entry: =address of tx buffer bcb ; on exit: all regs, flags clobbered txgo: call setrdy ;set tx buffer ready flag lhld txpct ;increment total tx packet count inx h ; / shld txpct ; / ret ; put octets 1-3 in tx buffer ; (internally called) ; on entry: =bcb address of tx buffer ; =packet identifier ; on exit: ,flags clobbered ; all other regs unchanged put3oct: xra a ;clear Q and D bits sta qbit ; / sta dbit ; / call octet1 ;assemble octet 1 in call putbuf ;put octet 1 in tx buffer lda chan ;get logical channel # call putbuf ;put octet 2 in tx buffer mov a,c ;get packet identifier call putbuf ;put octet 3 in tx buffer ret ; build octet 1 ; (internally called) ; on entry: no parameters ; on exit: =octet 1 ; flags clobbered ; all other regs unchanged octet1: push b ;save lda gfi ;get general format identifier rlc ;move to bits 8-5 rlc ; / rlc ; / rlc ; / mov b,a ;save result in lda qbit ;get q bit ora b ;merge with gfi mov b,a ;and save result in lda dbit ;get d bit ora b ;merge with gfi ani 0f0h ;make sure lower 4 bits are 0 mov b,a ;and save result in lda group ;get logical group # ani 0fh ;zero upper 4 bits ora b ;merge with gfi pop b ;restore ret ; build octet 3 of data packet ; (internally called) ; on entry: no parameters ; on exit: = octet 3 ; all other regs unchanged octet3: push b ;save lda pr ;get P(r) sta ltxpr ;update last tx P(r) rlc ;move to bits 8-6 rlc ; / rlc ; / rlc ; / rlc ; / ani 1110$0000b ;zero other bits mov b,a ;save result in lda ps ;get P(s) rlc ;move to bits 4-2 ani 0000$1110b ;zero other bits ora b ;merge with P(r) and M pop b ;restore ret ; put address octets in tx buffer ; (internally called) ; on entry: =tx bcb address ; on exit: ,flags clobbered ; all other regs unchanged putaddr: push b ;save push d ;save ; ; build octet 4 in tx buffer lda laddrl ;get local address length rlc ;move to bits 8-5 rlc ; / rlc ; / rlc ; / ani 1111$0000b ;make sure lower 4 bits are 0 mov b,a ;save result in lda raddrl ;get remote address length ani 0000$1111b ;make sure upper 4 bits are 0 ora b ;merge with local address length call putbuf ;put octet 4 in tx buffer ; ; now build called DTE address, if present lda raddrl ;get remote address length ora a ;length=0? jz putad2 ;yes, skip remote address ; mov b,a ;save length in lxi d,raddr ;point to remote address putad1: ldax d ;get first char rlc ;move to bits 8-5 rlc ; / rlc ; / rlc ; / ani 1111$0000b ;make sure lower bits are 0 mov c,a ;save result in inx d ;point to next address digit dcr b ;last digit? jz putad3 ;yes, get local address ; ldax d ;else get next char ani 0000$1111b ;make sure upper bits are 0 ora c ;merge with last digit call putbuf ;and put in tx buffer inx d ;point to next address digit dcr b ;last digit jnz putad1 ;no, get another ; ; ; build calling DTE address, if present ; entry point if called DTE address is even # of digits putad2: lda laddrl ;get local address length ora a ;length=0? jz putadexi ;yes, exit ; mov b,a ;else save length in lxi d,laddr ;point to local address jmp putad4 ;and keep going ; ; entry point if called DTE address is odd # of digits putad3: lda laddrl ;get local address length ora a ;length=0? jz putadexi ;yes, exit ; mov b,a ;else save length in lxi d,laddr ;point to local address jmp putad5 ;and keep going ; ; build msb digit putad4: ldax d ;get first char rlc ;move to bits 8-5 rlc ; / rlc ; / rlc ; / ani 1111$0000b ;make sure lower bits are 0 mov c,a ;save result in inx d ;point to next address digit dcr b ;last digit? jnz putad5 ;no, get next character ; call putbuf ;else put last octet in tx buffer jmp putadexi ;and exit ; ; build lsb digit putad5: ldax d ;get next char ani 0000$1111b ;make sure upper bits are 0 ora c ;merge with last digit call putbuf ;and put in tx buffer inx d ;point to next address digit dcr b ;last digit jnz putad4 ;no, get another ; ; common exit putadexi: pop d ;restore pop b ;restore ret ; ************************* ; * process timeouts * ; ************************* ; process timeout of DTE timer T20 ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered t20to: call t20off ;turn off timer lxi h,rtryct ;get retry count dcr m ;last retry? jz t20to1 ;yes, other end is dead ; call ilprt ;else try once more db 'L3: T20 timed out - ' db 'retransmitting restart request packet',cr,lf,0 call t20on ;restart timer T20 jmp txstar ;and transmit restart ; t20to1: call ilprt db 'L3: tx retry count exhausted - ' db 'no reply from DCE',cr,lf,0 ret ; process timeout of DTE timer T21 ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered t21to: call t21off ;turn off timer call ilprt ;and tell operator db 'L3: T21 timed out - ' db 'transmitting clear request packet',cr,lf,0 jmp txclrr ;and transmit clear request ; process timeout of DTE timer T22 ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered t22to: call t22off ;turn off timer lxi h,rtryct ;get retry count dcr m ;last retry? jz t22to1 ;yes, other end is dead ; call ilprt ;else try once more db 'L3: T22 timed out - ' db 'retransmitting reset request packet',cr,lf,0 call t22on ;restart timer T22 jmp txrstr ;and transmit reset request ; t22to1: call ilprt db 'L3: tx retry count exhausted - ' db 'logical channel out of order',cr,lf,0 ret ; process timeout of DTE timer T23 ; (internally called) ; on entry: no parameters ; on exit: all flags, regs clobbered t23to: call t23off ;turn off timer lxi h,rtryct ;get retry count dcr m ;last retry? jz t23to1 ;yes, other end is dead ; call ilprt ;else try once more db 'L3: T23 timed out - ' db 'retransmitting clear request packet',cr,lf,0 call t23on ;restart timer T23 jmp txclrr ;transmit clear request ; t23to1: call ilprt db 'L3: tx retry count exhausted - ' db 'logical channel out of order',cr,lf,0 ret ; *************************** ; * packet receive section * ; *************************** ; receive packet if available ; on entry: no parameters ; on exit: =bcb address if packet avail ; = packet octet # 3 (packet id) ; = rx buffer # rxpk: lxi h,rxplst ;point to received packet list call getbuf ;any there? rc ;no, exit ; lhld rxpct ;increment rx packet count inx h ; / shld rxpct ; / ; mov c,a ;else save rx buffer # in lxi h,rxbtab ;get buffer bcb address call bpoint ; / call getbuf ;get octet 1 jc rxfmer ;format error if not there ; mov d,a ;save octet 1 in call getbuf ;get octet 2 jc rxfmer ;format error if not there ; mov e,a ;save octet 2 in call getbuf ;get octet 3 jc rxfmer ;format error if not there ; mov b,a ;save octet 3 in cpi starid ;restart request? jz chkrst ;yes, check format ; cpi stacid ;restart confirmation jz chkrst ;yes, check format ; cpi diagid ;diagnostic jz chkrst ;yes, check format ; ; process packets having logical group and channel lda chan ;get logical channel # cmp e ;match? jnz rxcher ;no, channel # error ; mov a,d ;get back octet 1 ani 0011$0000b ;get bits 6-5 cpi 0001$0000b ;numbering modulo 8? jnz rxfmer ;no, format error ; mov a,d ;get back octet 1 ani 0000$1111b ;get bits 4-1 push b ;save mov b,a ;save logical group # in lda group ;get our logical group # cmp b ;same? pop b ;restore jnz rxgrer ;no, group # error ; ; branch to process known packet types mov a,b ;get back octet 3 bit 0,a ;data packet? jz rxdata ;yes, process it ; cpi intid ;interrupt packet? jz rxint ;yes, process it ; cpi intcid ;interrupt confirmation? jz rxintc ;yes, process it ; cpi rstrid ;reset request? jz rxrstr ;yes, process it ; cpi rstcid ;reset confirmation? jz rxrstc ;yes, process it ; cpi calrid ;call request? jz rxcr ;yes, process it ; cpi calaid ;call accepted? jz rxca ;yes, process it ; cpi clrrid ;clear request? jz rxclr ;yes, process it ; cpi clrcid ;clear confirmation? jz rxclc ;yes, process it ; ; process packets numbered modulo 8 rxpk3: ani 0001$1111b ;leave only bits 5-1 cpi rrid ;RR jz rxrr ;yes, process it ; cpi rnrid ;RNR? jz rxrnr ;yes, process it ; jmp rxpk4 ;else process id error ; check format of restart and diagnostic packets chkrst: mov a,d ;get back octet 1 cpi 0001$0000b ;modulo 8 format? jnz rxfmer ;no, format error ; mov a,e ;get back octet 2 ora a ;all zero? jnz rxfmer ;no, format error ; ; now branch to known restart packet types mov a,b ;get back octet 3 cpi starid ;restart? jz rxstar ;yes, process it ; cpi stacid ;restart confirmation? jz rxstac ;yes, process it ; cpi diagid ;diagnostic? jz rxdiag ;yes, process it ; else id is unrecognized so drop through to ; ; process unrecognized id error rxpk4: call flush ;discard packet lhld rbipct ;increment bad id counter inx h ; / shld rbipct ; / ret ; process packet format error rxfmer: call flush ;discard packet lhld rbfpct ;increment bad format counter inx h ; / shld rbfpct ; / ret ; process packet group error rxgrer: call flush ;discard packet lhld rbgpct ;increment bad group counter inx h ; / shld rbgpct ; / ret ; process packet channel error rxcher: call flush ;discard packet lhld rbcpct ;increment bad channel counter inx h ; / shld rbcpct ; / ret ; process rx data packet ; (internally called) ; on entry: =rx buffer bcb address ; =packet octet #3 ; =rx buffer # ; on exit: all regs, flags clobbered rxdata: xchg ;save bcb address lxi h,chstat ;point to channel state bit 0,m ;flow control ready state? xchg ;get back bcb address jz flush ;no, discard packet ; call ackd ;process P(s) and P(r) jc dterst ;reset channel if invalid ; xchg ;save bcb address lxi h,fstat ;point to file status bit 0,m ;receive file open? xchg ;restore bcb address jnz rxfdat ;yes, write packet in file ; ; else write packet to console receive buffer lxi d,crbcb ;point to console rx buffer rxcdat: call getbuf ;get data octet from rx buffer jc rxcd1 ;exit when empty ; xchg ;point to console rx buffer call putbuf ;put octet in console rx buffer xchg ;point back to rx buffer jmp rxcdat ;and go back for more ; ; process end of packet to console rxcd1: xchg ;point to console rx buffer call setrdy ;set buffer ready flag jmp rxdexi ;do common exit stuff ; write packet into disk file rxfdat: call getbuf ;get data octet from rx buffer jc rxfd1 ;exit if empty ; call pfdata ;else put data in file jmp rxfdat ;and loop until empty ; ; process end of rx packet data rxfd1: mvi a,'+' ;tell console packet rx call ctype ; / jmp rxdexi ;do common exit stuff ; common exit for rx packet data rxdexi: mov a,c ;get rx buffer # call rlsrxb ;release rx buffer lhld rxdpct ;increment rx data packet count inx h ; / shld rxdpct ; / ret ; process rx incoming call packet ; (internally called) ; on entry: =bcb address ; =packet octet 3 (id) ; =rx buffer # rxcr: call getbuf ;get octet 4 jc rxfmer ;format error if not there ; sta rxoc4 ;save the octet xchg ;save bcb address lxi h,chstat ;point to channel status bit 0,m ;flow control ready state (d1)? jnz rxcr1 ;yes, accept packet ; bit 1,m ;DTE restart request state (r2)? jnz flush ;yes, discard packet ; bit 2,m ;waiting state (p2)? jnz rxcr1 ;yes, accept packet ; bit 3,m ;reset request state (d2)? jnz rxcr1 ;yes, accept packet ; bit 4,m ;clear request state (p6)? jnz rxcr1 ;yes, accept packet ; bit 5,m ;ready state (p1)? jnz rxcr1 ;yes, accept packet ; jmp flush ;else discard packet ; rxcr1: xchg ;get back bcb address call chkcadr ;check whether address is for us jc badadr ;refuse call if invalid ; call getbuf ;get facilities length octet jc rxfmer ;format error if not there ; ;*** special facilities not implemented ora a ;facilities requested? jnz calrej ;yes, refuse call ; mov a,c ;get rx buffer # call rlsrxb ;release it call reset ;reset flow control variables call t21off ;turn off timer T21 call t22off ;turn off timer T22 call t23off ;turn off timer T23 call ilprt db 'L3: rx incoming call ',0 lda caddrl ;get calling DTE address length ora a ;=0? jz rxca3 ;yes, keep going ; inr a ;increment length by one mov b,a ;and save in call ilprt ;display calling address db 'from: ',0 lxi h,caddr ;point to calling address rxca2: dcr b ;end of address? jz rxca3 ;yes, exit loop ; mov a,m ;else get nibble call phex1 ;display it in hex inx h ;bump pointer jmp rxca2 ;and get next nibble ; rxca3: call ilprt ;terminate message db cr,lf,0 lxi h,l3stat ;point to flow status res 1,m ;reset DCE busy flag res 2,m ;reset interrupt pending flag res 6,m ;reset end of message flag lxi h,chstat ;point to channel status setb 0,m ;set flow control ready state (d1) res 3,m ;reset DTE reset request state (d2) res 4,m ;reset DTE clear request state (p6) res 5,m ;reset ready state (p1) bit 2,m ;DTE waiting state (p2)? jz txca ;no, tx call accepted packet ; ; call collision state (p5) res 2,m ;else reset state p2 ret ;and exit ; process rx call connected packet ; (internally called) ; on entry: =bcb address ; =packet octet 3 (id) ; =rx buffer # rxca: xchg ;save bcb address lxi h,chstat ;point to channel status bit 2,m ;DTE waiting state (p2)? jnz rxca0 ;yes, accept packet ; jmp flush ;else discard packet ; rxca0: xchg ;get back bcb address call getbuf ;get octet 4 if present jc rxca1 ;skip address check if not present ; sta rxoc4 ;save octet 4 if present call chkadr ;check addresses jc badadr ;refuse call if invalid ; call getbuf ;get octet 5 if present jc rxca1 ;skip facilities check if not present ; ;*** special facilities not implemented ; ; checks all done, accept call rxca1: mov a,c ;get rx buffer # call rlsrxb ;release it call reset ;reset flow control variables call t21off ;turn off timer T21 call t22off ;turn off timer T22 call t23off ;turn off timer T23 call ilprt db 'L3: rx call connected',cr,lf,0 lxi h,l3stat ;point to flow control status res 1,m ;reset DCE busy flag res 2,m ;reset interrupt pending flag res 6,m ;reset message complete flag lxi h,chstat ;point to channel status setb 0,m ;set flow control ready state (d1) res 2,m ;reset DTE waiting state (p2) res 3,m ;reset DTE reset request state (d2) res 4,m ;reset DTE clear request state (p6) res 5,m ;reset ready state (p1) ret ;and exit ; process invalid address ; (internally called) ; on entry: =rx buffer # ; on exit: all flags, regs clobbered ; badadr: call flush ;discard packet lhld rbapct ;increment bad address count inx h ; / shld rbapct ; / call ilprt db 'L3: bad address - tx clear request',cr,lf,0 jmp txclrr ;transmit clear request ; refuse call ; (internally called) ; on entry: =rx buffer # ; on exit: all flags, regs clobbered calrej: call flush ;discard packet call ilprt db 'L3: call refused - tx clear request',cr,lf,0 jmp txclrr ;transmit clear request ; process rx clear indication (clear request) packet ; (internally called) ; on entry: =bcb address ; =packet octet 3 (id) ; =rx buffer # rxclr: call getbuf ;get octet 4 jc rxfmer ;format error if not there ; mov b,a ;save octet 4 in xchg ;save bcb address lxi h,chstat ;point to channel status bit 0,m ;flow control ready state (d1)? jnz rxclr0 ;yes, accept packet ; bit 4,m ;clear request state (p6)? jnz rxclr0 ;yes, accept packet ; jmp flush ;else discard packet ; rxclr0: xchg ;restore bcb address call ilprt ;tell operator db 'L3: rx clear indication packet, cause: ',0 mov a,b ;get back octet 4 call phex ;print in hex call ilprt ; / db ' (hex)',cr,lf,0 ; / call getbuf ;get octet 5 jc rxclr2 ;keep going if not there ; mov b,a ;save octet 5 in call ilprt db ' diagnostic code : ',0 mov l,b ;print diagnostic code mvi h,0 ; / call pdec ;print in decimal call ilprt db cr,lf,0 ; ; perform flow control actions rxclr2: mov a,c ;get rx buffer # call rlsrxb ;and release it call reset ;reset flow control variables call t21off ;stop timers call t22off ; / call t23off ; / call ctxfil ;close transmit file call crxfil ;close receive file lxi h,chstat ;point to channel status res 0,m ;reset state d1 res 2,m ;reset state p2 res 3,m ;reset state d2 setb 5,m ;set ready state p1 bit 4,m ;was it DTE clear request state (p6)? jz txclrc ;no, tx clear confirmation packet ; ; DTE clear request state (p6) res 4,m ;else reset clear request state ret ;and exit ; process rx clear confirmation packet ; (internally called) ; on entry: =bcb address ; =packet octet 3 (id) ; =rx buffer # rxclc: call getbuf ;get octet 4 jnc rxfmer ;format error if there ; lxi h,chstat ;point to channel status bit 4,m ;DTE clear request state (p6)? jz flush ;no, discard packet ; ; DTE clear request state (p6) res 4,m ;reset back to ready state mov a,c ;get rx buffer # call rlsrxb ;and release it call reset ;reset flow control variables call ilprt ;tell operator db 'L3: rx clear confirmation packet',cr,lf,0 ret ; process rx INT packet ; (internally called) ; on entry: =bcb address ; =rx buffer # rxint: call getbuf ;get octet 4 jc rxfmer ;format error if not there ; xchg ;save bcb address in lxi h,chstat ;point to channel status bit 0,m ;flow control ready state (d1)? jz flush ;no, discard packet ; xchg ;restore bcb address mov b,a ;save octet 4 in call ilprt db 'L3: rx INT packet - user data: ',0 mov a,b ;get back octet 4 call phex ;print in hex call ilprt ;terminate line db cr,lf,0 mov a,c ;get rx buffer # call rlsrxb ;release it jmp txintc ;and transmit int confirmation ; process rx INT confirmation packet ; (internally called) ; on entry: =bcb address ; =rx buffer # rxintc: call getbuf ;tryto get octet 4 jnc rxfmer ;format error if there ; lxi h,chstat ;point to channel status bit 0,m ;flow control ready state (d1)? jz flush ;no, discard packet ; lxi h,l3stat ;point to level 3 status bit 2,m ;interrupt pending? jz flush ;no, discard packet ; res 2,m ;else clear int pending flag call ilprt db 'L3: rx interrupt confirmation packet',cr,lf,0 mov a,c ;get rx buffer # call rlsrxb ;release it ret ; process DIAG packet ; (internally called) ; on entry: =bcb address ; =packet octet #3 (packet id) ; =rx buffer # rxdiag: call getbuf ;get octet 4 jc rxfmer ;format error if not there ; xchg ;save bcb address in mov b,a ;save octet 4 in call ilprt db 'L3: rx DIAG packet - diagnostic # ',0 mov l,b ;print diagnostic code mvi h,0 ; / call pdec ; / call ilprt ;print explanation if present db cr,lf,'L3: diagnostic explanation: ',0 xchg ;get back bcb address ; print diagnostic explanation diaglp: call getbuf ;get next octet jc diagexi ;exit if not there ; call phex ;print in hex call ilprt ;and separator db ' ',0 jmp diaglp ;and try for next byte ; diagexi: call ilprt ;terminate explanation line db cr,lf,0 mov a,c ;get rx buffer call rlsrxb ;release it ret ; process rx RR packet ; (internally called) ; on entry: =octet 3 ; =rx buffer # rxrr: lxi h,chstat ;point to channel status bit 0,m ;flow control ready state? jz flush ;no, discard packet ; call chkpr ;check P(r) and update window jc dterst ;local procedure error ; lxi h,l3stat ;point to level 3 status res 1,m ;clear DCE busy mov a,c ;release rx buffer call rlsrxb ; / ret ; process rx RNR packet ; (internally called) ; on entry: =octet 3 ; =rx buffer # rxrnr: lxi h,chstat ;point to channel status bit 0,m ;flow control ready state? jz flush ;no, discard packet ; call chkpr ;check P(r) & update window jc dterst ;local procedure error ; lxi h,l3stat ;point to level 3 status setb 1,m ;signal DCE busy mov a,c ;release rx buffer call rlsrxb ; / ret ; process received reset indication ; (internally called) ; on entry: =octet 3 ; =rx buffer # rxrstr: lxi h,chstat ;point to channel status bit 3,m ;reset request state (d2)? jnz rxstr0 ;yes, accept packet ; bit 0,m ;flow control ready state (d1) jnz rxstr1 ;yes, accept packet ; jmp flush ;else discard packet ; ; reset collision (para 4.4.3.3) rxstr0: res 3,m ;clear reset request state setb 0,m ;set flow control ready state d1 call t22off ;stop timer T22 mov a,c ;get rx buffer # call rlsrxb ;release buffer ret ;and exit ; ; DTE in flow control ready (d1) state rxstr1: mov a,c ;release rx buffer call rlsrxb ; / call reset ;reset flow control variables lxi h,l3stat ;point to level 3 status res 1,m ;clear DCE busy status jmp txrstc ;and transmit reset confirmation ; process received reset confirmation ; (internally called) ; on entry: =octet 3 ; =rx buffer # rxrstc: lxi h,chstat ;point to channel status bit 3,m ;DTE reset request state? jz flush ;no, discard packet ; ; DTE in reset request state (d2) res 3,m ;clear state d2 setb 0,m ;set state d1 call t22off ;stop timer T22 mov a,c ;get rx buffer # call rlsrxb ;release buffer lxi h,l3stat ;point to level 3 status res 1,m ;clear DCE busy status ret ;and exit ; ; process received restart indication ; (internally called) ; on entry: =octet 3 ; =rx buffer # rxstar: lxi h,chstat ;point to channel status res 0,m ;clear state d1 for now res 2,m ;and state p2 res 3,m ;and state d2 res 4,m ;and state p6 setb 5,m ;set ready state p1 lda pvcmod ;get pvc mode flag cpi 1 ;VC? jz rstar1 ;yes, keep going ; ; set flow control ready if in PVC mode res 5,m ;reset ready state p1 setb 0,m ;and set flow control state d1 ; rstar1: mov a,c ;release buffer call rlsrxb ; / bit 1,m ;DTE restart request state (r2)? jz rstar2 ;no, keep going ; ; DTE in restart request state (r2) res 1,m ;clear state r2 call t20off ;stop timer T20 ret ;and exit ; ; DTE not in restart request state rstar2: call reset ;reset flow control variables lxi h,l4stat ;point to level 4 status setb 0,m ;signal console prompt ;*** do other things here? ; call ilprt db 'L3: rx restart',cr,lf,0 jmp txstac ;and transmit restart confirmation ; process received restart confirmation ; (internally called) ; on entry: =octet 3 ; =rx buffer # rxstac: lxi h,chstat ;point to channel status bit 1,m ;DTE restart request state? jz flush ;no, discard packet ; ; DTE in restart request state (r2) res 0,m ;clear state d1 for now res 1,m ;and state r2 res 2,m ;and state p2 res 3,m ;and state d2 res 4,m ;and state p6 setb 5,m ;set ready state p1 lda pvcmod ;get PVC mode flag cpi 1 ;VC? jz rstac1 ;yes, keep going ; ; set flow control ready if in PVC mode res 5,m ;reset ready state p1 setb 0,m ;and set flow control state d1 ; rstac1: call t20off ;stop timer T20 mov a,c ;get rx buffer # call rlsrxb ;release buffer lxi h,l4stat ;point to level 4 status setb 0,m ;signal console prompt ret ;and exit ; ; reset DTE dterst: mov a,c ;release buffer call rlsrxb ; / call ilprt db cr,lf,'L3: local procedure error - ' db 'resetting channel',cr,lf,0 call reset ;reset flow control variables jmp txrstr ;and transmit reset request ; ************************************************* ; * utility subroutines for receive section * ; ************************************************* ; discard data packet ; (internally called) ; on entry: =rx buffer # ; on exit: all regs, flags clobbered flush: mov a,c ;get rx buffer # call rlsrxb ;release it lhld rxxpct ;increment discarded packet count inx h ; / shld rxxpct ; / ret ; acknowledge received data packet & update window ; (internally called) ; on entry: =octet 3 of data packet ; on exit: carry set if P(s) or P(r) sequence error ; , other flags clobbered ; all other regs unchanged ackd: push h ;save regs push d ; / push b ; / call chkpr ;check P(r) and update window jc ackdexi ;exit with carry if invalid P(s) ; check for valid rx P(s) mov a,b ;get octet 3 ani 0000$1110b ;extract rx P(s) rrc ;move to bits 0-2 mov c,a ;save rx P(s) in ; ; check for P(s) next in sequence lda lrxps ;get last rx P(s) inr a ;bump mod 7 ani 7 ; / cmp c ;next in sequence? jnz ackderr ;no, invalid ; ; calculate top of valid range for rx P(s) lda pr ;get local P(r) adi wsize+1 ;add window size+1 ani 7 ;mod 7 mov e,a ;and save in ; ; check for rx P(s) within window lda pr ;bottom edge= local P(r) ackd3: cmp e ;past top of window? jz ackderr ;yes, error ; cmp c ;rx P(s) at bottom edge? jz ackdok ;yes, valid rx P(r) ; inr a ;else bump bottom edge ani 7 ; / jmp ackd3 ;and keep looping ; ; valid rx P(s) ackdok: mov a,c ;get rx P(s) sta lrxps ;update last rx P(s) inr a ;let P(r)=P(s)+1.. ani 7 ;..mod 7 sta pr ;and update P(r) stc ;clear carry bit cmc ; / jmp ackdexi ;and exit ; ; invalid rx P(s) ackderr: stc ;set carry bit ; common exit ackdexi: pop b ;restore regs pop d ; / pop h ; / ret ; check received P(r) and update window if valid ; (internally called) ; on entry: =octet 3 of rx packet ; on exit: carry set if invalid rx P(r) ; ,other flags clobbered ; all other regs unchanged chkpr: push h ;save regs push d ; / push b ; / mov a,b ;get octet 3 ani 1110$0000b ;extract rx P(r) rrc ;move to bits 0-2 rrc ; / rrc ; / rrc ; / rrc ; / mov c,a ;save rx P(r) in lda lastpr ;get last rx P(r) cmp c ;same as this one? jz chkexi ;yes, nothing new ; ; calculate top of valid range for rx P(r) lda ps ;get local P(s) inr a ;increment mod 7... inr a ;..past top of valid range ani 7 ; / mov e,a ;save in ; ; check for rx P(r) within window lda lastpr ;bottom edge=last rx P(r) chkpr1: cmp e ;past top of window? jz chkerr ;yes, invalid cmp c ;rx P(r) at bottom edge? jz chkpr2 ;yes, valid inr a ;else bump bottom edge ani 7 ;mod 7 jmp chkpr1 ;and keep looping ; ; valid rx P(r) chkpr2: mov a,c ;get rx P(r) sta lastpr ;update lower window edge xra a ;clear carry flag jmp chkexi ;and exit ; ; invalid rx P(r) chkerr: stc ;set carry flag ; ; common exit chkexi: pop b ;restore regs pop d ; / pop h ; / ret ; check for valid local DTE address in call request packet ; (internally called) ; on entry: =bcb address ; =rx buffer # ; on exit: carry set if address is invalid ; ,flags clobbered ; all other regs unchanged chkcadr: push b ;save regs push d ; / push h ; / lxi h,l3stat ;point to level 3 status res 5,m ;clear address error flag pop h ;restore bcb address lda rxoc4 ;get rx address length octet mov b,a ;save in call getmsn ;get high nibble sta caddrl ;store calling address length mov a,b ;get back octet 4 ani 0000$1111b ;get called address length mov b,a ;save it in lda laddrl ;get our address length cmp b ;same? cnz adderr ;no, signal error lxi d,laddr ; points to our address inr b ;bump received called address length ; ; check to see if called address is ours laddr1: dcr b ;last called address byte? jz caddr1 ;yes, go read calling address ; call getbuf ;else get next address octet cc adderr ;signal error if not there mov c,a ;save octet in call getmsn ;get high nibble xchg ;point to our address cmp m ;match? cnz adderr ;no, signal error xchg ;point back to bcb inx d ;bump pointers dcr b ;last called address byte? jz caddr0 ;yes, go read calling address ; mov a,c ;get back octet ani 0000$1111b ;get low nibble xchg ;point to our address cmp m ;match? cnz adderr ;no, signal error xchg ;point back to bcb inx d ;bump pointer jmp laddr1 ;and look for next octet ; ; read and store calling address if at high nibble caddr0: lda caddrl ;get calling address length mov b,a ;save in lxi d,caddr ;point to calling address buffer inr b ;bump received calling address length jmp caddr3 ;and keep going ; ; read and store calling address if at low nibble caddr1: lda caddrl ;get calling address length mov b,a ;save in lxi d,caddr ;point to calling address buffer inr b ;bump received calling address length ; ; read address if at low nibble caddr2: dcr b ;last address nibble? jz cadexi ;yes, exit ; call getbuf ;get next octet cc adderr ;else signal error mov c,a ;save in call getmsn ;get high nibble stax d ;save at pointer location inx d ;bump pointers ; ; read address if at high nibble caddr3: dcr b ;last address nibble? jz cadexi ;yes, exit ; mov a,c ;else get back octet ani 0000$1111b ;get low nibble stax d ;and save at pointer location inx d ;bump pointer jmp caddr2 ;and get next octet ; ; exit with carry set if error occured cadexi: stc ;set carry flag push h ;save bcb lxi h,l3stat ;point to level 3 status bit 5,m ;called address error? pop h ;restore bcb jnz cadexi1 ;and exit with carry ; cmc ;else clear carry cadexi1: pop d ;restore regs pop b ; / ret ; get high nibble of octet ; (internally called) ; on entry: =octet ; on exit: =high nibble of octet ; all other regs unchanged getmsn: ani 1111$0000b ;strip out high nibble rrc ;and move to bits 0-4 rrc ; / rrc ; / rrc ; / ret ; signal called DTE address error ; (internally called) ; on entry: no parameters ; on exit: l3stat bit 5=1 ; all regs unchanged ; adderr: push h ;save lxi h,l3stat ;point to level 3 status setb 5,m ;set address error bit pop h ;restore ret ; check for valid addresses in call accepted packet ; (internally called) ; on entry: =rx bcb address ; on exit: carry set if address error ; all other regs unchaged chkadr: ;*** not implemented yet xra a ret ; ***************** ; * data area * ; ***************** dseg ;data area ; level 3 status indicators l3stat: db 0 ;level 3 status flags chstat: db 0 ;logical channel state ; X.25 address and channel parameters group db 0 ;logical group number chan db lchan ;logical channel number gfi db 0 ;general format identifier laddrl: db 0 ;local address length (# of hex chars) raddrl: db 0 ;remote address length (# of hex chars) caddrl: db 0 ;rx calling DTE address length laddr: ds 15 ;local DTE address (1 hex char/byte) raddr: ds 15 ;remote DTE address (1 hex char/byte) caddr: ds 15 ;rx calling DTE address (1 hex char/byte) rxoc4: db 0 ;received address length octet 4 ; X.25 packet flow control variables pr db 0 ;P(r) ps db 0 ;P(s) lastpr db 0 ;last rx P(r) ltxpr db 0 ;last tx P(r) lrxps db 7 ;last rx P(s) ltxps db 7 ;last tx P(s) qbit db 0 ;Q (qualifier) bit (bit 7) dbit db 0 ;D (delivery confirmation) bit (bit 6) rtryct db n3 ;tx retry count pvcmod db 1 ;VC/PVC mode flag (1=VC,2=PVC) packct db kpack ;packet acknowledgement delay count ; level 3 diagnostic counters txpct: dw 0 ;total tx packets txfpct: dw 0 ;tx file data packets txcpct: dw 0 ;tx console data packets ntxbct: dw 0 ;errors due to no free tx bcb ; rxpct: dw 0 ;total rx packets rxdpct: dw 0 ;total rx data packets rbfpct: dw 0 ;total rx bad format packets rbcpct: dw 0 ;total rx bad channel packets rbapct: dw 0 ;total rx bad address packets rbipct: dw 0 ;total rx bad id packets rbgpct: dw 0 ;total rx bad group packets rxxpct: dw 0 ;total discarded rx packets