! NETVET: Interactively process net lists in .NET and .PAG files, using ! position information from the .CPL file, and vet the order in which the ! pins within each net are visitied. For power nets (especially when the ! design is to wire-wrapped) there is the option of splitting large nets ! up into smaller nets. ! RWT March 1990 %include "inc:util.imp" %include "inc:level1.imp" %begin ! String processing %externalintegerfnspec heapget(%integer n) %externalstring(255)%fnspec itos(%integer n,p) %integerfn encode(%string(255)s) ! The string S is converted into a 32-bit number, which is ! used in subsequent processing instead of the string itself. ! The string is stored on the heap and accessed via a linear ! list hung off a hash table. The value returned is the ! address of the string (this is assumed to be positive). ! Special cases: The null string is encoded as the value 0; ! strings which are decimal representations of non-negative ! numbers are encoded as -N-1. %constinteger hashmax=32 %recordformat hr(%record(hr)%name next,%string(*)%name s) %ownrecord(hr)%namearray hashtable(0:hashmax-1) %owninteger initialised=0 %integer h,n,i,num %bytename k %record(hr)%name rec %string(*)%map newstring(%string(255)s) ! Allocate just enough heap space to hold S, and copy it in. %string(*)%name n %ownstring(1)nil = "" %result == nil %if s="" n == string(heapget(length(s)+1)) n = s %result == n %end %result = 0 %if s="" h = 0; n = 0; i = 1; num = 1 %cycle k == charno(s,i) k = k-32 %if k>='a' h = h+h+k %if num#0 %start num = 0 %unless 0<=k-'0'<=9 %if num#0 %start num = 0 %if n<=-3276 %or (n=-3276 %and k>'7') n = n*10-k+'0' %if num#0 %finish %finish i = i+1 %repeatuntil i>length(s) %result = n-1 %unless num=0 %if initialised=0 %start initialised = 1 hashtable(i) == nil %for i = 0,1,hashmax-1 %finish h = h&(hashmax-1); n = 0; rec == hashtable(h) %while rec##nil %cycle %result = addr(rec_s) %if rec_s=s rec == rec_next %repeat rec == new(rec) rec_s == newstring(s) rec_next == hashtable(h); hashtable(h) == rec %result = addr(rec_s) %end %string(255)%fn decode(%integer n) ! Reconstitute a string from its encoded value. %string(255)s s = "" %if n<0 %start s = itos(-1-n,0) %elseif n>0 s = string(n) %finish %result = s %end %recordformat pinfm - (%record(pinfm)%name next,%integer name,%integer x,y) %recordformat compfm - (%record(compfm)%name next,%integer name,%record(pinfm)%name pins) %record(compfm)%name comps == nil %integer minx=256,miny=256,maxx=0,maxy=0 %on 3 %start selectoutput(0) printstring(event_message); newline %return %finish %begin {set up hole matrix as blank, read CPL file} %integer n=0 %integer x,y,prev,this,pin %record(compfm)%name c==nil %record(pinfm)%name p %string(255)s %on 9 %start printstring(" components"); newline %return %finish prev = 0 openinput(1,cliparam.".cpl") %cycle read(s); this = encode(s) {component name} %unless this=prev %start prev = this; c == new(c) c_name = this; c_pins == nil; c_next == comps; comps == c n = n+1; printsymbol(13); write(n,0) %finish read(s); this = encode(s) {pin name} read(x); read(y) {pin coords} x = x//100; y = y//100 minx = x %if xmaxx miny = y %if ymaxy p == new(p); p_name = this; p_x = x; p_y = y p_next == c_pins; c_pins == p %repeat %end %routine box(%integer x0,y0,x1,y1) hline(x0,x1,y0); hline(x0,x1,y1) vline(x0,y0,y1); vline(x1,y0,y1) %end %routine swap(%integername a,b) %integer c; c = a; a = b; b = c %end %constinteger bot=0,top=511,left=0,right=687 %begin {flip board if appropriate, draw it} %record(compfm)%name c %record(pinfm)%name p %integer width=maxx-minx+1,height=maxy-miny+1,n,s,e,w,scale %integer avw=right-left+1,avh=top-bot+1,swapflag=0 %if height>width %start printstring("Converting portrait to landscape."); newline swap(height,width); swap(minx,miny); swap(maxx,maxy) swapflag = 1 %finish %if avw//widthn s = p_y %if p_ye w = p_x %if p_xmax %start max = dist; best == this %finish this == this_next %repeatuntil this==nil %result == best %end %record(netpinfm)%map addto(%record(netpinfm)%name set,item) %result == set %if item==nil item_next == set; %result == item %end %record(netpinfm)%map removefrom(%record(netpinfm)%name set,item) %record(netpinfm)%name pred == set %signal 15,,,"Cannot remove null item from a set" %if item==nil %if item==set %start set == item_next; item_next == nil; %result == set %finish %cycle %signal 15,,,"Item to be removed not found in set" %if pred==nil %if pred_next==item %start pred_next == item_next; item_next == nil; %result == set %finish pred == pred_next %repeat %end %record(netpinfm)%map reverse(%record(netpinfm)%name head) %record(netpinfm)%name item,tail==nil %cycle %result == tail %if head==nil item == head; head == item_next item_next == tail; tail == item %repeat %end %record(netpinfm)%map new pin %record(netpinfm)%name np np == new(np) np_c == c; np_p == p np_x = p_x; np_y = p_y np_next == nil %result == np %end %routine show wires(%record(netpinfm)%name q) %record(netpinfm)%name p==nil %while q##nil %cycle join(p,q); p == q; q == q_next %repeat %end %routine erase colour(black); fill(left,bot,right,top) %end %routine cursor ! Use global variables MOUSEX, MOUSEY, MOUSEB. ! Put up cursor, wait until all buttons released, ! Then move cursor around until (a) button(s) is/are pressed. ! Remove cursor. %integer dx,dy,x,y,b %routine draw %integer l,r,b,t x = left %if xright y = bot %if ytop l = x-7; l = left %if lright b = y-7; b = bot %if btop hline(l,r,y); vline(x,b,t) %end x = mousex; y = mousey enable(8); colour(8); draw b = mousebuttons&7 %until b=0 %cycle dx = relmousex; dy = relmousey; b = mousebuttons&7 %if dx=0 %and dy=0 %start %exitif b#0 %else colour(0); draw x = x+dx; y = y+dy colour(8); draw %finish %repeat mousex = x; mousey = y; mouseb = b colour(0); draw; enable(255) %end %integerfn mousedistanceto(%record(netpinfm)%name p) %result = int(sqrt(sq(p_x-mousex)+sq(p_y-mousey))) %end %routine autosort(%record(netpinfm)%name beg,end) ! Order SET such that the route beginning at BEG, calling at ! every point in SET, and ending at END, is "optimal". In fact ! the optimal solution (involving all permutations) is attempted ! only when SET contains no more than 5 points. Otherwise a simpler ! algorithm (potentially liable to poor behaviour) is used: ! Points in the set are removed and connected to BEG and END alternately ! until the size of the set is reduced to at most 5. The optimal ! solution is applied to what remains. ! If BEG is NIL (in which case END is also NIL), SET contains N points. ! If BEG is not NIL, SET contains N-1 points if END is NIL, otherwise ! SET contains N-2 points. %constshortarray limit(1:5)=5,5,3*5,12*5,60*5 {limit(i) is 5*i!//2} ! For each K from 1 to 5!//2=60, PERMS(5*K:5*K+4) is the Kth permutation of ! {1,2,3,4,5}. In all of these 1 occurs before 2. They are ordered such ! that the first 12 groups all end in 5, the other 4 digits representing the ! permutations of {1,2,3,4}. Similarly the first 3 groups all end in 4,5 ! and represent the 3 permutations of {1,2,3}. %constbytearray perms(5:60*5+4)=- 1,2,3,4,5, 1,3,2,4,5, 3,1,2,4,5, 1,2,4,3,5, 1,4,2,3,5, 4,1,2,3,5, 1,3,4,2,5, 3,1,4,2,5, 1,4,3,2,5, 4,1,3,2,5, 3,4,1,2,5, 4,3,1,2,5, 1,2,3,5,4, 1,3,2,5,4, 3,1,2,5,4, 1,2,5,3,4, 1,5,2,3,4, 5,1,2,3,4, 1,3,5,2,4, 3,1,5,2,4, 1,5,3,2,4, 5,1,3,2,4, 3,5,1,2,4, 5,3,1,2,4, 1,2,4,5,3, 1,4,2,5,3, 4,1,2,5,3, 1,2,5,4,3, 1,5,2,4,3, 5,1,2,4,3, 1,4,5,2,3, 4,1,5,2,3, 1,5,4,2,3, 5,1,4,2,3, 4,5,1,2,3, 5,4,1,2,3, 1,3,4,5,2, 3,1,4,5,2, 1,4,3,5,2, 4,1,3,5,2, 3,4,1,5,2, 4,3,1,5,2, 1,3,5,4,2, 3,1,5,4,2, 1,5,3,4,2, 5,1,3,4,2, 3,5,1,4,2, 5,3,1,4,2, 1,4,5,3,2, 4,1,5,3,2, 1,5,4,3,2, 5,1,4,3,2, 4,5,1,3,2, 5,4,1,3,2, 3,4,5,1,2, 4,3,5,1,2, 3,5,4,1,2, 5,3,4,1,2, 4,5,3,1,2, 5,4,3,1,2 %integer dist,optdist=-1,a,b,c,d,e,oa,ob,oc,od,oe,i,j,x,y %record(netpinfm)%namearray point(1:5) %record(netpinfm)%name p %integerfn distance(%record(netpinfm)%name p,q) %result = 0 %if p==nil %or q==nil %result = {int(sqrt(} sq(p_x-q_x)+sq(p_y-q_y) {))} %end j = n-2 j = j+1 %if beg==nil j = j+1 %if end==nil %cycle %if beg==nil %or end##nil %start %exitif j<=5; j = j-1 %if beg==nil %start p == furthest(set,mx,my) %else p == nearest(set,beg_x,beg_y) %finish set == removefrom(set,p) beg == addto(beg,p) %finish %exitif j<=5; j = j-1 %if end==nil %start p == furthest(set,beg_x,beg_y) %else p == nearest(set,end_x,end_y) %finish set == removefrom(set,p) end == addto(end,p) %repeat %for i = 1,1,5 %cycle point(i) == set set == removefrom(set,set) %unless set==nil %repeat %signal 15,,,"Set not razed" %unless set==nil %for i = 5,5,limit(j) %cycle a = perms(i) b = perms(i+1) c = perms(i+2) d = perms(i+3) e = perms(i+4) dist = distance(beg,point(a)) dist = dist+distance(point(a),point(b)) dist = dist+distance(point(b),point(c)) dist = dist+distance(point(c),point(d)) dist = dist+distance(point(d),point(e)) dist = dist+distance(point(e),end) %if optdist<0 %or distprocess net %finish openinput(1,cliparam.ext); selectinput(1) openoutput(1,cliparam.ext."."); selectoutput(0) %cycle read(net); read(pin); pin -> comp.("-").pin this = encode(net); cn = encode(comp); pn = encode(pin) c == comps %cycle %if c==nil %start printstring("Unknown component "); ->junk %finish %exitif c_name=cn; c == c_next %repeat p == c_pins %cycle %if p==nil %start printstring("Unknown pin ") junk: printstring(comp); printsymbol('-') printstring(pin); printstring(" in net ") printstring(net); newline c == nil; %exit %finish %exitif p_name=pn; p == p_next %repeat %continueif c==nil %if this=prev %start np == newpin square(np,2) set == addto(set,np) n = n+1; mx = mx+p_x; my = my+p_y %else process net: beg == nil; end == nil; ->accept %if set==nil spaces(length(netname)); printsymbol(13) netname = decode(prev); subnetno = 0 printstring(netname); printsymbol(13) enable(green); colour(green) mx = mx//n; my = my//n %if n<=limit %start {No choice for shorties} autosort(nil,nil); showwires(set); ->accept %finish showwires(set) ask1: cursor; enable(green); erase; colour(green) beg == nil %and ->accept %if mouseb=mouseright %if mouseb=mouseleft %start {autoroute from here} %if beg==nil %or end##nil %start beg == nearest(set,mousex,mousey) set == removefrom(set,beg) square(beg,3) end == nil %else set == removefrom(set,beg) end == nearest(set,mousex,mousey) set == removefrom(set,end) square(beg,3) square(end,3) %finish autosort(beg,end); showwires(set); ->ask1 %finish {manually from here} beg == nearest(set,mousex,mousey) set == removefrom(set,beg) square(beg,3) ask2: cursor; enable(green); colour(green) %if mouseb=mousemiddle %start {route to or erase from here} np == nil; end == nil np == nearest(set,mousex,mousey) %unless set==nil end == nearest(beg,mousex,mousey) %unless beg==nil ->ro %if end==nil ->er %if np==nil %if mousedistanceto(end)ask2 %if set==nil %if set_next==nil %start {only one left} join(beg,set) set_next == beg; beg == set; set == nil square(beg,3) %finish %finish ->ask2 %finish %if mouseb=mouseleft %start {complete} %if set==nil %start set == beg; beg == nil; end == nil ->ask1 %finish %cycle np == nearest(set,beg_x,beg_y) set == removefrom(set,np) join(beg,np) np_next == beg; beg == np %repeatuntil set==nil ->ask2 %finish {split net and accept} ->accept %if set==nil subnetno = 1 %if subnetno=0 enable(red); colour(black) selectoutput(1) %while beg##nil %cycle np == beg; outputpin(np); square(np,2) beg == np_next; dispose(np) %repeat newline selectoutput(0) subnetno = subnetno+1 beg == nearest(set,mousex,mousey) set == removefrom(set,beg) enable(green); erase; colour(green); square(beg,3) ->ask2 accept: selectoutput(1) beg == reverse(beg) %while beg##nil %cycle np == beg; outputpin(np); beg == beg_next; dispose(np) %repeat %while set##nil %cycle np == set; outputpin(np); set == np_next; dispose(np) %repeat newline %unless n=0 selectoutput(0) enable(yellow); erase %exitif this=0 prev = this set == newpin mx = p_x; my = p_y; n = 1 colour(red); square(set,2) %finish %repeat selectoutput(1); closeoutput; selectoutput(0); newline erase %end printstring("First: L: Autoroute M: Handroute R: Accept"); newline printstring("Later: L: Complete M: Handroute R: Split"); newline process(".net",5) process(".pag",2) %end %end