(Message 662) Subject: Re: Newcastle Interface From: I.N.Dallas @ uk.ac.ukc 29 Aug 85 16:13:38 bst To: B.Gilmore @ uk.ac.edinburgh In reply to: Your message <29 Aug 85 16:05:09 bst 140005@EMAS> Via: uk.ac.ukc ; (to uk.ac.edinburgh.emas) 30 Aug 85 08:12:22 bst Msg ID: <29 Aug 85 16:13:38 bst 010857@EMAS> Attached is the un-prepped source of xprot. There will be a mail message following which has the GO file, which generates the object. Thanks for your assistance, I will look closely at the sources too. Source follows: *********** #if k %list #fi ! !************************************************* !* * !* PSS X-25 Level 2 Protocol Handler * !* * !* XPROT * !* * #datestring #timestring !* Version 30.1 22 July 1985 * !* * !************************************************* ! Prep options ! ! q - dqs11 code ! p - dup11 code ! n - kv11 code (n = Newcastle) ! b - Big Buffer version ! k - UKC ! u - UKC - Sgate specific ! d - Buffer tracing (UKC) ! y - Use a second xgate (for psse & small buffer version only) ! #if k #if u ! ! SSSSS GGGGG AAAAA TTTTTTT EEEEEEE ! S S G G A A T E ! S G A A T E ! SSSSS G AAAAAAA T EEEEE ! S G GGG A A T E ! S S G G A A T E ! SSSSS GGGGG A A T EEEEEEE ! #else ! ! GGGGG AAAAA TTTTTTT EEEEEEE ! G G A A T E ! G A A T E ! G AAAAAAA T EEEEE ! G GGG A A T E ! G G A A T E ! GGGGG A A T EEEEEEE ! #fi #fi #if b #report Producing Big Buffer Manager Version #fi #if p&q #report must have either p (dup11) or q (dqs11e) or neither (both) #fi #if ~p & ~q & ~n #report MUST specify either p, q or k #fi #if q #report dqs11e code included #fi #if p #report dup11 code included #report WARNING: Not checked yet, see segment use & map3 !!!!!!! #fi #if n #report Kv11 code used #fi !* ! NB: This handler now requires the later version of the Buffer Manager ! that protects itself from double Q manipulation. (see ring version) ! #if b %constinteger big buffer length = 320; ! NB: New Length ****************** #else %constinteger big buffer length = 160; ! NB: New Length ****************** #fi %control 1 !* !******************************** !* * !* Declarations * !* * !******************************** %begin !***** Configuration Information ***** !* #if k %include "config" %include "inc_sers" #else %include "ercm06.INC_CONFIG" %include "ercm06.INC_SERS" #fi %owninteger dcedte =0 ;!DCE !* !***** Constintegers ***** ! !*State Values %constinteger waiting for disc =1 ;!DTE %constinteger ua queued 1 =2 ;!DTE & DCE %constinteger sabm queued =3 ;!DTE & DCE %constinteger waiting for ua =4 ;!DTE & DCE %constinteger waiting for sabm =5 ;!DCE %constinteger uaqueued 2 =6 ;!DCE %constinteger disc queued =7 ;!DTE & DCE %constinteger link up =0 ;!DTE & DCE %constinteger dce waiting for ua =1 ;!DCE %constinteger dte waiting for ua = 8 ;!DTE %constinteger dce sarm queued = 9 ;!DCE - LAP-Compatibility code !*Substate values (Values of RSTATE) %constinteger rrsent = 0 %constinteger rrpending = 1 %constinteger rejsent = 2 %constinteger rejpending = 3 %constinteger rnrsent = 5 %constinteger rnrpending = 6 %constinteger rrdeferred = 7 !*Monitor Calls !* %constinteger ok =0 %constinteger line down =1 %constinteger line up =2 %constinteger query =3 %constinteger push error = 4 %constinteger buffers low = 5 %constinteger silo full = 7 %constinteger bad fr = 8 %constinteger dms = 9 %constinteger init msg = 10 %constinteger mon clock tick = 11 %constinteger bad addrs rx = 12 %constinteger spurious uframe rx = 13 %constinteger rrs rx = 16 %constinteger rejs rx = 17 %constinteger rnrs rx = 18 %constinteger iframes rx = 19 %constinteger iseqerss rx = 20 %constinteger sabms rx = 21 %constinteger uas rx = 22 %constinteger discs rx = 23 %constinteger frmrs rx = 24 %constinteger badframes rx = 25 %constinteger null iframes rx = 26 %constinteger grotted 2 = 27 %constinteger grotted 3 = 28 %constinteger grotted 4 = 29 %constinteger grotted 5 = 30 %constinteger poll failure = 31 %constinteger rrs tx = 32 %constinteger rejs tx = 33 %constinteger rnrs tx = 34 %constinteger iframes tx = 35 %constinteger retries tx = 36 %constinteger sabms tx = 37 %constinteger uas tx = 38 %constinteger discs tx = 39 %constinteger frmrs tx = 40 %constinteger mon hw fail = 47 %constinteger funny int = 48 %constinteger buff full = 49 %constinteger bad address = 50 %constinteger spurious data = 51 %constinteger grotted 1 = 52 %constinteger short frame = 54 %constinteger from upper = 56 %constinteger to upper = 57 %constinteger funny state = 58 %constinteger bad function = 59 %constinteger output tx = 61 %constinteger bad ack = 62 %constinteger input rx = 63 %constinteger line no wrong = 64 %constinteger line type wrong = 65 !* !Line and module state values for communicating with XGATE !* %constinteger link established =0 %constinteger link down =1 %constinteger xprot up =2 !* !* X25 Frames !*Information transfer %constinteger iframe =0 !*Supervisory %constinteger rr =1 %constinteger rnr =5 %constinteger rej =9 !*Unnumbered %constinteger sabm =x'2F' %constinteger sarm =x'0F' %constinteger disc =x'43' %constinteger ua =x'63' %constinteger frmr =x'87' ! !***** Hardware control bits ***** ! #if p!q %constinteger rset=k'100',dsr=k'1000',dtr=2,rts=4,cts=k'20000' %constinteger dcd=k'10000',rxen=k'20',txen=k'20',dlen=k'40' %constinteger tsom = k'400', teom = k'1000' %constinteger drs = k'400', snd = k'20', rcven = k'20' %constinteger rx done = k'200', tx done = k'200' #else ! in Interface register %constinteger intAenb = k'04' %constinteger intBenb = k'10' %constinteger RxBCzero = k'20' %constinteger TxBCzero = k'40' %constinteger intB = k'100' %constinteger intA = k'200'; ! bus timeout %constinteger dmaIenb = k'400' %constinteger dmaOenb = k'1000' %constinteger X1 clock = k'4000'; ! set = use external clock %constinteger CLRchip = k'100000'; ! master reset ! in Chip reg 1 %constinteger set DTR = k'002' %constinteger Act Tx = k'100' %constinteger Act Rx = k'200' ! in Chip reg 2 %constinteger auto flag = 1 ! in INTR (NB:can only read once) %constinteger Data set chg = k'10' %constinteger tx bad = k'020' %constinteger tx ok = k'040' %constinteger rx bad = k'100' %constinteger rx ok = k'200' ! in chip status register %constinteger crc err = k'001' %constinteger ovr err = k'002' %constinteger abort rec = k'004' %constinteger Rec idle = k'010' %constinteger Misc In = k'020' %constinteger DSR = k'040' %constinteger Carr det = k'100' %constinteger Ring Ind = k'200' #fi !* !* Values of flags etc !* %constinteger clear =0 %constinteger set =1 %constinteger pending =1 %constinteger sent =2 %constinteger pfset =x'10' %constinteger command =0 %constinteger response =1 %constinteger invalid =-1 %constinteger sfmask =63 %constinteger dce =0 %constinteger dte =1 %constinteger initialise =0 %constinteger line output =2 %constinteger input here =3 %constinteger output done =4 %constinteger modem status = 5 %constinteger rxgo =k'111' %constinteger txgo =k'111' %constinteger input req =1 %constinteger output req =2 %constinteger bounce =3 %constinteger put down =4 %constinteger put up =5 %constinteger poke = 22 %constinteger dead =0 %constinteger timed out =1 %constinteger reset = 2 %constinteger sabm received = 3 %constinteger user request =4 %constinteger read fails = 7 %constinteger uframe in data =6 %constinteger data retries =5 %constinteger full up = 8 %constinteger disc received = 9 %constinteger line timeout = 10 %constinteger no buffs = 11 %constinteger critical = 4 %constinteger big limit = 5; ! level for sending RNR !* !***** Record Formats ***** %recordformat qf(%record (qf) %name link, %integer count) #if p!q %recordformat hwf((%integer rcs, rdb, tcs, tdb) %or %c (%integer mcsr, tcsr, rsr, rcr, twcr, tcar, rwcr, rcar)) #else %recordformat hwf(%integer ICcsr, Eaddr, x1, x2, RxAddr, RxBc, TxAddr, TxBc, %c chipR1, chipR2, chipR3, RHR, INTR, chipSTR) #fi %recordformat x25f(%byte add, type, octet1, octet2, octet3) %recordformat parf(%integer type, (%record (x25f) %name b %or %integer address), %c #if b %integer len, buff no) #else %integer len) #fi %recordformat desf(%integer pt, %byte state, s1, %c %integer maxln, p1, flag, seg, sa, vec, intno) %recordformat des2f(%record (desf) rx, tx) %recordformat m1f(%integer a, b, c, d, e, f, g) #if b %recordformat mef(%integer buff no, len, %byte owner, type, %c %byte d0, %record (x25f) x25) ! nb: the 'type' of buffer (ie short or long) ! is now further down, the 'owner' of a ! buffer is recorded on an INCOMING buffer #else %recordformat mef(%record(mef) %name link, %byte len, type, %c %byte d0, d1, d2, %record(x25f) x25) #fi %recordformat pf(%byte ser, reply, ((%integer a, b, c) %or %c #if b (%byte fn, line, %integer buff no, %byte len, c2))) #else (%byte fn, line, %record(mef) %name m, %byte len, c2))) #fi !* !* !***** Monitoring Information ***** !* %owninteger irx, rrrx, rnrrx, rejrx, discrx, uarx, sabmrx, frmrrx, ierrrx, %c nullrx, wcov, silo, abort rx, d1, d2 = 0 %owninteger itx, rrtx, rnrtx, rejtx, disctx, uatx, sabmtx, frmrtx, retrytx = 0 #if ~f %ownintegerarray moncount(0:63)=0(64) %constbytearray monaction(0:63) = %c 2, 2, 2, 1, 1, 1, 1, 3, 3, 1, 1, 1, 3, 1, 1, 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 3, 2, 3, 3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3, 2, 3, 3, 3, 1, 2, 1, 1, 1, 3, 3, 3, 4, 2, 4 #fi !***** INTEGERS ***** !* %owninteger rx watchdog = 0 %owninteger tx watchdog = 0 %owninteger clock0 =0 %owninteger clock1 =0 %owninteger clock2 =0 %owninteger clock3 =0 %owninteger clock4 =0; ! read fails - block too long %owninteger clock5 =0; ! no read buffers for 3 mins %owninteger address = 0 %owninteger type = 0 %owninteger pfbit = 0 %owninteger comres = 0 %owninteger poll =0 ;!"Pending" if we have a Poll bit to send !"Sent" when we have sent it, cleared when we receive a final bit %owninteger final =0 ;!Set when far end sends us a Poll bit. !Cleared when we send back a Final bit %owninteger istate= 0 ;!State of our end of the link %owninteger tstate= 0 ;!Set if far end has RNR up against us %owninteger rstate = 0 %owninteger abort req,abort reason = 0 %owninteger window = 6 %owninteger aaa = 0 ;!Last message ackked by far end %owninteger eee = 0 ;!Next message expected %owninteger ttt = 0 ;!Next message to send %owninteger xxx = 0 ;!High Water Mark !This is the most advanced frame for which a valid ack is possible !It is equal to TTT except during timer recovery (retransmission) !where TTT is the frame just sent and XXX is the most advanced frame %owninteger fff = 0 ;!Last message sent %owninteger active =0 %owninteger max reads = 5 %owninteger t1 = 6 ;!6 Ticks = 2.5 - 3 secs %owninteger n2 = 20 %ownbyte line %ownbyte line type %owninteger i,b = 0 %owninteger txint = -6 %owninteger rxint = -7 %owninteger buffers held = 0 %owninteger quiet idle = 1 %owninteger hold rnr = 0 ;!Hold RNR up for testing %owninteger outstanding buff req = 0 #if n %owninteger intr, chipstr #fi %ownbyte monbyte = 1;!Controls what is monitored to where !* !* Buffer Management Constants etc !* #if b %recordformat hold buff link(%integer link, buff no) %record (hold buff link) %name hold f #fi #if b %constintegername ps == k'017776'; ! processor status - in seg 0 %constintegername big buff pt== k'120032' %constintegername small buff pt == k'120034' %constintegername free h == k'120036' %constintegername no of big buff == k'120040' %constintegername no of small buff == k'120042' %constintegername min no of big == k'120046' %constintegername min no of small == k'120050' %constintegername no of big req == k'120052' %constintegername big start == k'120060' #else %constintegername ps == k'017776'; ! processor status - in seg 0 %constintegername big buff pt== k'100104' %constintegername small buff pt == k'100106' %constintegername no of small buff == k'100114' %constintegername min no of big == k'100120' %constintegername min no of small == k'100122' %constintegername no of big req == k'100124' #fi !* !****** NAMES ***** !* #if k %include "inc_exts" %include "inc_various" #else %include "ercm06.INC_EXTS" %include "ercm06.INC_VARIOUS" #fi !***** Arrays ***** !* !* !***** Own and Const Arrays ***** !* %constintegerarray initstate(0:1)=disc queued(2) !* !***** Records and record names ***** !* %ownrecord (pf) p %constrecord (*) %name null == 0 !* variables used by the low-level comms hw driving routines %ownrecord (parf) parb %ownrecord (des2f) %name des %ownrecord (mef) %name mes %ownrecord (des2f) %array %name desx #if k %constrecord (hwf) %name hw == k'100' #else %constrecord (hwf) %name hw == k'3000' ;!Set up by xprot on initialise #fi %ownrecord (*) %name handler address == 1 %owninteger tx reply, rx reply %owninteger f, cad, oseg, ext bits, save ext bits %owninteger par, pad, x %ownintegerarray raddr(0:7) %recordformat bpf(%record (mef) %name m) %ownrecord (m1f) m1, m2 #if b %recordformat idse((%record (mef) %name m %or %integer b), %integer len, buff no) %recordformat wdse(%integer buff no, len) #else %recordformat wdse((%record (mef) %name m %or %integer b), %integer len) #fi %ownrecord (wdse) %name wdesc %ownrecord (wdse) %array wspace(0:sfmask) #if b %ownrecord (idse) %name idesc %ownrecord (idse) icurr = 0 #else %ownrecord (wdse) %name idesc %ownrecord (wdse) icurr = 0 #fi %ownrecord (qf) ipool #if b %ownrecord (idse) om #else %ownrecord (wdse) om #fi %ownrecord (bpf) %name im %ownrecord (bpf) %name me2 %ownstring (7) %array abo reason(0:11) = "Dead", "tmd out", "Reset", "Sabm rx", "User Rq", "Rd Fail", "Ufrm Rx", "Data Tx", "Full Up", "Disc Rx", "Line Tm", "No Buff" !***** Routine Specs ***** ! %routinespec stop(%integer reason) #if d %routine traceid(%record (mef) %name buf, %integer id) !----------------------------------------------------- %recordformat traceblock(%integerarray ids(0:7), %integer top) %record (traceblock) %name trace %integer i %if addr(buf)=0 %then %return %if buf_type & 64 # 0 %then %return; !short buffer trace == record(addr(buf)+236) i = trace_top; !index to last saved item trace_ids(i) = trace_ids(i) & x'ff'; !remove marker from previous top i = (i+1)&7 trace_ids(i) = x'f000' ! id; !add in marker so top item visisble trace_top = i %end #fi ! ! %routinespec abort(%integer reason) %routinespec clock int #if b %record (mef) %mapspec map(%integer buff no) %routinespec free buffer(%integer buff no) #else %routinespec free buffer(%record(mef) %name p) #fi %routinespec handle input %routinespec handle output %routinespec monitor(%record (pf) %name p,%integer type) %routinespec octal(%integer n) %routinespec query processes %routinespec reinitialise hardware %routinespec reset line %routinespec move(%integer len, from, to) %routinespec put read on hardware %routinespec replace read %routinespec to comms hw(%record (parf) %name par) %routinespec to xgate(%integer flag) !****** Others ***** !* !* !****** END OF DECLARATIONS ***** !********************************** !* * !* Main Program * !* * !********************************** #if ~b map virt(buffer manager,5,4) #fi map virt(buffer manager,6,5) im == m1 ; om_m == m2 change out zero = t3 ser ;!Queued console I/O p_ser=0 ;!Accept all messages poff(p) ;!Wait. Expect an initialisation message #if ~f monitor(p, init msg) #fi line=p_fn ;!We have only one line. Just record it and use !it for communicating with XGATE. #if k printstring("XPRO (".longnetname(line).") ".datestring." ".timestring) ; newline #else printstring("XPRO (") ;printstring(longnetname(line)) ;printstring(") Running ") #fi line type = p_line & 7 ;!0 = DQS11 ;1 = DUP11 2 = DUP11 with read-chained-read DUP driver dcedte = p_line >> 7 ;!0=DCE 1=DTE #if b handler address==record(p_b) #else handler address==p_m #fi rxint=p_len!X'FF00' txint=p_c2!X'FF00' stop(line no wrong) %unless 0 <= line <= 2 stop(line type wrong) %unless 0 <= line type <= 2 istate = initstate(dcedte) reinitialise hardware to xgate(xprot up) alarm(25) ;!Half a second timer tick handle output %cycle ;!Main loop p_ser=0 ;!Accept all messages poff(p) ;!Wait %if p_ser&x'80'#0 %start ;!Interrupt #if p!q %if p_ser = txint & x'ff' %start parb_type = output done to comms hw(parb) active = 0 tx watchdog = 0 handle output %else replace read rx watchdog = 0 handle input %finish #else %if p_ser = txint&x'ff' %start; ! type A int (bus timeout) hw_iccsr = hw_iccsr&(~intA) ! nb: timeout will cause a type B int as well %continue %finish ! type B int - Data set change, Input int, Output int OR COMBINATION intr = hw_intr; ! read once only chipstr = hw_chipstr; ! may also change parb_len = intr %if intr&data set chg # 0 %start parb_type = modem status to comms hw(parb) %finish %if intr&(Rx ok!Rx Bad) # 0 %start replace read; ! it needs intr, but used globally for compatibility rx watchdog = 0 handle input %finish %if intr&(Tx ok!Tx Bad) # 0 %start parb_type = output done to comms hw(parb) active = 0 tx watchdog = 0 handle output %finish #fi %continue %finish %if p_reply=0 %start ;!Clock tick !Interrupts: !0-9: Change monitoring level !A: Force a line abort !B:Generate a bad link-level address !E: Force a REJ !N: Close trace file and start a new one !Q: Quiet: Suppress idle RR exchanges !U: Generate a spurious U-frame !R: Force a Transmitted sequence error !S: Force a reset of line by SABM !X: Generate a spurious frame (invalid) !W: Hold up RNR !Z: Stop program moderately tidily #if ~f monitor(null, mon clock tick) #fi clock int %if int = 0 %then %continue %if int = 'S' %start abort(reset) %elseif int = 'A' abort(user request) ;!Int A aborts line %elseif int='?' query processes monitor(null,query) ;!Int ? produces a status report %elseif '0' <= int <= '9' monbyte = int - '0' %elseif int = 'N' selectoutput(1) ;close output %elseif int = 'Q' quiet idle = 1 - quiet idle %elseif int = 'W' hold rnr = 1 - hold rnr ;!Force RNR for testing #if n %else %if int = 'K' hw_chipR1 = hw_chipR1&(~act rx) hw_chipR1 = hw_chipR1!act rx; ! force a re-synch #fi %finishelse %continue int = 0 %continue %finish #if ~f monitor(p, from upper) #fi %if p_fn = output req %start ; !"Write to line" from higher level buffers held = buffers held + 1 #if b mes == map(p_buff no) %unless k'4000' <= mes_buff no <= k'7777' %then stop(grotted 2) mes_owner = own id; ! record who owns the buffer #else %if 0 # p_m_type # 64 %then stop(grotted 2) #fi %if istate=link up %start ;!Ignore unless line is up !Xprot maintains a circular array of 64 records. These !point to buffers received from the higher level from the time !they arrive to the time they are acknowleged wdesc==wspace(fff) #if b wdesc_buff no = p_buff no #if q mes_d0 = 0 ;!Flag to tell DQS handler whether to shuffle or not #fi wdesc_len=mes_len+3+2; ! nb: so Gatex is same as before #else wdesc_m == p_m wdesc_len = p_len + 2 #fi fff=(fff+1)&sfmask ;!Increment n(s): Sequence no of next frame %if fff = aaa %start !We've filled up our carousel. Nothing for it but to drop !the line to prevent a crash monitor(null, buff full) abort(full up) %finish handle output %else ;!Link down #if b free buffer(mes_buff no) ; p_buff no = 0 #else free buffer(p_m) ; p_m == null #fi %finish %elseif p_fn = poke %if istate = link up %then p_len = 1 p_c2 = buffers held i = p_ser ;p_ser = p_reply ;p_reply = i #if b %unless p_buff no = 0 %start mes == record(p_buff no); ! this is NOT a buffer move(48, addr(irx), addr(mes_d0)) ; mes_len = 48 %finish #else %unless p_m == null %start move(48, addr(irx), addr(p_m_d0)) ; p_m_len = 48 %finish #if d traceid(p_m, p_ser) #fi #fi pon(p) %else monitor(p,bad function) !We Won't free the buffer (Better slowly gobble space than risk crashing BUFF) %finish %repeat !* !**************************************** !* * !* Routines * !* * !**************************************** %routine abort(%integer reason) %integer i, x %if istate = link up %start set prio(1); ! no priority, bm must absorb buffers abort reason = reason %unless reason = 0 %if abort req=0 %start ;!First try at aborting printstring(longnetname(line)) ;printstring(" Line Down at Level 2:") printstring(abo reason(abort reason)); newline monitor(null,line down) to xgate(link down) %finish %if active=2 %start ;!Big block being transmitted abort req=1 %else abort req=0 x = 0; ! restrict concurrent no of release requests %while aaa#fff %cycle ;!Clear up requests wdesc == wspace(aaa) #if b free buffer(wdesc_buff no); wdesc_buff no = 0 wdesc_buff no = 0 #else free buffer(wdesc_m) ; wdesc_m == null wdesc_m == null #fi aaa=(aaa+1)&sfmask x = x+1 %if x = 7 %then x = 0 %and set prio(1); ! force it to wait %repeat istate=disc queued ;clock3 = 0 %if abort reason = reset %then istate = sabm queued %if abort reason = sabm received %then istate = ua queued 1 %if abort reason = disc received %then istate = ua queued 2 abort reason = 0 handle output %finish %elseif istate = 1 istate = disc queued ;clock3 = 0 handle output %finish %end ;!of abort #if b %record (mef) %map map3(%integer buff no) *mov_#6,1; ! desired vm seg * 2, ie seg 3 (r1=buff no) *iot %result == record(k'060000') ! This routine could be done without for use with ! the DUP code (which uses seg 3), but an extra ! MAP must then be done in Put Read On %end %record (mef) %map map(%integer buff no) ! buff no is already in r0 - where its wanted *mov_#8,1; ! desired vm seg no *2 ie 4*2 *iot %result == record(k'100000') %end %integerfn grab buffer %integer x, buff, ffree, q ! my addresses are in range 120000 - 137777 ! buff man address are 140000 - 157777 - so subtract 20000 ! buffers there, grab one ps = ps!k'340'; ! stop processor interrupts %if no of big buff >= critical %start buffers held = buffers held+1 no of big buff = no of big buff-1 %if no of big buff < min no of big %then min no of big = no of big buff no of big req = no of big req+1 x = big buff pt; ! pick up descriptor of big buffer q = x x = x-k'20000'; ! into my address range holdf == record(x); ! map buffer descriptor on buff = holdf_buff no; ! and extract buffer number big buff pt = holdf_link; ! unlink the descriptor from q ffree = free h; ! get top of free desc q free h = q; ! and put descriptor on free desc q holdf_link = ffree ps = ps&(\k'340'); ! allow ints again %result = buff; ! and pass back result %finish ps = ps&(\k'340') %result = 0 %end %routine free buffer(%integer buff no) %integer x, q, ffree %record (pf) p !Frees the block pointed at by M %unless buff no = 0 %start ;!Safety check for NULL pointer %if buff no < k'4000' %or buff no > k'7777' %then stop(grotted 5) buffers held = buffers held - 1 ps = ps!k'340'; ! put processor status = 7 ffree = free h; ! get a buff descr. from the free q x = ffree-k'20000'; ! ensure I can access it holdf == record(x); ! map descriptor to it free h = holdf_link; ! Unlink it from desc q holdf_buff no = buff no; ! and store buffer no in it %if buff no < big start %start; ! if its a SMALL buffer no of small buff = no of small buff+1 holdf_link = small buff pt; ! add descriptor to small buff q small buff pt = ffree; ! address in ITS vm, not mine %finish %else %start no of big buff = no of big buff+1 holdf_link = big buff pt big buff pt = ffree %finish ps = ps&(\k'340'); ! and allow ints again %finish %end ;!of free block #else %record (mef) %map grab buffer %integer x #if k %record (mef) %name mes #fi ! buffers there, grab one ps = ps!k'340'; ! stop processor interrupts %if no of buff >= critical %start buffers held = buffers held+1 no of buff = no of buff-1 %if no of buff < min no of big %then min no of big = no of buff no of big req = no of big req+1 x = big buff pt; ! get buffer managers free pointer x = x-k'20000'; ! make it my vm (my seg 3 = bm seg 4) big buff pt = integer(x); ! copy rest of free queue ps = ps&(\k'340'); ! allow ints again #if k mes == record(x) mes_type = mes_type & (8_376) ; ! remove 'free' buffer bit #if d traceid(mes, kernel ser) #fi #fi %result == record(x); ! and pass back result %finish ps = ps&(\k'340') %result == null %end %routine free buffer(%record (mef) %name mes) %integer x %record (pf) p !Frees the block pointed at by M #if d traceid(mes, buffer manager) #fi %unless mes == null %start ;!Safety check for NULL pointer buffers held = buffers held - 1 ps = ps!k'340'; ! put processor status = 7 x = addr(mes)+k'20000'; ! address in buff managers VM. %if mes_type # 0 %start; ! small buffer #if k mes_type = mes_type ! 1 ; ! buffer free flag #fi no of small buff = no of small buff+1 integer(addr(mes)) = small buff pt small buff pt = x %finish %else %start ! %if x < Big Boundary %start; ! neg numbers ! printstring("xpr:bad big"); ! octal(x); ! newline ! ps = ps&(\k'340'); ! ints on ! %return; ! ditch bad buffer (its really a short one) ! %finish #if k mes_type = mes_type ! 1 ; ! buffer free flag #fi no of buff = no of buff+1 integer(addr(mes)) = big buff pt; ! copy in top of chain big buff pt = x; ! and remake 1st entry %finish ps = ps&(\k'340'); ! and allow ints again %finish %end ;!of free block #fi %routine handle output %record (x25f) %name x25 %record (mef) %name m #if b %integer len, type, buff no, x #else %integer len, type, x #fi %return %if active#0 ;!Transmit channel busy %if abort req#0 %then abort(dead) %if istate#0 %start ;!Link setup phase %if istate=sabm queued %start ;!Have sent UA (DTE). Now send SABM type=sabm istate=waiting for ua sabmtx = sabmtx + 1 %elseif istate = uaqueued 1 type=ua %if b = 0 %start ;!LAP-B istate=link up reset line to xgate(link established) %else istate = dce sarm queued %finish uatx = uatx + 1 %elseif istate = uaqueued 2 ;!We have had a DISC from DCE and !must send a UA in reply, with the P/F bit as received type=ua %if dcedte = dte %then istate=sabm queued %else istate = waiting for sabm uatx = uatx + 1 %elseif istate=disc queued ;!We have had either an abort !or a DISC while the link was up. Send a DISC back !and wait for DCE to repoll with DISCs type=disc %if dcedte = dte %then istate = dte waiting for ua %else istate = dce waiting for ua !i.e. down disctx = disctx + 1 %elseif istate = dce sarm queued ;!LAP type = sarm istate = link up reset line to xgate(link established) %else %return %finish -> send unnumbered %else ;!Link up %if rstate = rejpending %start type = rej rejtx = rejtx + 1 rstate = rejsent ;!2 ->send supervisory %elseif rstate = rnrpending ;!6 type = rnr rnrtx = rnrtx + 1 rstate = rnrsent ;!5 ->send supervisory %elseif rstate = rrpending %or (rstate = rejsent %and clock0 >= t1) %or final = set rstate = rrsent %if rstate = rrpending type = rr rrtx = rrtx + 1 clock5 = 0; ! clear the solid RNR Clock ->send supervisory %finish int r: %if ttt#fff %and tstate=0 %and (ttt-aaa)&7#window %start !Something to send/No RNR up from far end/No modulo count runout !respectively %if ttt=xxx %or clock1 >= t1 %start !Branch past this if we are retransmitting and Clock1 is still running wdesc==wspace(ttt) ;!Pick up the top frame on the Q #if b buff no = wdesc_buffno m==map(buff no) #else m == wdesc_m #fi x25==m_x25 len=wdesc_len type=(ttt&7)<<1 %if xxx=ttt %start xxx=(xxx+1)&sfmask itx = itx + 1 %else poll=pending retrytx = retrytx + 1 %finish !If we are not retransmitting, keep high water mark abreast of TTT !If we are, this is a retransmission so has the poll bit set ttt=(ttt+1)&sfmask active=2 ;!Big block being transmitted clock1=0 #if ~f %if int = 'R' %then int = 0 %and active=0 %and ->int r ;!Force a transmit sequence error #fi ->send frame %finish %finish %finish %return send supervisory: send unnumbered: len=2 active=1 x25 == om_m #if b buff no = 0; ! signal internal address #fi send frame: !In LAPB, I,SABM,DISC are always commands. UA,FRMR are responses. ! RR,REJ,RNR can be either ! We will drive REJ as a reply. RR and RNR will be commands if sent as ! idle line polls and responses if prompted by an I or RR command ! Note they must set the poll bit. pfbit=clear ;!Default %if type&1=0 %or type=sabm %or type=disc %then x=command %else x=response %if type = rr %or type = rnr %start x = comres %if x=command %then poll=pending %finish %if type&3 # 3 %then type = eee<<5 ! TYPE %if x=command %and poll=pending %then pfbit=pfset %and poll=sent %if x=response %and final=set %then pfbit=pfset %and final=clear !Calculate the address byte as follows: PSS algorithm is ! Commands DCE--> DTE Address=3 DTE--> DCE Address=1 ! Responses DCE--> DTE Address=1 DTE--> DCE Address=3 %if x=command %then address=1 %else address=3 !Addresses are the other way round for a DCE. %if dcedte=dce %then address=4-address clock0=0 #if ~f %if int = 'B' %then address = 2 %and int = 0 ;!Force a bad address %if int = 'U' %then type = ua %and int = 0 ;!Force a spurious UA %if int = 'X' %then type = x'FD' %and int = 0;!Force a bad ctrl byte #fi !For DQS - we may have shuffled the data one byte to the left. !if so, plant address and control bytes in the shuffled position not where !they normally go. #if q %if addr(x25) & 1 = 0 %or byteinteger(addr(x25)-1) = 0 %start #fi x25_add=address x25_type=type ! PFBIT #if q %else byteinteger(addr(x25_add)-1) = address x25_add = type ! pfbit %finish #fi parb_type=line output parb_b==x25 parb_len=len #if b parb_buff no = buff no #fi !There's no need for the deferred RR once we've sent a frame of any kind rstate = rrsent %if rstate = rrdeferred #if ~f monitor(parb, output tx) #fi to comms hw(parb) %end ;!of handle output %routine handle input #if ~b %record (parf) m #fi %record (x25f) %name x25 %record (wdse) %name imess #if b %integer r, s, x, l, buff no #else %integer r, s, x, l #fi #if b parb_address = parb_address-7; ! get it back at beginning mes == parb_b x25 == mes_x25 buff no = parb_buff no #else x25 == parb_b m_b == x25 ; m_address = m_address - 7 ; ! remove offset to x25 data #fi l = parb_len #if ~f %if int = 'E' %and type&1 = 0 %then l = -2 %and int = 0 !Force a received sequence error #fi %if l<2 %start ;!Bad frame %if l=-2 %start #if ~f monitor(null,dms) #fi clock4=clock4+1 %if clock4>24 %then abort(read fails) #if ~f %elseif l=-1 monitor(null,bad fr) %elseif l=-3 monitor(null,silofull) ;!Keep a count %else monitor(null, short frame) write(l, 3) ;printsymbol(':') write(address, 3) ;write(type, 3) ;write(x25_octet1, 3) newline #fi %finish ->noise %finish %if address&x'FD' # 1 %then monitor(null, bad addrs rx) %and -> noise !Check for bad address. Strictly speaking we should ignore these if we're a DCE pfbit=type&x'10' !Find out what sort of frame this is. We need to know if it is !a command or response (or invalid). x=invalid ;!Guilty till proved innocent %if type&3#3 %start ;!S-frames and I-frames r=(type>>5)&7 ;!Extract N(R) %if type&1=0 %start ;!I-frames. s=(type>>1)&7 ;!Extract N(S) type=iframe x=command %else ;!Supervisory frames type = type & 15 ;!Mask out N(R) and P/F bit %if type=rr %or type=rnr %or type=rej %start ;!Only ones we recognise %if dcedte=dce %then address=4-address ;!Watch out. %if address = 3 %then x = command %else x = response %finish %finish %else ;!Unnumbered frames type = type & x'EF' ;!Mask out P/F bit %if type=sabm %or type=disc %then x=command %if type=ua %or type=frmr %then x = response %finish %if x=command %start comres = response ;!Next frame is a response to this one unless there is a good reason otherwise %if pfbit=pfset %start !Command with poll bit set requires an immediate RESPONSE final=set %if rstate = rrsent %or rstate = rnrsent %start #if b %if no of big buff < big limit %or hold rnr # 0 %start #else %if no of buff < big limit %or hold rnr # 0 %start #fi #if ~f monitor(null, buffers low) #fi rstate = rnrpending %finishelse rstate = rrpending %finish %finish %else %if x=response %and poll=sent %start %if pfbit=pfset %then poll = clear %elsestart #if ~f %if dcedte = dce %then monitor(null, poll failure) #fi %finish %finish %if x=invalid %then monitor(null, badframes rx) %and -> noise %finish ->noise %if abort req#0 %if istate#link up %start %if type=ua %and istate=waiting for ua %then %start istate = link up reset line to xgate(link established) set prio(2); ! link up, so now raise tasks priority level ! important for DUPs when modem signals lost ->valid %finish %if type=sabm %then b = 0 %and istate = uaqueued 1 %and ->valid %if type = sarm %then b = 1 %and istate = uaqueued 1 %and -> valid ;!LAP %if dcedte=dte %start %if type=disc %then istate = uaqueued 2 %and ->valid %if type = ua %then istate = sabm queued %and -> valid %else ;!DCE mode %if type=ua %then istate=waiting for sabm %and ->valid %if type=disc %and istate # dce waiting for ua %and %c istate # disc queued %then istate = uaqueued 2 %and ->valid %finish #if ~f monitor(null,spurious uframerx) #fi ->noise %else ;!LINK UP %if type&3=3 %start %if type=frmr %start frmrrx = frmrrx + 1 %elseif type = sabm abort(sabm received) %elseif type = disc abort(disc received) %finishelse abort(uframe in data) -> noise %elseif type=iframe %if s = eee %start ;!Sequence OK %if l > 2 %start clock4 = 0; ! No too long frame received p_ser=kernel ser p_reply = own id p_fn=input req p_line=line ;!Redundant here #if b p_buff no = buff no #else p_m == m_b #fi mes_len=l-2 ;!Length excluding address & control bytes #if ~f monitor(p,to upper) #fi buffers held = buffers held - 1 irx = irx + 1 ;!Just keep a count #if d traceid(p_m, p_ser) #fi pon(p) #if b buff no = 0;!Avoid freeing buffer #else x25 == null ; !Avoid freeing buffer #fi %finishelse nullrx = nullrx + 1 eee=(eee+1)&7 ;!Increment received sequence no. #if b %if no of big buffnoise %finish %finish %finish ! x=aaa %while x&7#r %cycle %if x=xxx %start #if ~f monitor(null, badack) ;monitor(null, query) ;write(r, 3) ;newline #fi printstring("Bad Ack ") ->valid %finish x=(x+1)&sfmask %repeat %unless active=2 %and (xxx-x)&sfmask <= (xxx-ttt)&sfmask %start !Ignore ack if it includes one for block currently being transmitted %while aaa#x %cycle ;!Free off ackked blocks wdesc == wspace(aaa) #if b free buffer(wdesc_buff no); wdesc_buff no = 0 #else free buffer(wdesc_m) ; wdesc_m == null #fi itx = itx + 1 ;!Just count them #if ~b wdesc_m == null #fi !I have managed to convince myself that TTT could equal AAA !If we receive an ack for a frame while in mid-retransmit !If we dont do this, TTT and AAA could wind up inside-out. ttt = (ttt+1) & sfmask %if ttt = aaa aaa=(aaa+1)&sfmask ;!Increment sequence no. of first frame not ackked xxx=ttt ;clock1=0 ;window=6 ;!Leave Timer recovery condition clock3=0 %repeat %if ttt#xxx %then ttt=aaa ;!Retransmitting: retransmit first unackked frame %if type=rej %start ttt = aaa ;xxx = ttt %if rstate = rrsent %or rstate = rejsent %then rstate = rr pending %finish !to the first one not ackked If a Reject or retransmission %finish %finish ! valid: ! "Valid" here just means that the CRC was OK and it was a recognisable frame clock2=0 ;!Reset validity timer - chops him if this gets too big. noise: #if b free buffer(buff no) %unless buff no = 0 #else free buffer(m_b) %and m_b == null %unless x25 == null %or m_b == im #fi ! handle output ! %end ;!of handle input %routine clock int alarm(25) ;!Replace 1/2 second timer clock0=clock0+1 #if p !Special code for nasty spivvo dup11s !Watchdog expires if rxdone is not followed by an interrupt within !a second or so. %if hw_rcs & rx done # 0 %start rx watchdog = rx watchdog + 1 %if rx watchdog = 5 %start printstring("Rx Watchdog Invoked") ;newline reinitialise hardware %finish %elseif hw_tcs & tx done # 0 tx watchdog = tx watchdog + 1 %if tx watchdog = 5 %start printstring("Tx Watchdog Invoked") ;newline reinitialise hardware active = 0 %finish %finish #fi %if istate#0 %start %if dcedte=dce %start ;!We are configured to be the DCE %if clock0 >= t1-1 %and istate=dce waiting for ua %then %c istate=disc queued %and poll = pending %if clock0>= t1*n2-1 %and istate=waiting for sabm %then %c istate = disc queued %and poll = clear %else ;!We are the DTE %if clock0 >= t1-1 %start %if istate=waiting for ua %start %if clock3 <= n2 %start clock3 = clock3 + 1 istate=sabm queued poll = pending %else istate = disc queued poll = clear %finish %elseif istate = dte waiting for ua %if clock3 <= n2 %start clock3 = clock3 + 1 istate = disc queued poll = pending %else istate = waiting for disc poll = clear %finish %finish %finish %finish %else ;!Link up %if rstate = rrdeferred %start #if b %if no of big buff < big limit %or hold rnr # 0 %then rstate = rnrpending %c #else %if no of buff < big limit %or hold rnr # 0 %then rstate = rnrpending %c #fi %else rstate = rrpending %finish #if b %if no of big buff < big limit %start; ! time this out #else %if no of buff < big limit %start; ! time this out #fi clock5 = clock5 + 1 %if clock5 > 360 %then abort(no buffs) %finish clock2=clock2+1 %if clock2 = n2*t1 %and ttt # aaa %start !No data acknowledged by far end in 80 ticks. abort(line timeout) %finish !Clock 1 is knocked back whenever one of our frames is ackked or !we retransmit. If there is a frame unacknowleged (AAA#TTT) and it !hasnt been ackkecd for 5 seconds we wil retransmit !unless he has RNR up. %if aaa#xxx %then clock1=clock1+1 #if q ! code for dqs losing occasional ints %if clock1 = t1*2 %and active # 0 %start; ! recover it printstring("TX Watchdog Invoked ") hw_tcsr = 0; ! clear it out hw_tcsr = tx go;! kick it (will send grotty frame but who cares!) ! Leave it alone now, as it ought to gen an interrupt %finish %if clock1 > t1*50 %and active # 0 %start; ! had it printstring("Tx Hardware Problem ") reinitialise hardware; ! ditch (&lose) the current block!!!! abort(line timeout) %finish #fi %if clock1 >= t1 %and aaa#ttt %and tstate=0 %start !Enter Timer Recovery state clock3=clock3+1 ttt=aaa ;window=1 %if clock3 >= n2 %then abort(dataretries) %and %return ;!Retry N2 times and give up %else %if clock0 >= t1*2 %and quiet idle =0 %start ;!RCO-Defined line idle poll comres = command #if b rstate = rnrpending %if no of big buff>13) par = par+(pad&k'17700')>>6 %else ;!Otherwise make it a long one #if b mex == map3(buff no); ! nb to seg 3, only to put 'owner' in !! mex_owner = own id; ! nb Causes PROBLEMS with DUP code #fi icurr_len = big buffer length-7 #if b icurr_b = k'100000'; ! always at beginning of seg 4 pad = k'100007'; par = buff no #else pad = icurr_b + 7 #fi %finish #if q par = par + (pad & k'17700') >> 6 ext bits = (par & k'176000') >> 6 cad = par << 6 + pad & k'77' x = cad & x'fffe' ;hw_rcar = x x = -(icurr_len >> 1) ;hw_rwcr = x x = rxgo ! ext bits ;hw_rcr = x #else #if p cad = pad&k'17777'!K'140000'; ! IN SEG NO 6 des_rx_maxln = icurr_len des_rx_seg = par des_rx_pt = cad !If we are running with read-chained-read DUP driver, DUP read is !re-initialised for us. %if line type # 2 %then hw_rcs = hw_rcs!K'100'!RCVEN des_rx_state = 0 #else ext bits = (par&k'176000')>>10 cad = par<<6+pad&k'77' hw_rxaddr = cad save ext bits = (save ext bits&x'c')!ext bits hw_Eaddr = save ext bits hw_rxbc = -icurr_len hw_iccsr = hw_iccsr&(~rxBCzero) hw_iccsr = hw_iccsr!dmaIenb #fi #fi %end; ! of put read on hardware %routine stop(%integer reason) %record (pf) p printstring("Xpro ") ;printstring(longnetname(line)) ;printstring(" disaster") write(reason, 1) ;newline !Gracefully. (This may not be a good idea but we'll try it.) %cycle poff(p) ;!Should be better than a tight loop - !a) Scheduler knows we're suspended b) won't fill poff queue %repeat %end ;!of Stop %routine octal(%integer n) %integer i printsymbol((n >> i)&7+'0') %for i = 15, -3, 0 %end ;!of Octal %routine move(%integer len,from,to) ! ! 'Assembler Routine' to emulate EMAS MOVE. ! Note: 1. No action if LEN<=0 ! 2. Registers 1,2 and 3 used. ! %label uploop, downloop, up, return ! *mov_len,1 ;! Load the length *ble_return ;! Return if less than or equal to zero *mov_from,2 ;! Load the FROM address *mov_to,3 ;! Load the TO address *cmp_3,2 ;!Is TO address > FROM address? *bgt_up ;!Yes - Move from top down in case... *beq_return ;!Move in place - Null function ! ! Loop to move LEN bytes FROM -> TO ! downloop: *movb_(2)+,(3)+ ;! Move the byte *sob_1,downloop ;! decrement & Continue if length not exhausted *br_return ! up: *add_1,2 *add_1,3 uploop: *movb_-(2),-(3) *sob_1,uploop return: %return %end ;!of Move %routine replace read !The object of this routine is to get the next read on as fast as possible. !Side-effect is that once the first read after a reinitialise hardware has !been issued it is never taken off. !The old read returns the actual length read plus a flag via des. We !remembered the read base address in PAD. We return.. !read address in parb_ADDRESS !read length in parb_LEN !x25 address in ADDRESS !x25 control in TYPE !These last two fields are passed up separately to avoid their being !overwritten if we are reading into IM %integer x, flag, ext bits, ad %record (mef) %name mx #if q %if hw_rsr&k'34067' = 0 %start %if hw_rsr&k'1000' # 0 %then flag = -2 %and wcov=wcov+1 %and -> flt ! WC OVERFLOW flag = 0 parb_len = hw_rcar-cad-2 parb_len = parb_len + 1 %if cad&1 # 0 ;!DQS ODD-BYTE ! NUMBER OF BYTES TRANS %if hw_rsr&k'074000' # 0 %then parb_len = parb_len-1 %else flag = -1; ! FRAME ERROR %if hw_rsr&k'20' # 0 %then flag = -3; ! SILO FULL silo = silo+1 flt: hw_rcr = 0; ! CLEAR DOWN hw_rcr = k'10'; ! AND UP AGAIN %finish #else #if p flag = des_rx_flag parb_len = des_rx_pt - cad #else hw_iccsr = hw_iccsr&(~dmaIenb) %if intr&rx Ok # 0 %start; ! nb: intr is global! ! Block in ok flag = 0 parb_len = hw_RXaddr-cad-2 %else ! Block in error %if monbyte >= 8 %start printstring("Err:"); octal(chipstr&x'ff'); newline %finish flag = -1 %if chipstr&abort rec # 0 %then abort rx = abort rx+1 %if chipstr&ovr err # 0 %then wcov = wcov+1 %if chipstr&crc err # 0 %then silo = silo+1 %unless int = '+' %start hw_chipR1 = hw_chipR1&(~act rx); ! force re-synch hw_chipR1 = hw_chipR1!act rx %finish %finish #fi #fi #if b parb_address = pad; parb_buff no = icurr_buff no #else parb_address = pad #fi put read on hardware; ! replace the read now #if b mx == map(parb_buff no) %unless parb_buff no = 0 #else mx == parb_b %unless parb_b == null #fi ! map it on UNLESS its an internal buffer #if q !If it was an odd-byte read, address & type will be in wrong place %if pad & 1 = 0 %start address = mx_x25_add ; type = mx_x25_type %else address = byteinteger(addr(mx_x25_add)-1) ; type = mx_x25_add %finish #else address = mx_x25_add ;type = mx_x25_type #fi #if n %if flag = 0 %and monbyte = 9 %start printstring(" In:"); octal(address); space; octal(type) newline %finish #fi %if flag < 0 %then parb_len = flag %elsestart %if parb_len > big buffer length %start #if q ad = hw_rcar #else #if p ad = hw_rcs #else ad = hw_rxaddr #fi #fi printstring("HW: read len > max:") octal(ad) ;space ;octal(cad) ;space ;octal(parb_len) ;newline #if q %finishelsestart %if parb_address & 1 # 0 %start !DQS doesnt obey odd addresses - received data will !start at parb_address&X'FFFE' so shift up 1 byte to compensate move(parb_len, parb_address&x'FFFE', parb_address) %finish #fi %finish %finish %end %routine to comms hw(%record (parf) %name p) stop(mon hw fail) %if p_b == null %and p_type # initialise #if p %recordformat r1f(%integer n) %recordformat r2f(%record (des2f) %arrayname des) %record (r1f) r1; %record (r2f) %name r2 %constinteger mark = k'377' %constinteger parm = k'101062'; ! MODE=BYTE, NO CRC %integer i %switch typesw(initialise:output done) -> type sw(p_type) type sw(initialise): ! LEN IS NOW THE DEVICE NUMBER (0-2) id = get id maphwr(3) hw == p_b %for i = 1, 1, 7 %cycle; ! FIND ABSOLUTE ADDRESSES raddr(i) = map abs(i<<13, 256, id); ! MY ADDRESSES f = map abs(i<<13, 0, id); ! AND OFF AGAIN %repeat x = dup addr(0) r2 == r1 r1_n = x&k'77'; ! JUST THE PAGE DISPLACEMENT desx == r2_des; des == desx(p_len) des_rx_vec = k'160000'!(P_ADDRESS&K'17777') des_tx_vec = des_rx_vec hw_tcs = 0; hw_rcs = 0; ! ensure ints etc are OFF (stuff pending) hw_tcs = hw_tcs!DRS; ! RESET THE DEVICE i = 0; ! TO FORCE A MOV #0, hw_rdb = i; ! PARM = 0 hw_rcs = hw_rcs!DTR %while hw_rcs&dsr = 0 %cycle; %repeat hw_rcs = hw_rcs!RTS %while hw_rcs&cts = 0 %cycle; %repeat %while hw_rcs&dcd = 0 %cycle; %repeat hw_tcs = hw_tcs!K'100'!SND hw_tdb = tsom %return type sw(output done): ! TRANSMITTER type = line output %if des_tx_flag < 0 %or txreply = 0 %start !! TRANSMITTER ERROR printstring("TX ERROR ") p_len = 1 %else p_len = 0 %finish p_type = line output txreply = 0 %return type sw(input here): %return type sw(line output): !! OUTPUT REQUEST %if tx reply # 0 %then -> abort tx reply = id oseg = p_address #if b par = p_buff no par = raddr(oseg>>13) %if par = 0 #else par = raddr(oseg>>13) #fi %if par = 0 %then -> abort des_tx_seg = par des_tx_pt = p_address&k'17777'!K'140000'; ! IN SEG NO 6 des_tx_sa = p_len; ! LENGHT IN CHARS des_tx_state = 1; ! TELL IT TO EXPECT INTS %return abort: printstring("DUP FAIL ") stop(mon hw fail) #fi #if q %integer i %switch typesw(initialise:modem status) -> type sw(p_type) type sw(initialise): id = get id %for i = 1, 1, 7 %cycle; ! FIND ABSOLUTE ADDRESSES raddr(i) = map abs(i<<13, 256, id); ! MY ADDRESSES f = map abs(i<<13, 0, id); ! AND OFF AGAIN %repeat maphwr(0) p_address = p_address&k'17777'; ! ENSURE ADDRESS IN SEG 0 hw == p_b hw = 0; ! tidy it up hw_mcsr = k'40003'; ! DON'T TRANSFER THE CRC hw_rcr = k'10'; ! ENABLE RECEIVER hw_tcsr = k'10'; ! ENABLE TRANSMITTER rx reply = 0; tx reply = 0 %return type sw(output done): ! TRANSMITTER type = line output %if hw_tcsr < 0 %or txreply = 0 %start !! TRANSMITTER ERROR printstring("TX Error ") p_len = 1 %else p_len = 0 %finish p_type = line output txreply = 0 %return type sw(input here): %return type sw(line output): !! OUTPUT REQUEST %if tx reply # 0 %then -> abort tx reply = id oseg = p_address !Shuffle data one byte left to cope with DQS. Leave a flag !in mes_d0 to remind us not to do it again on retries !oseg-1 should correspond to mes_d0. !Note that short blocks sent from om will be on an even byte !otherwise we would attempt to write a '1' 1 byte in front of om %if oseg&1 # 0 %and byteinteger(oseg-1) = 0 %start move(p_len, oseg, oseg-1); ! _d0 will now benon zero %finish #if b par = p_buff no par = raddr(oseg>>13) %if par = 0 #else par = raddr(oseg>>13) #fi %if par = 0 %then -> abort par = par+(oseg&k'17700')>>6; ! ENSURE ACTUAL BLOCK ext bits = (par&k'176000')>>6 x = par << 6+p_address&k'77' x = x & x'FFFE' ;!DQS ODD-BYTE hw_tcar = x f = 0 x =- ((p_len+1) >> 1) ;hw_twcr = x %if p_len&1 # 0 %start f = k'040000'; ! 8 IN REMAINING BIT FIELD %finish x = tx go!F!EXT BITS ;hw_TCSR = X %return type sw(modem status): %return abort: printstring("DQS Fail ") stop(mon hw fail) #fi #if n ! Newcastle KV11 specific code %integer i %switch typesw(initialise:modem status) -> type sw(p_type) type sw(initialise): id = get id %for i = 1, 1, 7 %cycle; ! FIND ABSOLUTE ADDRESSES raddr(i) = map abs(i<<13, 256, id); ! MY ADDRESSES f = map abs(i<<13, 0, id); ! AND OFF AGAIN %repeat maphwr(0) p_address = p_address&k'17777'; ! ENSURE ADDRESS IN SEG 0 hw_iccsr = clr chip i = 0 %cycle %exit %if hw_iccsr < 0 i = i+1 %exit %if i < 0 %repeat i = 0; ! allow chip to quiese hw_chipR1 = set DTR %cycle; i=i+1; %exit %if i<0; %repeat %if hw_chipstr&DSR # 0 %start printstring("got DSR ") hw_iccsr = hw_iccsr!x1 clock; ! switch to external clock %else printstring("No dsr ") %finish hw_chipR2 = auto flag; ! start flags hw_iccsr = hw_iccsr!intBenb; ! nb:no intAenb now hw_chipR1 = hw_chipR1!Act Tx rx reply = 0; tx reply = 0 %return type sw(output done): ! TRANSMITTER type = line output %if intr&tx bad # 0 %or txreply = 0 %start !! TRANSMITTER ERROR printstring("TX Error:"); octal(intr); newline p_len = 1 %else %if monbyte = 9 %then printstring("Tx Ok ") p_len = 0 %finish p_type = line output txreply = 0 %return type sw(input here): %return type sw(line output): !! OUTPUT REQUEST %if tx reply # 0 %then -> abort tx reply = id oseg = p_address #if b par = p_buff no par = raddr(oseg>>13) %if par = 0 #else par = raddr(oseg>>13) #fi %if par = 0 %then -> abort par = par+(oseg&k'17700')>>6; ! ENSURE ACTUAL BLOCK ext bits = (par&k'176000')>>8 x = par << 6+p_address&k'77' save ext bits = (save ext bits&k'3')!ext bits hw_Eaddr = save ext bits hw_TxAddr = x hw_TxBc = -p_len hw_iccsr = hw_iccsr&(~txbczero) hw_iccsr = hw_iccsr!dmaOenb %if monbyte >= 9 %start #if b printstring("Tx:"); octal(p_buff no); space octal(oseg); write(p_len, 2); newline #fi %finish %return type sw(modem status): ! data set change %if mon byte >= 8 %start printstring("Dschg ") %finish hw_chipR1 = hw_chipR1&(~Act rx) %if chipstr&dsr # 0 %start hw_iccsr = hw_iccsr!x1 clock; ! go external timing %else ! hw_iccsr = hw_iccsr&(~x1 clock); ! internal to stop chip hanging %finish hw_chipR1 = hw_chipR1!Act Rx %return abort: printstring("kv11 Fail ") stop(mon hw fail) #fi %end ;!of to comms hw %routine to xgate(%integer flag) %record (pf) p !Routine to send an 8-byte parameter area to XGATE giving it global !status, namely XPROT UP LINK ESTABLISHED/DOWN. !Differs from RCO-HDLC version in that LINK ESTABLISHED call passes !a Zero as the X25 address. p_ser = kernel ser p_reply = own id p_fn=output req p_line=line #if b p_buff no = 0 #else p_m == null #fi p_c = flag #if ~f monitor(p,to upper) #fi pon(p) %end ;!of to XGATE %endofprogram ! !Compiler is apt to do arithmetic in the LHS when compiling statements !such as LHS = . Doesnt usually matter but bad !news if LHS is a hardware register - Arithmetic will twiddle status !bits etc. version hierarchy: !P = DUP11 only !Q = DQS11 only !F = Fast (Monitoring cut out)