--CellsTry --this module attempts to make an initial ordering of the columns DIRECTORY IODefs: FROM "IODefs", CellsDefs: FROM "CellsDefs"; CellsTry:PROGRAM IMPORTS IODefs, CellsDefs EXPORTS CellsDefs= BEGIN OPEN CellsDefs; Error:SIGNAL=CODE; Space:CHARACTER=' ; Ret:CHARACTER=' ; Id:TYPE=INTEGER; Signal:TYPE=INTEGER; Group:TYPE=INTEGER; Remember:TYPE=INTEGER; maxGroup:INTEGER=500; maxIds:INTEGER=2000; maxSignal:INTEGER=signalMax; GroupEntry:TYPE=RECORD[active,chain:Id]; Ids:TYPE=RECORD[sig:Signal, chain:Id, active:BOOLEAN]; Use:TYPE=RECORD[total,used:[0..256)]; RememberEntry:TYPE=RECORD[type:INTEGER, me,friend,other:Signal]; groupsType:TYPE=ARRAY [0..maxGroup) OF GroupEntry; -- a group is all the ids connecting to a particular track signal idsType:TYPE=ARRAY [0..maxIds) OF Ids; --ids are list storage for constructing groups useType:TYPE=ARRAY [0..maxSignal) OF Use; --to keep track of how many instances of a signal name exits rememberType:TYPE=ARRAY [0..maxGroup) OF RememberEntry; columnListType:TYPE=ARRAY [0..maxSignal) OF Signal; groups:LONG POINTER TO groupsType; ids:LONG POINTER TO idsType; use:LONG POINTER TO useType; remember:LONG POINTER TO rememberType; columnList:LONG POINTER TO columnListType; nextId:Id; nextRemember:Remember; groupEnd:INTEGER←0; ClusterColumns:PUBLIC PROCEDURE= {SigToGroups; MakeUseCounts; Reduce; Rebuild; FixEnds; NumberColumns}; SigToGroups:PROCEDURE=BEGIN ids↑←ALL[[0,-1,FALSE]]; nextId←0; groups↑←ALL[[0,-1]]; groupEnd←0; FOR s:Signal IN [0..maxSignal) DO IF sig[s].def=NIL THEN LOOP; groupEnd←MAX[groupEnd,s+1]; Append[s,s]; SELECT sig[s].def.s.type FROM norPullUp=>BEGIN base:Signal←sig[s].def.s.e; --Append[base,base]; FOR j:TList←sig[s].def.next, j.next UNTIL j=NIL DO IF j.s.type=norPullDown THEN {Append[j.s.d,j.s.d]; Append[j.s.d,base]}; ENDLOOP; END; pass1=>BEGIN --Append[sig[s].def.s.d,sig[s].def.s.d]; Append[sig[s].def.s.d,sig[s].def.s.g]; Append[sig[s].def.s.d,sig[s].def.s.e]; END; ENDCASE; ENDLOOP; FOR s:Signal IN [0..maxSignal) DO IF sig[s].def=NIL THEN LOOP; SELECT sig[s].def.s.type FROM wire=>BEGIN base:Signal←sig[s].def.s.e; FOR j:TList←sig[s].def.next, j.next UNTIL j=NIL DO t:Id=groups[base].chain; q:Id=groups[j.s.d].chain; l:Id←-1; FOR k:Id←q,ids[k].chain UNTIL k=-1 DO l←k; ENDLOOP; groups[base].chain←q; --groupEnd←MAX[groupEnd,base]; IF l#-1 THEN ids[l].chain←t; groups[j.s.d].chain←-1; --groupEnd←MAX[groupEnd,j.s.d]; SubstituteX[base,j.s.d]; ENDLOOP; END; ENDCASE; ENDLOOP; MakeActiveCounts[]; END; SubstituteX:PROCEDURE[new,old:Signal]=BEGIN t,f:Id; IF new=old THEN Error; FOR g:Group IN [0..maxGroup) DO FOR i:Id←groups[g].chain,ids[i].chain UNTIL i=-1 DO IF ~(ids[i].sig=old AND ids[i].active) THEN LOOP; t←-1; FOR j:Id←groups[g].chain,f UNTIL j=-1 DO f←ids[j].chain; IF ids[j].sig=new THEN {IF t=-1 THEN groups[g].chain←f ELSE ids[t].chain←f}; t←j; ENDLOOP; ids[i].sig←new; ENDLOOP; ENDLOOP; END; Append:PROCEDURE[from,to:Signal]=BEGIN t:Id=nextId; FOR i:Id ←groups[to].chain,ids[i].chain UNTIL i=-1 DO IF ids[i].sig=from THEN RETURN; ENDLOOP; nextId←nextId+1; IF nextId>=maxIds THEN {Error; RETURN}; ids[t]←[from,groups[to].chain,TRUE]; groups[to].chain←t; END; MakeActiveCounts:PROCEDURE=BEGIN FOR g:Group IN [0..groupEnd) DO n:INTEGER←0; FOR i:Id ←groups[g].chain,ids[i].chain UNTIL i=-1 DO IF ids[i].active THEN n←n+1; ENDLOOP; groups[g].active←n; ENDLOOP; END; MakeUseCounts:PROCEDURE=BEGIN use↑←ALL[[0,0]]; FOR g:Group IN [0..groupEnd) DO IF groups[g].active=0 THEN LOOP; FOR i:Id ←groups[g].chain,ids[i].chain UNTIL i=-1 DO IF ~ids[i].active THEN LOOP; use[ids[i].sig].total←use[ids[i].sig].total+1; ENDLOOP; ENDLOOP; END; Reduce:PROCEDURE=BEGIN remember↑←ALL[[0,0,0,-1]]; nextRemember←0; PrintGroups[]; FOR g:Group IN [0..groupEnd) DO IF groups[g].active=1 THEN BEGIN friend:Signal←ids[groups[g].chain].sig; IF use[g].total=0 THEN BEGIN IF g=friend THEN Error; RememberMe[4,g,friend,-1]; END; KillGroup[g]; END; ENDLOOP; DO FOR hard:INTEGER IN [0..2] DO progress:BOOLEAN←FALSE; PrintGroups[]; --PrintUse[]; PrintRemember[]; FOR s:Signal IN [0..maxSignal) DO excess:INTEGER=use[s].total-use[s].used; IF hard=2 THEN {IF excess>0 AND ReduceParallelUses[s] THEN progress←TRUE} ELSE SELECT excess FROM 0=>NULL; 1=>{ReduceSingleUses[s]; progress←TRUE}; 2=>IF hard=1 AND ReduceDoubleUses[s] THEN progress←TRUE; ENDCASE; ENDLOOP; IF progress THEN EXIT; IF hard=2 THEN BEGIN FOR g:Group IN [0..groupEnd) DO IF groups[g].active#0 THEN {ReduceRandomly[g]; progress←TRUE; EXIT}; ENDLOOP; IF progress THEN EXIT; RETURN; END; ENDLOOP; ENDLOOP; END; ReduceRandomly:PROCEDURE[g:Group]=BEGIN FOR i:Id←groups[g].chain,ids[i].chain UNTIL i=-1 DO IF ~ids[i].active THEN LOOP; ids[i].active←FALSE; use[ids[i].sig].used←use[ids[i].sig].used+1; DecrementActive[g]; RETURN; ENDLOOP; Error; END; ReduceSingleUses:PROCEDURE[s:Signal]=BEGIN --s occurs exactly once FOR g:Group IN [0..groupEnd) DO IF groups[g].active=0 THEN LOOP; FOR i:Id←groups[g].chain,ids[i].chain UNTIL i=-1 DO friend,other:Signal; IF ~(ids[i].sig=s AND ids[i].active) THEN LOOP; use[s].used←use[s].total; ids[i].active←FALSE; [friend,other]←AnyMember[g]; RememberMe[1,s,friend,other]; DecrementActive[g]; RETURN; ENDLOOP; ENDLOOP; Error; END; ReduceDoubleUses:PROCEDURE[s:Signal] RETURNS[progress:BOOLEAN]=BEGIN friend,other:Signal; FOR g:Group IN [0..groupEnd) DO IF groups[g].active#2 THEN LOOP; FOR i:Id←groups[g].chain,ids[i].chain UNTIL i=-1 DO IF ~(ids[i].sig=s AND ids[i].active) THEN LOOP; use[s].used←use[s].total; ids[i].active←FALSE; [friend,other]←AnyMember[g]; RememberMe[2,s,friend,other]; groups[g].active←0; Substitute[friend,s]; RETURN[TRUE]; ENDLOOP; ENDLOOP; RETURN[FALSE]; END; ReduceParallelUses:PROCEDURE[s:Signal] RETURNS[progress:BOOLEAN]=BEGIN FOR g:Group IN [0..groupEnd) DO IF groups[g].active=0 THEN LOOP; FOR i:Id←groups[g].chain,ids[i].chain UNTIL i=-1 DO IF ~(ids[i].sig=s AND ids[i].active) THEN LOOP; FOR j:Id←groups[g].chain,ids[j].chain UNTIL j=-1 DO IF ~(ids[j].active AND i#j AND Verify[s,ids[j].sig]) THEN LOOP; RememberMe[3,s,ids[j].sig,-1]; Remove[s]; RETURN[TRUE]; ENDLOOP; ENDLOOP; ENDLOOP; RETURN[FALSE]; END; AnyMember:PROCEDURE[g:Group] RETURNS[a,b:Signal]=BEGIN a←b←-1; FOR i:Id←groups[g].chain,ids[i].chain UNTIL i=-1 DO IF ~ids[i].active THEN LOOP; IF a=-1 THEN a←ids[i].sig ELSE {b←ids[i].sig; RETURN}; ENDLOOP; IF a=-1 THEN Error; END; DecrementActive:PROCEDURE[g:Group]=BEGIN groups[g].active←groups[g].active-1; IF groups[g].active=1 THEN KillGroup[g]; END; KillGroup:PROCEDURE[g:Group]=BEGIN FOR j:Id←groups[g].chain,ids[j].chain UNTIL j=-1 DO IF ~ids[j].active THEN LOOP; ids[j].active←FALSE; use[ids[j].sig].used←use[ids[j].sig].used+1; groups[g].active←0; RETURN; ENDLOOP; Error; END; Substitute:PROCEDURE[new,old:Signal]=BEGIN FOR g:Group IN [0..groupEnd) DO IF groups[g].active=0 THEN LOOP; FOR i:Id←groups[g].chain,ids[i].chain UNTIL i=-1 DO IF ~(ids[i].sig=old AND ids[i].active) THEN LOOP; ids[i].sig←new; FOR j:Id←groups[g].chain,ids[j].chain UNTIL j=-1 DO IF j#i AND ids[j].sig=new AND ids[j].active THEN BEGIN ids[j].active←FALSE; use[new].used←use[new].used+1; DecrementActive[g]; END; ENDLOOP; ENDLOOP; ENDLOOP; END; debug:Signal←-1; Verify:PROCEDURE[s,t:Signal] RETURNS[BOOLEAN]=BEGIN sFound,tFound:BOOLEAN; IF s=debug THEN Error; FOR g:Group IN [0..groupEnd) DO IF groups[g].active=0 THEN LOOP; sFound←tFound←FALSE; FOR i:Id←groups[g].chain,ids[i].chain UNTIL i=-1 DO IF ~ids[i].active THEN LOOP; SELECT ids[i].sig FROM s=>sFound←TRUE; t=>tFound←TRUE; ENDCASE; ENDLOOP; IF sFound AND ~tFound THEN BEGIN IF s=debug THEN Error; RETURN[FALSE]; END; ENDLOOP; RETURN[TRUE]; END; Remove:PROCEDURE[s:Signal]=BEGIN FOR g:Group IN [0..groupEnd) DO IF groups[g].active=0 THEN LOOP; FOR i:Id←groups[g].chain,ids[i].chain UNTIL i=-1 DO IF ~(ids[i].active AND ids[i].sig=s) THEN LOOP; ids[i].active←FALSE; DecrementActive[g]; ENDLOOP; ENDLOOP; use[s].used←use[s].total; END; RememberMe:PROCEDURE[type:INTEGER, me,friend,other:Signal]=BEGIN IF ~(me IN [0..signalMax) AND friend IN [0..signalMax)) THEN Error; begin←friend; remember[nextRemember]←[type,me,friend,other]; nextRemember←nextRemember+1; END; last:Signal; Rebuild:PROCEDURE=BEGIN columnList↑←ALL[-1]; last←begin; FOR s:Remember DECREASING IN [0..nextRemember) DO me:Signal=remember[s].me; friend:Signal=remember[s].friend; IF remember[s].type=0 THEN LOOP; IF columnList[me]#-1 THEN Error; Mid[me,friend] ENDLOOP; END; Front:PROCEDURE[s:Signal]={columnList[s]←begin; begin←s}; Back:PROCEDURE[s:Signal]={columnList[last]←s; last←s}; Mid:PROCEDURE[s,t:Signal]=BEGIN q:Signal=columnList[t]; IF q=-1 THEN BEGIN IF t#last THEN columnList[last]←t; last←s; END; columnList[s]←q; columnList[t]←s; END; FixEnds:PROCEDURE=BEGIN FOR s:Signal←begin,columnList[s] UNTIL s=-1 DO last←s; ENDLOOP; FOR s:Signal IN [0..maxSignal) DO SELECT sig[s].fixed FROM hi=> FixEnd[s,TRUE];lo=> FixEnd[s,FALSE]; ENDCASE; ENDLOOP; END; FixEnd:PROCEDURE[f:Signal,hi:BOOLEAN]=BEGIN back:Signal←-1; FOR s:Signal←begin,columnList[s] UNTIL s=-1 DO IF f#s THEN {back←s; LOOP}; IF back=-1 THEN begin←columnList[s] ELSE {columnList[back]←columnList[s]; IF s=last THEN last←back}; columnList[s]←-1; IF hi THEN Back[f] ELSE Front[f]; RETURN; ENDLOOP; Error; END; begin:Signal←-1; NumberColumns:PROCEDURE=BEGIN c:INTEGER←0; column↑←ALL[0]; FOR s:Signal←begin,columnList[s] UNTIL s=-1 DO sig[s].columnNum←c; column[c]←s; c←c+1; ENDLOOP; PrintColumns[]; END; PrintColumns:PROCEDURE=BEGIN OPEN IODefs; IF chip THEN RETURN; FOR c:INTEGER IN [0..maxSignal) UNTIL column[c]=0 DO WriteChar[Ret]; WriteDecimal[c]; WriteChar[Space]; WriteString[Lookup2[column[c]]]; ENDLOOP; END; PrintGroups:PROCEDURE=BEGIN OPEN IODefs; k:INTEGER; IF chip THEN RETURN; FOR g:Group IN [0..groupEnd) DO IF groups[g].chain=-1 THEN LOOP; WriteChar[Ret]; WriteDecimal[g]; WriteChar[Space]; WriteDecimal[groups[g].active]; WriteChar[Space]; k←0; FOR i:Id←groups[g].chain,ids[i].chain UNTIL i=-1 OR (k←k+1)>30 DO WriteChar[Space]; WriteChar[IF ids[i].active THEN Space ELSE 'X]; WriteChar[Space]; --WriteDecimal[ids[i].sig]; WriteString[Lookup2[ids[i].sig]]; ENDLOOP; ENDLOOP; END; PrintUse:PROCEDURE=BEGIN OPEN IODefs; IF chip THEN RETURN; FOR s:Group IN [0..maxSignal) DO IF use[s].total=0 THEN LOOP; WriteChar[Ret]; WriteDecimal[s]; WriteChar[Space]; WriteString[Lookup2[s]]; WriteChar[Space]; WriteDecimal[use[s].total]; WriteChar[Space]; WriteDecimal[use[s].used]; ENDLOOP; END; PrintRemember:PROCEDURE=BEGIN OPEN IODefs; FOR s:Remember IN [0..nextRemember) DO WriteChar[Ret]; WriteDecimal[s]; WriteChar[Space]; WriteDecimal[remember[s].type]; WriteChar[Space]; WriteString[Lookup2[remember[s].me]]; WriteChar[Space]; WriteString[Lookup2[remember[s].friend]]; ENDLOOP; END; InitStorage:PROCEDURE=BEGIN groups←zone.NEW[groupsType]; ids←zone.NEW[idsType]; use←zone.NEW[useType]; remember←zone.NEW[rememberType]; columnList←zone.NEW[columnListType]; END; InitStorage; END.. Rebuild:PROCEDURE=BEGIN columnList←ALL[-1]; last←begin; FOR s:Remember DECREASING IN [0..nextRemember) DO me:Signal=remember[s].me; friend:Signal=remember[s].friend; other:Signal=remember[s].other; upSide:BOOLEAN←FALSE; IF remember[s].type=0 THEN LOOP; IF columnList[me]#-1 THEN Error; SELECT other FROM -2,-1 => {Back[me]; LOOP}; -3 => {Front[me]; LOOP}; -4 => upSide←FALSE; -5 => upSide←TRUE; ENDCASE=>FOR s:Signal←friend,columnList[s] UNTIL s=-1 DO IF s=other THEN {upSide←TRUE; EXIT}; ENDLOOP; IF upSide THEN IF last=friend THEN Back[me] ELSE Mid[me,friend] ELSE IF friend=begin THEN Front[me] ELSE FOR t:Signal←begin,columnList[t] UNTIL t=-1 DO IF columnList[t]=friend THEN {Mid[me,t]; EXIT}; ENDLOOP; ENDLOOP; END;