! ROUTE: ! Take as input an ESDL ".BIC" file that has preferably been through ! the VZAP interactive route vetting program. ! Partition net segments into layer groups and examine conflicts. ! RWT September 1986 %begin %include "inc:util.imp" %include "inc:maths.imp" !Reminder of ESDL data format: !ESDL -> ^S [0:eic,1:fic,2:cic,3:bic] UNIT* !UNIT -> ^U [1:spec,2:unit,3:chip,4:board,5:pack] HEAD UNIT* ! ^J nsubs HEAD* {^N{^A netname nfans {subno tno}*}+}* ! ^E !HEAD -> ^H0 nin nout nio nt label name ! {^T tno<<2+[0:dup,1:out,2:in,3:inout] pinname signalname}* ! {^P [1:at,2:on,3:pack,4:subpack,5:delay,6:value,7:size,8:place] parm}* ! ^G !In particular for .BIC files we have: ! ^S3^U4 HEAD(label=circuitname,name=boardname,p7(size)) ^Jn ! {HEAD(label=uselessPACKnumber,name=chipname,p1(ATslotname), ! p2(ONpackname),p7(size),p8(place(x:y)))}n ! {^N{^A ...}+}* ^E ! pinnames in ^T lists take the form x:y/pinname %recordformatspec pinf %recordformatspec netf %recordformat chipf(%record(chipf)%name next,%record(pinf)%name pins, %integer label,name,on,at,wide,high,x,y) %recordformat pinf(%record(pinf)%name nextinchip,nextinnet, %record(chipf)%name chip,%record(netf)%name net, %integer tno,flags,pin,signal,index,x,y) %recordformat netf(%record(netf)%name nextnet,nextsubnet,net, %record(pinf)%name pins, %integer signal,index) %constinteger pat=1,pon=2,psize=7,pplace=8 %integer sym; !Current I-code symbol %string(255)s; !Current I-code string %integer si; !Signal name index, normally -1, but for !a signal A<17>, si would be 17 and s A %constinteger hashmask=63 %recordformat hashf(%record(hashf)%name next,%string(255)s) %record(hashf)%namearray hashtab(0:hashmask) %record(netf)%name nets; !List of nets in main circuit %record(chipf)%name chips; !List of chips in main circuit, of which !the first is the main circuit itself. %integer width,height,power,ground %string(255)file="" %integer layers=4 %integerfn codestring ! Returns a code value which uniquely identifies ! global string S, which is entered in a dictionary. ! This consists of a primary hash table with simple ! unsorted linked lists hanging off each entry. ! The actual number returned is the address of the string. %record(hashf)%name h %integer value=0,i %result = 0 %if length(s)=0 %for i = 1,1,length(s) %cycle value = value<<1+(charno(s,i)!32) %repeat value = value&hashmask h == hashtab(value) %cycle %if h==nil %start; !Tag new entry onto (end of) list h == record(heapget(5+length(s))) h_s = s; h_next == hashtab(value) hashtab(value) == h %result = addr(h_s) %finish %result = addr(h_s) %if h_s=s h == h_next %repeat %end %string(255)%fn hashstring(%integer tag) ! Re-constitutes a hash-coded string %result = "" %if tag=0 %result = string(tag) %end %string(255)%fn indexstring(%integer i) ! Re-constitutes index part of a signal name %string(255)s %result = "" %if i<0 s = itos(i,0) %result = "<".s.">" %end %record(*)%map reverse(%record(*)%name list) ! Reverses an arbitrary singly linked list, provided ! the first field in the record is used for linking. %recordformat f(%record(f)%name next) %record(f)%name head,tail,temp head == list; tail == nil; %result == nil %if list==nil %cycle temp==head; head==temp_next; temp_next==tail; tail==temp %repeatuntil head==nil %result==tail %end ! ESDL I-code input procedures %routine readsym ! Read significant character and store in global SYM. ! NB newlines are not significant but spaces are. readsymbol(sym) %until sym#nl %returnunless sym='^' readsymbol(sym); sym=sym+'^'<<8 %end %routine verify(%integer want) ! Ensure global SYM corresponds to WANT %routine p(%integer x) printsymbol(x>>8) %unless x>>8=0 printsymbol(x) %end %returnif sym=want printstring("Got "); p(sym) printstring(" when expecting "); p(want) newline; %stop %end %routine readstring ! Read string and store in global S and SI (if of form signal) %owninteger dotted=0 %integer indexed=0 %integer len,i si = -1 read(len); readsym; verify(':') length(s) = len %for i=1,1,len %cycle readsym indexed = i %if indexed=0 %and sym='<' charno(s,i) = sym %repeat %if indexed#0 %start length(s) = indexed-1 si = 0 %cycle indexed = indexed+1; i = charno(s,indexed)-'0' %exitunless 0<=i<=9 si = si*10+i %repeat %finish %end %integerfn getnum ! Extract a possibly signed decimal number off the front of global ! string S, which is shortened by the number plus its terminator. %integer n=0,sign=0,pos=1 %while pos<=length(s) %cycle sym = charno(s,pos); pos = pos+1 %if sym='-' %start sign = 1 %finishelseif '0'<=sym<='9' %start n = n*10-'0'+sym %finishelseexit %repeat s = substring(s,pos,length(s)) %result = n %if sign=0 %result=-n %end %predicate contains(%string(*)%name s,%integer k) ! Does string S contain character K? %integer i %for i = 1,1,length(s) %cycle %trueif charno(s,i)=k %repeat %false %end %record(chipf)%map readchips ! Read {^H0 ... ^G}* %integer i %record(chipf)%name chead,ctail %record(pinf)%name phead,ptail ctail == nil readsym %while sym='^H' %cycle readsym; verify('0') chead == new(chead); chead = 0 chead_next == ctail; ctail == chead read(i); read(i); read(i); read(i) {ni,no,nio,nt} readstring; chead_label = codestring readstring; chead_name = codestring ptail == nil; readsym %while sym='^T' %cycle read(i) %if i&3#0 %start; !In,Out,or InOut phead == new(phead); phead = 0; phead_chip == chead phead_nextinchip == ptail; ptail == phead phead_tno = i>>2; phead_flags = i&3 readstring %if contains(s,':') %start phead_x = getnum; verify(':'); phead_y = getnum %finish phead_pin = codestring readstring; phead_signal = codestring; phead_index = si %else; !Dummy pin readstring; readstring %finish readsym %repeat chead_pins == reverse(phead) %while sym='^P' %cycle read(i); readstring %if i=pon %start chead_on = codestring %finishelseif i=pat %start chead_at = codestring %finishelseif i=psize %start chead_wide = getnum; verify(':') chead_high = getnum %finishelseif i=pplace %start chead_x = getnum; verify(':') chead_y = getnum %finish readsym %repeat verify('^G') readsym %repeat %result == chead %end %record(netf)%map readnets ! Read {^N {subnet}*}* %record(netf)%name head,tail %record(netf)%map readsubnets ! Read {^A subnetname pairs {chip pin}*}* %record(netf)%name head,tail %record(pinf)%name p,term %record(chipf)%name sub %integer nfans,subno,tno tail == nil %while sym='^A' %cycle head == new(head); head = 0 head_nextsubnet == tail; tail == head readstring; head_signal = codestring; head_index = si read(nfans); p == nil %while nfans>0 %cycle nfans = nfans-1; read(subno); read(tno) sub == chips ! Scan component list (by position) sub == sub_next %and subno = subno-1 %while subno>0 term == sub_pins ! Scan component's pin list (by pin number value) term == term_nextinchip %while term##nil %and term_tno#tno %if term==nil %start printstring("Terminal "); write(tno,0) printstring(" not found in component ") printstring(hashstring(sub_name)) printstring(" at "); printstring(hashstring(sub_at)); newline %elseif term_flags&4=0; !All is well: not been here before term_flags = term_flags!4; term_net == head term_nextinnet == p; p == term {} term_signal = head_signal; term_index = head_index %finishelseunless term_net==head %start; !Confusion printstring("Terminal"); write(term_tno,1) printstring(", pin ".hashstring(term_pin)) space; printstring(hashstring(term_signal)) printstring(" of ".hashstring(term_chip_label)); space printstring(hashstring(term_chip_name)." at ") printstring(hashstring(term_chip_at)); newline printstring("is already connected to ") printstring(hashstring(term_net_signal)) printstring(indexstring(term_net_index)) printstring(", cannot also connect to ".s) printstring(indexstring(si)); newline %finish %repeat head_pins == p readsym %repeat head == tail %cycle tail_net == head; tail == tail_nextsubnet %repeatuntil tail==nil %result == head %end tail == nil %while sym='^N' %cycle readsym; head == readsubnets head_nextnet == tail; tail == head %repeat %result == head %end ! End of ESDL input stuff %routine generate segment lists %recordformat vf(%short x,y) %recordformat sf(%record(sf)%name f,r,%record(vf)a,b,ab,%short angle,net,flags) %record(sf)%namearray list(1:layers) %record(sf)%name slist,s %integer netno=0,segcount=0,x,y,i %record(netf)%name m,n %record(pinf)%name p %record(sf)%map newseg %record(sf)%name s s == new(s); s = 0 s_f == s; s_r == s %result == s %end %routine add by position(%record(sf)%name i,list) %record(sf)%name l,r r == list r == r_f %until r==list %or r_a_x>=i_a_x %or (r_a_x=i_a_x %and r_a_y>=i_a_y) l == r_r l_f == i; r_r == i i_r == l; i_f == r %end %routine check list(%record(sf)%name slist) %integer checked=0,conflicts=0,overlaps=0,tees=0,crosses=0,count=0,time %record(sf)%name a,b %routine check(%record(sf)%name ab,cd) %record(vf)ac,ad,ca,cb %integer a,b,c,d %routine fromto(%record(vf)%name f,t,ft) ft_x = t_x-f_x ft_y = t_y-f_y %end %integerfn s(%integer x) %result = -1 %if x<0 %result = 0 %if x=0 %result = 1 %end %integerfn vp (%register(a0)%record(vf)%name a,b) ! %result = a_x*b_y-a_y*b_x *move.w a_x,d0; *muls b_y,d0 *move.w a_y,d1; *muls b_x,d1 %result = d0-d1 %end %integerfn lengthsquared(%register(a0)%record(vf)%name z) ! %result = z_x\\2+z_y\\2 *move.w z_x,d0; *muls d0,d0 *move.w z_y,d1; *muls d1,d1 %result = d0+d1 %end checked = checked+1 %returnif ab_net=cd_net fromto(ab_a,cd_a,ac) fromto(ab_a,cd_b,ad) fromto(cd_a,ab_a,ca) fromto(cd_a,ab_b,cb) c = s(vp(ab_ab,ac)) d = s(vp(ab_ab,ad)) %returnif c=d#0 a = s(vp(cd_ab,ca)) b = s(vp(cd_ab,cb)) %returnif a=b#0 %if a=b %or c=d %start overlaps = overlaps+1 %elseif a=-b %if c=-d %then crosses = crosses+1 %else tees = tees+1 %elseif c=-d tees = tees+1 %else %signal 14 %finish conflicts = conflicts+1 ab_flags = ab_flags+1 cd_flags = cd_flags+1 %end time = cputime a == slist_f %cycle count = count+1 b == a_f %while b##slist %and b_a_x<=a_b_x %cycle check(a,b); b == b_f %repeat a == a_f %repeatuntil a==slist time = cputime-time write(count,4; checked,8; conflicts,10; crosses,8; tees,5; overlaps,9; time,5); newline %end %routine add by angle(%record(sf)%name i,list) %record(sf)%name l,r r == list r == r_f %until r==list %or r_a_x>=i_a_x %or (r_a_x=i_a_x %and r_a_y>=i_a_y) l == r_r l_f == i; r_r == i i_r == l; i_f == r %end %routine segment to(%short newx,newy) %record(sf)%name s %if x=-1 %and y=-1 %start x = newx; y = newy; %return %finish segcount = segcount+1 s == newseg s_net = netno s_a_x = x; s_a_y = y s_b_x = newx; s_b_y = newy s_ab_x = newx-x; s_ab_y = newy-y %if s_ab_x<0 %or (s_ab_x=0 %and s_ab_y<0) %start s_a = s_b; s_b_x = x; s_b_y = y s_ab_x = -s_ab_x; s_ab_y = -s_ab_y %finish x = newx; y = newy %if s_ab_y=0 %then s_angle = 0 - %elseif s_ab_x=0 %then s_angle = 90 - %else s_angle = int(180*arctan(s_ab_x,s_ab_y)/pi) add by angle(s,slist) %end %routine pins(%record(chipf)%name c) %record(pinf)%name p %while c##nil %cycle newline p == c_pins %while p##nil %cycle write(p_x,0); write(p_y,1) %if p_signal=power %then printsymbol('P') - %elseif p_signal=ground %then printsymbol('G') - %elseif p_signal=0 %then printsymbol('B') - %elseif charno(hashstring(p_signal),1)='.' - %then printstring(hashstring(p_signal)) - %else printsymbol('S') newline p == p_nextinchip %repeat c == c_next %repeat newline; printstring("-1"); newline %end %routine output list(%integer k) %record(sf)%name l,i write(k,0); newline l == list(k); i == l_f %while i##l %cycle write(i_flags,0; i_a_x,1; i_a_y,1; i_b_x,1; i_b_y,1); newline i == i_f %repeat printstring("-1"); newline %end printstring("Writing part one") openoutput(1,file.".seg"); selectoutput(1) write(width,0; height,1); newline pins(chips) selectoutput(0); newline; printstring("Generating segment list") slist == newseg list(i) == newseg %for i = 1,1,layers m == nets %while m##nil %cycle n == m; m == m_nextnet %if power#n_signal#ground %start netno = netno+1; x = -1; y = -1 %cycle p == n_pins %while p##nil %cycle segment to(p_x,p_y) p == p_nextinnet %repeat n == n_nextsubnet %repeatuntil n==nil %finish %repeat newline; printstring("Partitioning") s == slist_f i = 0 %cycle s == s_f; add by position(s_r,list((i*layers)//segcount+1)) i = i+1 %repeatuntil i=segcount newline printstring("Count checked Conflicts Crosses Tees Overlaps Time"); newline checklist(list(i)) %for i = 1,1,layers printstring("Writing part two") selectoutput(1) output list(i) %for i = 1,1,layers printstring("-1"); newline closeoutput selectoutput(0); newline %end ! Acquire Parameters define param("Filename",file,pamnodefault) define int param("Layers",layers,0) processparameters(cliparam) toupper(file) ! Initialise, Read BIC file hashtab(sym) == nil %for sym = 0,1,hashmask printstring("Reading .BIC file") openinput(1,file.".BIC"); selectinput(1) readsym; verify('^S'); readsym; verify('3') readsym; verify('^U'); readsym; verify('4') chips == readchips width = chips_wide; height = chips_high verify('^J'); read(sym) chips_next == reverse(readchips) nets == readnets verify('^E') closeinput; newline s = ".GND"; ground = codestring s = ".5V"; power = codestring generate segment lists %endofprogram