title 'LEVEL1.ASM' ;************************************************ ;* * ;* LEVEL1.ASM * ;* * ;* Hardware level initialization and interrupt * ;* service routines for X.25 protocol. * ;* Implemented for Digital Research Computers * ;* 'Big Board' single board computer. * ;* (Z80+SIO+CTC using mode 2 interrupts) * ;* * ;* rev 1.39 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 ; design parameters ; timer periods (seconds) t1: equ 10 ;level 2 timer T1 t20: equ 180 ;level 3 timer T20 t21: equ 200 ;level 3 timer T21 t22: equ 180 ;level 3 timer T22 t23: equ 180 ;level 3 timer T23 ; BIG BOARD equates ; I/O port assignments BAUDA: equ 00h ;channel A baud generator SIO: equ 04h ;dual serial I/O SIODPA: equ SIO+0 ;SIO data port A SIOCPA: equ SIO+2 ;SIO control/status port A CTC: equ 18h ;quad counter/timer circuit CTC0: equ CTC+0 ;CTC channel 0 CTC1: equ CTC+1 ;CTC channel 1 ; interrupt vector locations SIOV4: equ 0FF08h ;SIO port A xmit buffer empty int vector SIOV5: equ 0FF0Ah ;SIO port A external status change SIOV6: equ 0FF0Ch ;SIO port A receive data available SIOV7: equ 0FF0Eh ;SIO port A special receive condition CTCV1: equ 0FF12h ;CTC channel 1 interrupt ; SIO commands srcres equ 0011$0000b ;reset special rx cond errors eomres equ 1100$0000b ;reset tx eom latch crcres equ 1000$0000b ;reset tx crc escres equ 0001$0000b ;reset external status interrupt intpres equ 0010$1000b ;reset tx interupt pending abort equ 0000$1000b ;HDLC abort command ; special Level 2 frame identifiers cmdrfid equ 1000$0111b ;X.25 CMDR frame identifier ; hooks for main program ; subroutine entry points public inisio ;initialize SIO channel A public sbaud ;set baud rate public txwake ;start frame transmission public txabo ;transmit immediate abort public t1on ;start level 2 timer T1 public t1off ;stop level 2 timer T1 public t20on ;start level 3 timer T20 public t20off ;stop level 3 timer T20 public t21on ;start level 3 timer T21 public t21off ;stop level 3 timer T21 public t22on ;start level 3 timer T22 public t22off ;stop level 3 timer T22 public t23on ;start level 3 timer T23 public t23off ;stop level 3 timer T23 ; addresses public baudop ;default baud rate option public rxgfct ;count of good received frames public rxbfct ;count of bad received frames public rxbbct ;count of buffer busy public rxboct ;count of buffer overrun public rxcect ;count of crc errors public rxoect ;count of received frame overruns public rxabct ;count of received aborts public txefct ;count of tx end of frames public txuect ;count of tx underrun errors public txabct ;count of transmitted aborts public txaddr ;tx address byte public txctrl ;tx control byte public rxstat ;receive status flags public txstat ;transmit status flags public tistat ;timer status flags ; definition of rxstat flag byte: ; bit set condition ; 0 rx active ; 1 undefined ; 2 undefined ; 3 undefined ; 4 undefined ; 5 receiver buffers unavailable ; 6 undefined ; 7 undefined ; definition of txstat flag byte: ; bit set condition ; 0 tx active ; 1 tx message complete ; 2 tx frame underrun ; 3 next tx character is control ; 4 undefined ; 5 undefined ; 6 undefined ; 7 undefined ; definition of tistat flag byte: ; bit set condition ; 0 level 2 timer t1 timed out ; 1 level 3 timer t20 timed out ; 2 level 3 timer t21 timed out ; 3 level 3 timer T22 timed out ; 4 level 3 timer T23 timed out ; 5 undefined ; 6 undefined ; 7 undefined ; external suboutines extrn ilprt ;in line print routine extrn putbuf ;write char to buffer extrn getbuf ;read char from buffer extrn bpoint ;point to bcb address extrn newrxb ;get new rx buffer extrn clrbuf ;clear buffer for new use extrn resbcb ;restore bcb pointers extrn delay ;wait a bit ; external addresses extrn rxbact ;active rx buffer # extrn rxbtab ;table of rx bcb pointers extrn rxfree ;bcb for list of free rx buffers extrn rxflst ;bcb for list of complete rx buffers extrn rxbcbp ;active rx bcb extrn txbtab ;table of tx bcb pointers extrn txbcbp ;active tx bcb extrn txubcb ;bcb for CMDR/FRMR I data ; miscellaneous equates cr equ 0Dh ;carriage ret lf equ 0Ah ;line feed cseg ;code segment ; ********************************* ; * initialization section * ; ********************************* ; initialize SIO port A ; (externally called) ; on entry: no paramters ; on exit: flags, regs clobbered inisio: ; initialize interrupt vectors lxi h,siotbe ;tx interrupt service shld siov4 lxi h,sioesc ;ext status change service shld siov5 lxi h,siorca ;rx interrupt service shld siov6 lxi h,siosrc ;special rx condition service shld siov7 lxi h,tick ;1 second timer interrupt shld ctcv1 ; initialize baud rate lda baudop ;get initial baud rate option call sbaud ;set rate ; initialize programmable I/O devices lxi h,intab ;point to SIO parameter table inilp: mov b,m ;b= loop bytecount inx h mov c,m ;c= device control port # inx h outir ;output byte string mov a,m ;test for end of table inr a ; / jnz inilp ;loop again if not at end ; initialize program status flags xra a sta rxstat ;clear receive flags sta txstat ;clear transmit flags ; clear sio rx buffer in siodpa ;clear out SIO data buffer in siodpa ;again for luck ret ; ********************************* ; * interrupt service routines * ; ********************************* ; receive character interupt service routine ; (externally called) ; on entry: no parameters ; on exit: all flags, registers unchanged siorca: call save ;save registers in siodpa ;get received char mov b,a ;save char in lxi h,rxstat ;point to rx status flag setb 0,m ;set rx active bit 5,m ;rx buffer available? jnz erxbusy ;no, handle error ; mov a,b ;get byte lhld rxbcbp ;=active bcb pointer call putbuf ;store in buffer rnc ;exit if no buffer overflow ; lhld rxboct ;else increment buffer overflow inx h ;..error counter shld rxboct ; / ret ; handle no buffer available error erxbusy: lhld rxbbct ;get buffer busy error count inx h ;increment it shld rxbbct ;and save updated count ret ; special receive condition interrupt service routine ; (externally called) ; on entry: no parameters ; on exit: all flags, regs unchanged siosrc: call save ;save registers mvi a,1 ;select rr1 out siocpa ; / in siocpa ;read rr1 mov b,a ;save status in mvi a,srcres ;reset error command out siocpa ; / in siodpa ;clear data byte lxi h,rxstat ;clear rx active res 0,m bit 7,b ;check end of frame bit jnz eof ;yes, service it ; ; process error conditions lhld rxbfct ;update bad frame count inx h ; / shld rxbfct ; / bit 6,b ;crc error? cnz crcerr ;yes, service it ; bit 5,b ;overrun error? cnz orerr ;yes, service it ; call flush ;clear rx buffer ret ; ; process end of frame eof: lda rxbact ;get active buffer # lxi h,rxflst ;point to list of rx frames call putbuf ;hand over frame call newrxb ;get new rx buffer if avail lhld rxgfct ;update good frame count inx h ; / shld rxgfct ; / ret ; ; crcerr: lhld rxcect ;update crc error counter inx h ; / shld rxcect ; / ret ; orerr: lhld rxoect ;update overrun error counter inx h ; / shld rxoect ; / ret ; tx wake routine (starts transmission of frame) ; (externally called) ; on entry: no paramters ; on exit: flags, regs clobbered txwake: lxi h,txstat ;point to tx status flag setb 0,m ;signal tx active setb 3,m ;signal next char is control mvi a,crcres ;reset tx crc out siocpa ; / lda txaddr ;get address byte out siodpa ;transmit it mvi a,eomres ;reset tx eom latch out siocpa ; / ret ; tx buffer empty interrrupt service routine ; (externally called) ; on entry: no parameters ; on exit: all flags, regs unchanged siotbe: call save ;save registers lxi h,txstat ;point to tx status flag bit 1,m ;message complete? jnz txeof ;yes, process end of frame ; lda txctrl ;get control byte bit 3,m ;next char is control? jz txnext ;no, process remainder of frame ; res 3,m ;yes, reset flag out siodpa ;transmit control byte ret ; ; process remainder of frame txnext: bit 0,a ;I frame? jz txinfo ;yes, process it ; ani 1110$1111b ;CMDR frame? cpi cmdrfid ; / jnz txeom ;no, process end of message ; lxi h,txubcb ;yes, point to CMDR bcb call getbuf ;byte available? jc txeom ;no, process end of message ; out siodpa ;else output byte ret ; process I frame txinfo: lhld txbcbp ;point to active bcb call getbuf ;end of buffer? cc resbcb ;yes, restore bcb pointers jc txeom ;and process end of message ; out siodpa ;else output byte ret ; ; process end of transmitted message txeom: lxi h,txstat ;point to tx status flag setb 1,m ;set message complete semaphore lhld txefct ;increment end of frame count inx h ; / shld txefct ; / jmp txexi ; process end of transmitted frame txeof: res 1,m ;clear tx mc flag res 0,m ;set tx inactive txexi: mvi a,intpres ;reset tbe int pending out siocpa ; / ret ; service external status change interrupt ; (externally called) ; on entry: no parameters ; on exit: all flags, regs unchanged sioesc: call save ;save registers in siocpa ;read rr0 mov b,a ;save status in bit 6,b ;tx buffer underrun? jnz txurun ;yes, process it ; bit 7,b ;abort received? jnz rxabo ;yes, process it ; ; else it's only a sync detect in siodpa ;clear extraneous char jmp escexi ;and exit ; ; process rx abort rxabo: mvi a,3 ;wr3 out siocpa ; / mvi a,1101$0001b ;enter hunt phase out siocpa in siodpa ;clear any extraneous char lhld rxabct ;increment rx abort count inx h ; / shld rxabct ; / call flush ;clear rx buffer call delay ;wait a little bit jmp escexi ;and exit ; ; process tx buffer underrun txurun: mvi a,eomres ;reset eom/underrun latch out siocpa ; / lxi h,txstat ;point to tx status flag bit 1,m ;tx message complete? jnz escexi ;yes, it's normal termination ; ; process real tx buffer underrun error res 0,m ;clear tx busy flag lhld txuect ;increment underrun error count inx h ; / shld txuect ; / call txabo ;and abort transmission lda txctrl ;get control byte bit 0,a ;I frame? jnz escexi ;no, exit ; lhld txbcbp ;yes, point to active tx bcb call resbcb ;and reset pointers ; ; common exit escexi: mvi a,escres ;reset esc condition out siocpa ; / ret ; clear active rx buffer ; (internally called) flush: lhld rxbcbp ;point to active rx bcb call clrbuf ;clear buffer ret ; service 1 second timer interrupt from CTC-1 ; (externally called) ; on entry: no parameters ; on exit: all flags, regs unchanged tick: call save ;save registers lxi d,tistat ;=A(timer status word) lxi h,t1ct ;point to first counter xra a ;clear cmp m ;count=0? jz tick1 ;yes, keep going dcr m ;else decrement count jnz tick1 ;keep going if not 0 xchg ;else set timeout flag setb 0,m ; / xchg ; / tick1: inx h ;point to next counter cmp m ;count=0? jz tick2 ;yes, keep going dcr m ;else decrement count jnz tick2 ;keep going if not 0 xchg ;else set timeout flag setb 1,m ; / xchg ; / tick2: inx h ;point to next counter cmp m ;count=0? jz tick3 ;yes, keep going dcr m ;else decrement count jnz tick3 ;keep going if not 0 xchg ;else set timeout flag setb 2,m ; / xchg ; / tick3: inx h ;point to next counter cmp m ;count=0? jz tick4 ;yes, keep going dcr m ;else decrement count jnz tick4 ;keep going if not 0 xchg ;else set timeout flag setb 3,m ; / xchg ; / tick4: inx h ;point to next counter cmp m ;count=0? jz tick5 ;yes, keep going dcr m ;else decrement count jnz tick5 ;keep going if not 0 xchg ;else set timeout flag setb 4,m ; / xchg ; / tick5: ;room for expansion ret ; save register routine for interrrupt service save: xthl ;save & point to service routine push d ;save the other regs push b ; / push psw ; / call go ;go and return here from service routine pop psw ;restore registers pop b ; / pop d ; / pop h ;and get back from stack ei ;enable interupts reti ;restore interrupt chain ; go: pchl ;dispatch to ; ********************************* ; * level 1 control subroutines * ; ********************************* ; transmit abort signal ; (externally and internally called) ; on entry: no parameters ; on exit: flags, regs clobbered txabo: mvi a,abort ;send immediate abort out siocpa ; / lhld txabct ;increment transmitted abort count inx h ; / shld txabct ; / ret ; stop level 2 timer T1 ; (externally and internally called) ; on entry: no paramters ; on exit: all flas, regs unchanged t1off: push psw ;save regs and flags push h ; / xra a ;set count to 0 sta t1ct ; / lxi h,tistat ;reset timeout flag res 0,m ; / pop h ;restore regs and flags pop psw ; / ret ; stop level 3 timer T20 ; (externally and internally called) ; on entry: no paramters ; on exit: all flas, regs unchanged t20off: push psw ;save regs and flags push h ; / xra a ;set count to 0 sta t20ct ; / lxi h,tistat ;reset timeout flag res 1,m ; / pop h ;restore regs and flags pop psw ; / ret ; stop level 3 timer T21 ; (externally and internally called) ; on entry: no paramters ; on exit: all flas, regs unchanged t21off: push psw ;save regs and flags push h ; / xra a ;set count to 0 sta t21ct ; / lxi h,tistat ;reset timeout flag res 2,m ; / pop h ;restore regs and flags pop psw ; / ret ; stop level 3 timer T22 ; (externally and internally called) ; on entry: no paramters ; on exit: all flas, regs unchanged t22off: push psw ;save regs and flags push h ; / xra a ;set count to 0 sta t22ct ; / lxi h,tistat ;reset timeout flag res 3,m ; / pop h ;restore regs and flags pop psw ; / ret ; stop level 3 timer T23 ; (externally and internally called) ; on entry: no paramters ; on exit: all flas, regs unchanged t23off: push psw ;save regs and flags push h ; / xra a ;set count to 0 sta t23ct ; / lxi h,tistat ;reset timeout flag res 4,m ; / pop h ;restore regs and flags pop psw ; / ret ; start level 2 timer T1 ; (externally called) ; on entry: no parameters ; on exit: all regs, flags unchanged t1on: push psw ;save regs and flags push h ; / mvi a,t1 ;intitialize count sta t1ct ; / lxi h,tistat ;reset timeout flag res 0,m ; / pop h ;restore flags, regs pop psw ; / ret ; start level 3 timer T20 ; (externally called) ; on entry: no parameters ; on exit: all regs, flags unchanged t20on: push psw ;save regs and flags push h ; / mvi a,t20 ;intitialize count sta t20ct ; / lxi h,tistat ;reset timeout flag res 1,m ; / pop h ;restore flags, regs pop psw ; / ret ; start level 3 timer T21 ; (externally called) ; on entry: no parameters ; on exit: all regs, flags unchanged t21on: push psw ;save regs and flags push h ; / mvi a,t21 ;intitialize count sta t21ct ; / lxi h,tistat ;reset timeout flag res 2,m ; / pop h ;restore flags, regs pop psw ; / ret ; start level 3 timer T22 ; (externally called) ; on entry: no parameters ; on exit: all regs, flags unchanged t22on: push psw ;save regs and flags push h ; / mvi a,t22 ;intitialize count sta t22ct ; / lxi h,tistat ;reset timeout flag res 3,m ; / pop h ;restore flags, regs pop psw ; / ret ; start level 3 timer T23 ; (externally called) ; on entry: no parameters ; on exit: all regs, flags unchanged t23on: push psw ;save regs and flags push h ; / mvi a,t23 ;intitialize count sta t23ct ; / lxi h,tistat ;reset timeout flag res 4,m ; / pop h ;restore flags, regs pop psw ; / ret ; set baud rate ; (externally and internally called) ; on entry: =baud option (0-7) ; on exit: =upper 4 bits=0 ; all other regs unchanged sbaud: ani 07h ;extract lower 3 bits sta baudop ;save option push h ;save registers push d ; / lxi h,baudtab ;point to baud table mov e,a ;option to mvi d,0 dad d ;point to desired baud mov a,m ;get baud rate byte sta baudtab ;save it out bauda ;program the 8116 pop d ;restore registers pop h ret ; ***************** ; * data tables * ; ***************** dseg ;data segment baudop db 1 ;default baud rate option ; table of constants for 8116 baud rate generator baudtab db 0000$0000b ;0= current baud rate db 0000$0101b ;1= 300 baud db 0000$0110b ;2= 600 baud db 0000$0111b ;3= 1200 baud db 0000$1010b ;4= 2400 baud db 0000$1100b ;5= 4800 baud db 0000$1110b ;6= 9600 baud db 0000$1111b ;7= 19200 baud ; SIO initialization table intab: db t1end-$-2 ;byte count db siocpa ;SIO channel a control port db 0 ;WR0 for sure db 0001$1000b ;reset channel a db 4 ;WR4 db 0010$0000b ;HDLC mode db 7 ;WR7 db 0111$1110b ;HDLC flag db 1 ;WR1 db 0001$1111b ;interrupt control db 5 ;WR5 db 1110$1011b ;tx parameters + tx enable t1end: equ $ ; initialize CTC0 db t2end-$-2 ;byte count db CTC0 ;CTC0 control port db 00100111b ;put CTC0 in timer mode db 105 ;with period=105*256*0.4 us t2end: equ $ ;(=10752 us) ; initialize CTC1 db t3end-$-2 ;byte count db CTC1 ;CTC1 control port db 11000111b ;put CTC1 in counter mode db 93 ;with period=93*10752 us t3end: equ $ ;(=1sec) & interrupt enabled ; initialize SIO receive section ; (separated to facilitate initialization in self test mode) db t4end-$-2 ;byte count db siocpa ;SIO-A control port db 3 ;WR3 db 1101$0001b ;rx parameters + rx enable t4end: equ $ db -1 ;end of table marker ; ************************* ; * global variables * ; ************************* rxstat db 0 ;rx status flags txstat db 0 ;tx status flags tistat db 0 ;timer status flags txaddr db 0 ;tx address byte txctrl db 0FFh ;tx control byte ; system timers (must be contiguous) t1ct: db 0 ;level 2 timer T1 count t20ct: db 0 ;level 3 timer T20 count t21ct: db 0 ;level 3 timer T21 count t22ct: db 0 ;level 3 timer T22 count t23ct: db 0 ;level 3 timer T23 count ; level 1 diagnostic counters rxbfct dw 0000h ;bad received frames rxgfct dw 0000h ;good received frames rxbbct dw 0000h ;chars lost due to buffers not avail rxboct dw 0000h ;chars lost due to buffer overrrun rxcect dw 0000h ;received crc errors rxoect dw 0000h ;receive overrun errors rxabct dw 0000h ;received aborts txefct dw 0000h ;tx end of frame count txuect dw 0000h ;tx underrun errors txabct dw 0000h ;transmitted aborts