! file 'fep_eam77' !******************************** !* emas-2900 fep am1 handler * !* file: eam7 * !* date: 24.mar.82 * !* modified for pcb interface * !******************************** !! stack size = 300 owninteger fep no = 9; ! number supplied on load control 1 include "deimosperm" begin conststring (13)vsn = "am1h:vsn07v " recordformat am1 linkf(integer rxs, rxd, txs, txd) constrecord (am1 linkf) name inter A == k'075160'; ! in seg 3 ? constrecord (am1 linkf) name inter B == k'075170'; ! i/f #2 ownrecord (am1 linkf) name l == 1; ! supplied on start recordformat nsi3f(byteintegerarray a(0:100)) recordformat mef(record (mef) name link, c byteinteger len, type, record (nsi3f)nss) ! think about the position of 'len' recordformat m2900f(record (mef) name link, byteinteger len, type, c integer stream, sub ident, c p2a, p2b, p3a, p3b, p4a, p4b, p5a, p5b, p6a, p6b) recordformat m2900cf(record (mef) name link, byteinteger len, type, c byteintegerarray b(0:23)) recordformat pe(byteinteger ser, reply, c fn, port, record (mef) name mes, integer str) recordformat p2f(byteinteger ser, reply, c fn, port, record (mef) name mes, integer str) recordformat qf(record (mef) name e) !******************************************************** !* formats of tables, ie stream descriptors, tcps etc * !******************************************************** recordformat streamf(integer owner, id 2900) !************************************************************* !* am1 commands (when the ninth bit is set) !************************************************************* constinteger primary = x'00' constinteger funny = 1 constinteger read = x'02' constinteger write c = x'03' constinteger sense = x'04' constinteger write control = x'05' constinteger identify = x'0a' constinteger limit = x'0c' constinteger property = x'0e' !***** primary status bits (11/34 -> 2900) constinteger unsuccessful = x'80' constinteger attention = x'20' constinteger terminated = x'10' constinteger short block = x'08' constinteger long block = x'04' constinteger condition x = x'02' constinteger condition y = x'01' !****************************************** !* 2900 constants !****************************************** constinteger property code = 14; ! as defined by k.y. constinteger attn byte = x'80' !******************************************************** !* 2900 am1 link transmitter & receiver bits !******************************************************** constinteger int on = k'100'; ! both constinteger ready = k'200'; ! both constinteger scfy = k'010'; ! transmitter only (txfy) constinteger maint = k'002'; ! force parity inbound error constinteger operable = k'004'; ! transmitter only constinteger comm bit = k'001' constinteger accept char = k'002'; ! really 'fetch next' constinteger rset = k'004' constinteger acfy = k'010'; ! peter calls it rxfy constinteger xopl = k'020'; ! x operable - latched constinteger xop = k'040'; ! x operable !************************************************************** !* buffer manager calls (from and to) * !************************************************************** constinteger buffer here = 0 !********** to buffer manager *********** constinteger request buffer = 0 constinteger release buffer = 1 !************************************************************** !* calls to 2900 link handler * !************************************************************** constinteger send data = 0 constinteger low level control = 1 constinteger here i am = 2 constinteger return control = 3 constinteger stop = 4 constinteger high lev con len = 24 ! %constinteger low lev con len = 8 !************************************************************** !* replies from 2900 link handler * !**************************************************************** constinteger interf addr = 0 constinteger do input = 1 constinteger do output = 2 constinteger message = 3 constinteger mainframe up = 4 constinteger mainframe down = 5 !*************************************************** !* am1 link states !*************************************************** constinteger idle = 0 constinteger user reading = 2 constinteger user writing = 3 constinteger terminate = 4; ! -> idle constinteger prop 1 = 5; ! -> prop 2 constinteger prop 2 = 6; ! -> prop 3 constinteger prop 3 = 7; ! -> prop 4 constinteger prop 4 = 8; ! -> terminate constinteger ident 1 = 9; ! -> ident 2 constinteger ident 2 = 10; ! -> terminate constinteger next control = 11; ! -> control m constinteger control m = 12; ! -> control m 2 constinteger control m2 = 13; ! -> control m 2, or terminate constinteger term x pend = 14; ! -> term x bit ? constinteger term x bit = 15; ! (?) -> idle constinteger error = 16; ! -> idle !! in state states constinteger initial 4 = 1; ! states of in state constinteger user read = 2 constinteger user write = 3 constinteger control input trf = 4 constinteger control output trf 1 = 5 constinteger control output trf 2 = 6 constintegerarray next state(idle:error) = idle, error, error, error, idle, prop 2,prop 3, prop 4, terminate, ident 2, terminate, control m, control m2, control m2, term x bit, idle, idle !**************************************************************** !********** various service numbers ************* constintegername no of small == k'100114'; ! in buff manager constinteger gate ser = 16 constinteger buffer manager = 17 constinteger link handler = 18 constbyteinteger am1 rx int = -13; ! ???????????????????????? constbyteinteger am1 tx int = -14; ! ???????????????????????/ constinteger t3 ser = 21 constbyteintegername change out zero == k'160310' !************************************************************ !! state variables owninteger state = 0; ! transmitter state owninteger in state = idle; ! input state owninteger to 2900 control; ! end of outward transfer buff owninteger control pt; ! start of same owninteger x bit sent; ! 1 = x bit sent (or about to) owninteger tx int expected; ! 1 = interrupt expected owninteger term cond = terminated; ! holds condition to go on terminate owninteger down = 1; ! 0 = up, 1 = down owninteger clock = 0; ! missing interrupt count owninteger mon = 1; ! monitoring flag owninteger swabf = 1; ! swab flag owninteger tot out l = 0; ! counts control output mess owninteger xop status = 0 owninteger read rej = 0; ! number of 'out of buffers' owninteger i int, o int, ich, o ch constbyteintegerarray swabx(0:23) = 1, 0, 3, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 !! constinteger lower = -2, upper = 400 ownrecord (streamf) array sta(lower:upper) ownrecord (streamf) name str ownrecord (m2900cf) name outm ownrecord (qf) mq; ! = k'143362' record (pe) p ownrecord (qf) name buffer pool owninteger no of buff = 0 integer i owninteger prflag = 0; ! dump print flag - temporary owninteger mon pt = 0 constinteger mon lim = 63 ownbyteintegerarray mon1(0:mon lim) ownintegerarray mon2(0:mon lim) !************************************************** !* routine specs !************************************************** routinespec input interrupt routinespec output interrupt routinespec output routinespec interrupt am1 routinespec user call routinespec stop interface routinespec clock int routinespec up down(integer which) routinespec free buffer(record (mef) name mes) record (m2900f) mapspec get buffer routinespec fault(integer stream, type, add) routinespec monitor(integer type, info) routinespec octal(integer i) routinespec dump regs !********************************************** !* initialisation * !********************************************** map hwr(3); ! map top seg to seg 3 linkin(link handler) linkin(am1 rx int); linkin(am1 tx int) printstring(vsn) i = map virt(buffer manager, 5, 4); ! map to my seg 4 i = map virt(buffer manager, 6, 5); ! and seg 6 to my 5 sta(2)_id 2900 = 2; ! artificially set stream 2 up p_ser = 0; poff(p); ! wait for fep no fep no = p_fn; ! supplied by load prog l == p_mes; ! set hardware address printstring("fep"); printsymbol(fepno+'0') newline alarm(50) change out zero = t3 ser; ! switch o/p to comm !! remove the tx int bit, set the rx int bit and accept char? l_txs=operable; l_rxs=accept char!int on cycle p_ser = 0; poff(p) if p_ser = own id and p_reply = 0 start ; ! clock int alarm(50) if 'm' <= int <= 'o' start mon = int-'o'; int = 0 finish if '1' <= int <= '2' start if down = 0 start printstring("Am1h: Wait till Emas is down ") else l_rxs = l_rxs&(¬int on); ! ints off on old interface printstring("Am1h: Going to Interface "); printsymbol(int) newline if int = '1' then l == inter A else l == inter B l_txs = operable; l_rxs = accept char!int on finish int=0 finish if int = 'F' start int = 0 i = mon pt selectoutput(1) cycle if mon1(i) # 0 start space printsymbol(mon1(i)); write(mon2(i), 3) if i & 15 = 0 then newline finish i = (i+1)&mon lim repeat until i = mon pt newline selectoutput(0) finish if int = 'x' start dump regs int = 0 finish if int = 'Z' start stop interface p_ser = 0; poff(p) stop finish if int = '?' start int = 0 printstring("am1h: buf ="); write(no of buff, 1) printstring(", rej ="); write(read rej, 1); newline printstring("i int ="); write(i int, 1); printstring("o int =") write(o int, 1); printstring(" i ch="); write(i ch, 1) printstring(" o ch ="); write(o ch, 1); newline i int = 0; o int = 0; i ch = 0; o ch = 0; finish clock int continue finish if mon # 0 start ; ! monitoring if p_reply = 0 then i = p_ser else i = p_fn monitor('m', i) finish if p_ser = link handler start user call finish else if p_ser = am1 rx int&x'ff' start input interrupt finish else if p_ser = am1 tx int&x'ff' then output interrupt repeat !******************************************************** !* routines * !******************************************************** routine input interrupt !************************************************* !* first part of any transfer is four bytes * !* two byte stream no, two byte max length * !************************************************* integer pp, error type, ninth bit, sym, stream, max integer ind, s2, sub ident, extra, i recordformat byteaf(byteintegerarray b(0:200)) recordformat intaf(integerarray a(0:100)) recordformat r3f(integername x) recordformat r4f(record (m2900f) name m) recordformat m2900df(byteintegerarray b(0:23)) recordformat mbf(integer link, two, record (m2900df) m) ownrecord (byteaf) header record (intaf) name head2 record (m2900f) name m2900 record (r3f) r3; record (r4f) name r4 record (mbf) name mb record (p2f) p2 switch state sw(idle:control output trf 2) switch control(0:15) pp = 0 head2 == header l_rxs = l_rxs&(¬int on) cycle i = 1000 while l_rxs&(ready!xopl) = 0 and i > 0 cycle ; i = i-1; repeat monitor('*', i) if mon # 0 and i # 1000 if i = 0 start ; ! timeout dump regs fault(instate, 't', state) instate = idle exit finish if l_rxs&xopl # 0 start ; ! x operable has gone down if xop status # 0 start ; ! print change only printstring("xop down!"); dump regs finish monitor('r', instate) if mon # 0 l_rxs = l_rxs&(¬xopl) l_txs = l_txs&(¬int on) in state = idle tx int expected = 0 unless outm == null start push(mq, outm) outm == null; ! put message back on q finish xop status = 0 if l_rxs&xop # 0 start printstring("xop up again ") l_rxs = l_rxs!accept char finish exit finish if xop status = 0 # l_rxs&xop start ; ! xop has come back l_rxs = l_rxs&(¬rset); ! i/f leaves rset on after xop back cycle i = 1,1,200; repeat ; ! wait two millisecs. if l_rxs&(ready!acfy!comm bit) c = (ready!acfy!comm bit) start xop status = 1 finish else start dump regs; newline extra = l_rxd error type = 6; ->fail it finish finish ninth bit = l_rxs&comm bit i ch = i ch+1 sym = l_rxd if l_rxs&acfy # 0 start ; ! failed to read sym = l_rxd; ! retry if l_rxs&acfy # 0 start ; ! hard failure printstring("am1: parity error ") error type = 7; extra = l_rxd; -> fail it finish finish l_rxs = l_rxs!accept char if ninth bit = 0 start ; ! 'true' data if pp>200 start ; ! not normal printstring("am1h:Missing control bit on link! ") pp = 0; !junk the bad data ! h/w has obviously had it finish header_b(pp+swabf) = sym pp = pp+1; swabf = swabf!!x'fffe'; ! flip 1 -> -1 -> 1 !************************************************* !* note: all 'data' bytes swapped on entry * !************************************************* monitor('i', sym) if mon # 0 continue ; ! get next char finish if mon # 0 then monitor('c', sym) ->control(sym&15); ! control command control(limit): if state # idle start monitor('x', state) if mon # 0 state = terminate exit if tx int expected # 0; ! will be coming ->check transmitter finish control(write c): control(read): ->state sw(in state) control(property): to 2900 control = 0; term cond = terminated; x bit sent = 0 up down(0); ! now up state = prop 1; ->check transmitter control(identify): state = ident 1; -> check transmitter control(sense): state = prop 3; ! sends 0, 0 check transmitter: ! attempt to send a character output exit state sw(initial 4): if down # 0 then error type = 9 and -> fail it if pp # 4 start error type = 1; extra = pp; -> fail it finish stream = head2_a(0); max = head2_a(1) monitor('s', stream) if mon # 0 str == sta(stream) if stream > 0 start ; ! data coming/going if str_owner # 0 start p_ser = str_owner; p_reply = link handler p_mes == null p_port = max p_str = stream pp = 0 in state = (stream&1)+user read ! even = am1 input, odd = am1 output state = terminate; output; ! send a 'prim stat' continue !* ie pick up the 'write c' or 'read' before going to user finish error type = 2; extra = stream; ->fail it; ! stream not in use finish !* must be a control stream transfer ******** pp = 0 if stream = -2 start !! inward control stream in state = control input trf else !! outward control stream (-1) in state = control output trf 1 finish state = terminate output exit state sw(user read): ! pick up 'read' command state sw(user write): ! pick up 'write' command if pp # 0 start error type = 3; extra = pp; ->fail it; ! data not expected finish p_fn = in state-1; ! read=2=doinput, write=3=dooutput pon(p) state = in state; ! transfer 11/34 -> am1 or reverse return state sw(control input trf): ! ie 11/34 -> 2900 control pt = 0 in state = idle; ! nothing more coming in state = control m if mq_e == null start monitor('?', to 2900 control) if mon # 0 state = terminate finish -> check transmitter state sw(control output trf 2): ! ie 2900 -> 11/34 !* after the 'limit' - data has been read !! now cycle up the buffer, firing the requests ind = 0; r4 == r3 cycle s2 = head2_a(ind); r3_x == head2_a(ind) if s2 # -1 start sub ident = head2_a(ind+1) if mon # 0 then monitor('l', s2) if s2 < lower or s2 > upper start fault(s2, 's', ind); exit finish str == sta(s2) if str_owner = 0 then fault(s2, 's', ind) elsestart m2900 == get buffer mb == m2900; ! align it to data area mb_m = r4_m; ! and copy it accross !! pick up "id 2900" if its a connecting messgae if mb_m_b(5) = 2 then str_id 2900 = m2900_p2b p2_ser = str_owner; p2_reply = link handler p2_fn = message p2_mes == m2900 pon(p2) finish finish ind = ind+high lev con len//2 exit if ind >= pp//2 repeat in state = idle state = term x bit; ! send x bit if necessary output exit control(write control): ! write control from 2900 !! this can only happen at the beginning of a transfer !! from the 2900, so whatever the state, force it to idle state sw(idle): extra = pp if pp # 0 then error type = 6 and -> fail it ! no control char ?? clock = 0 swabf = 1; ! used to "swab" the bytes in state = initial 4; continue state sw(control output trf 1): ! seen the 'write' command in state = control output trf 2 if no of small+no of buff < 7 or int='L' start read rej = read rej+1 in state = idle state = term x bit output while l_txs&ready = 0 cycle ; repeat i = l_rxd l_rxs = l_rxs!accept char monitor('q', read rej) if mon # 0 exit finish repeat l_rxs = l_rxs!int on return control(funny): ! should not occur control(primary): control(6):control(7):control(8): control(9):control(11):control(13):control(15): error type = 5; extra = sym fail it: fault(error type, 'i', extra) l_rxs = l_rxs!int on; in state = idle term cond = unsuccessful!terminated; state = terminate unless outm == null then free buffer(outm) and outm==null output end routine output interrupt !******************************************** !* routine handles output interrupt from am1 * !********************************************* o int = o int+1 l_txs = l_txs&(¬int on) if tx int expected = 0 start fault(0, 'o', state) else if tx int expected = 2 start ; ! special case of accept char !user has handed back control after reading from am1 !this handler must now say 'next char', but only after ! the GPC has seen the terminate tx int expected = 0 l_rxs = l_rxs!accept char l_rxs = l_rxs!int on monitor('u', in state) if mon # 0 in state = idle unless mq_e == null then interrupt am1 return finish tx int expected = 0; clock = 0 output; ! see whats up finish end routine output !! this routine is entered to check whether a character can !! be send to the 2900 !! if it can, then characters are sent until - !! 1) it goes 'busy' - in which case an interrupt is requested !! 2) all has gone - the state then goes to idle integer i, sym, ostate switch ts(idle:error) cycle if l_txs&ready = 0 start ; ! 'busy' l_txs = l_txs!int on; ! put ints on tx int expected = 1; ! set the flag return finish l_txs = l_txs&(¬comm bit); ! ensure ninth bit off ostate = state -> ts(state) ts(term x bit): ! send terminate+x bit if necessary sym = term cond!x bit sent -> set comm bit ts(terminate): sym = term cond set comm bit: l_txs = l_txs!comm bit monitor('d', -sym) if mon # 0 term cond = terminated -> send ts(prop 1): sym = property code; -> send ts(prop 2): sym = fep no; -> send ts(prop 3): ts(prop 4): ts(ident 1): sym = 0; -> send ts(ident 2): sym = attn byte; -> send ts(control m): ! set up transfer outm == pop(mq); ! get next entry to 2900 control = outm_len; ! get the length control pt = 0; ! start at beginning ts(control m2): sym = outm_b(swabx(control pt)) control pt = control pt+1; tot out l = tot out l+1 if control pt = to 2900 control start free buffer(outm) outm == null unless mq_e == null or tot out l > 180 start state = next control; ! get the next buffer else state = term x pend !! ** next state = term x bit - send x bit if necessary to 2900 control = 0 x bit sent = 0 unless mq_e == null then interrupt am1 finish finish send: o ch = o ch+1 if l_txs&comm bit # 0 and sym = (unsuccessful!terminated) start ! print string("abterm")! dump regs l_txd = sym l_rxs = l_rxs!accept char if l_rxs&acfy = 0 finish else l_txd = sym monitor('d', sym) if mon # 0 state = next state(state) repeat ts(error): ts(user reading): ts(user writing): ts(next control): ts(term x pend): int = 'F' if prflag = 0; prflag = 1 fault(state, 'e', ostate) ts(idle): end routine interrupt am1 if state = idle and in state = idle start term cond = attention; state = terminate output; ! kick the transmitter finish x bit sent = condition x tot out l = 0 end routine user call !**************************************************** !* reasons * !* 0) send data - high level control * !* 1) low level control * !* 2) here i am - ipl info wanted * !* 3) return control - was reading/writing * !**************************************************** constintegerarray typea(0:5) = terminated, short block, long block, unsuccessful, condition y, terminated integer fn, i, len, pp, stream byteinteger ind record (m2900f) name m2900 record (m2900cf) name m2900c switch user sw(send data:stop) ->user sw(p_fn) user sw(send data): ! high level control ->2900 user sw(low level control): len = high lev con len m2900c == p_mes; m2900 == m2900c stream = sta(m2900_stream)_id 2900 if stream = 0 start ; ! error printstring("am1: attempt to send zero stream, stream = ") write(m2900_stream, 1); write(m2900_sub ident, 1) write(m2900_p2a, 1); newline free buffer(m2900); return ; ! junk it finish m2900_stream = stream m2900_len = len; ! hold its length if down = 0 start ; ! 2900 is up if mq_e == null then interrupt am1 push(mq, m2900) !****************************************************** !* note: stream & sub ident are alwys swabbed !******************************************************* finish else free buffer(m2900); ! junk it return user sw(return control): unless user reading <= state <=user writing start fault(in state, 'r', state) else ind = p_str; ! type of termination if ind&64 = 0 start ; ! xopl not set. term cond = typea(ind&7)!terminated; ! send the terminate state = term x bit; ! append x bit as necessary output if ind&128 # 0 start ; ! char to accept l_txs = l_txs!int on; ! wait for GPC to terminate tx int expected = 2; ! with special flag set return ; ! and wait finish finish ints on: l_rxs = l_rxs!int on; in state = idle finish return user sw(here i am): stream = p_str sta(stream)_owner = p_reply; ! enable the stream if stream < 10 start ; ! control streams p_ser = p_reply; p_reply = link handler p_fn = interf addr; p_mes == l; ! pass addr of "l" pon(p) finish return user sw(stop): ! stop the am1 stop interface end !* routine clock int routine stop interface l_txs = l_txs&(¬(operable!int on)) l_rxs = l_rxs&(¬int on) end routine clock int !! handles clock interrupts integer i if tx int expected # 0 or x bit sent # 0 start clock = clock+1 monitor('w', clock) if mon < 0 and clock&3 = 0 if clock = 5 start ; ! emergency action printstring("am1:dying") dump regs l_txs = l_txs&(¬operable); ! drop operable cycle i = 1,1,10; repeat ; ! delay l_txs = l_txs!operable return finish if clock = 10 and l_txs&ready#0 then interrupt am1 if clock = 20 start ; ! 20 sec timeout fault(x bit sent, 'c', tx int expected) up down(1) state = idle; in state = idle l_txs = l_txs&(¬int on) int = 'F' finish finish else clock = 0 end !* routine up down routine up down(integer which) integer i, ser down = which cycle i = 2, 1, 6; ! send 'status' message to itp, rje ftp ser = sta(i)_owner if ser # 0 start if down = 0 start ; ! going up p_ser = ser; p_reply = link handler p_fn = interf addr; p_mes == l; ! pass 'l' (it may have changed) pon(p) finish p_ser = ser; p_reply = link handler p_fn = mainframe up+which p_mes == null pon(p) finish repeat !* tidy up variables x bit sent = 0; tx int expected = 0 while not mq_e == null cycle free buffer(pop(mq)) repeat unless outm == null then free buffer(outm) and outm==null end routine free buffer(record (mef) name mes) record (pe) p if no of buff > 13 or mes_type = 0 start !release if q too big, or its a big block p_ser = buffer manager; p_reply = own id p_fn = release buffer; p_mes == mes pon(p) else !! q it mes_link == buffer pool; buffer pool == mes no of buff = no of buff+1 finish end record (m2900f) map get buffer if buffer pool == null start ; ! ask for it p_ser = buffer manager; p_reply = own id p_fn = request buffer; p_str = 1; ! short buffer ponoff(p) else p_mes == buffer pool; buffer pool == p_mes_link p_mes_link == null no of buff = no of buff-1 finish result == p_mes end routine fault(integer stream, type, add) printstring("am1: fault "); printsymbol(type) write(stream, 3) printstring(", "); write(add, 1); newline monitor('f', type) if int # 'a' end routine monitor(integer type, info) mon1(mon pt) = type; mon2(mon pt) = info mon pt = (mon pt+1)&mon lim end routine octal(integer i) integer n space cycle n = 15, -3, 0 printsymbol((i>>n)&7+'0') repeat end routine dump regs printstring(" r"); octal(l_rxs) printstring(" t"); octal(l_txs) newline end endofprogram