9f374be1bd425164d4c4241ca9309e6575258f8b
[fleet.git] / src / edu / berkeley / fleet / assembler / Parser.java
1 package edu.berkeley.fleet.assembler;
2 import edu.berkeley.fleet.api.*;
3 import edu.berkeley.sbp.*;
4 import edu.berkeley.sbp.chr.*;
5 import edu.berkeley.sbp.misc.*;
6 import edu.berkeley.sbp.meta.*;
7 import edu.berkeley.sbp.util.*;
8 import static edu.berkeley.fleet.util.BitManipulations.*;
9 import edu.berkeley.fleet.two.*;
10 import edu.berkeley.fleet.api.Instruction.Set;
11 import static edu.berkeley.fleet.api.Instruction.*;
12 import static edu.berkeley.fleet.api.Instruction.Set.*;
13 import static edu.berkeley.fleet.api.Predicate.*;
14 import edu.berkeley.fleet.two.*;
15 import edu.berkeley.fleet.fpga.*;
16 import edu.berkeley.fleet.interpreter.*;
17 import java.util.*;
18 import java.io.*;
19
20
21 /**
22  *  @author Adam Megacz <megacz@cs.berkeley.edu>
23  */
24 public class Parser {
25
26     private static final BitVector SIGNAL_ZERO = new BitVector(1);
27     private static final BitVector SIGNAL_ONE  = new BitVector(1);
28     static {
29         SIGNAL_ONE.set(0,true);
30     }
31     
32     Parser(Fleet fleet) {
33         expect = new ArrayList<Long>();
34         this.fleet = fleet;
35     }
36
37     //////////////////////////////////////////////////////////////////////////////
38
39     private Fleet fleet;
40     private ArrayList<String> imports = new ArrayList<String>();
41
42     private HashMap<String,Ship> shipMap = new HashMap<String,Ship>();
43
44     // codebags in numerical order
45     private ArrayList<CodeBag> codeBags = new ArrayList<CodeBag>();
46     private HashMap<String,CodeBag> codeBagsByName = new HashMap<String,CodeBag>();
47     
48     private CodeBag getCodeBag(String name) {
49         CodeBag cb = codeBagsByName.get(name);
50         if (cb!=null) return cb;
51         return new CodeBag(name);
52     }
53
54     private static Union grammar;
55     private static synchronized Union getGrammar() throws Exception {
56         if (grammar != null) return grammar;
57         InputStream grammarStream =
58             Parser.class.getClassLoader().getResourceAsStream("edu/berkeley/fleet/assembler/fleet.g");
59         CharParser metaGrammarParser   = new CharParser(GrammarAST.getMetaGrammar());
60         Tree<String> parsedGrammar     = metaGrammarParser.parse(new CharInput(grammarStream)).expand1();
61         grammar                        = GrammarAST.buildFromAST(parsedGrammar, "s", new GrammarAST.ImportResolver() {
62                 public InputStream getImportStream(String importname) { return null; }
63             });
64         return grammar;
65     }
66
67     // FIXME: this ought to be cached via serialization, I think
68     private static CharParser cp = null;
69     Tree<String> parseIt(Reader r) throws Exception {
70         if (cp==null)
71             cp = new CharParser(getGrammar());
72         CharInput ci = new CharInput(r);
73         Forest f = cp.parse(ci);
74         return f.expand1();
75     }
76
77     public Instruction[] parse(Reader r) throws Exception {
78         // this needs to be "code bag zero"
79         CodeBag baseCodeBag = new CodeBag();
80         CodeBag rootCodeBag = new CodeBag();
81         skip = false;
82         Tree<String> parsed = (Tree<String>)parseIt(r);
83         walk(parsed, rootCodeBag);
84
85         // map from arbitrary identifiers to actual addresses
86         int[] codeBagMap = new int[codeBags.size()];
87         int count = 0;
88         for(int i=0; i<codeBags.size(); i++) {
89             CodeBag c = codeBags.get(i);
90             codeBagMap[i] = count;
91             for(Instruction inst : c) {
92                 count++;
93             }
94         }
95
96         // now write for real
97         count = 0;
98         ArrayList<Instruction> ret = new ArrayList<Instruction>();
99         for(int i=0; i<codeBags.size(); i++) {
100             CodeBag c = codeBags.get(i);
101             for(int j=0; j<c.size(); j++) {
102                 Instruction inst = c.get(j);
103                 if (c.isCBD.contains(j)) {
104                     Set old = (Set)inst;
105                     long lit = 0;
106                     lit = FleetTwoFleet.CBD_SIZE.setval(lit, codeBags.get((int)old.immediate).size());
107                     lit = FleetTwoFleet.CBD_OFFSET.setval(lit, codeBagMap[(int)old.immediate]);
108                     inst = new Set(old.dock, false, IgnoreOLC, SetDest.DataLatch, lit);
109                 }
110                 ret.add(inst);
111                 count++;
112             }
113         }
114         long startcbd = 0;
115         for(int i=0; i<codeBags.size(); i++) {
116             if (codeBags.get(i)==rootCodeBag) {
117                 long lit = 0;
118                 lit = FleetTwoFleet.CBD_SIZE.setval(lit, codeBags.get(i).size());
119                 lit = FleetTwoFleet.CBD_OFFSET.setval(lit, codeBagMap[i]);
120                 startcbd = lit;
121             }
122         }
123         if (codeBags.size()<=2)
124             return (Instruction[])ret.toArray(new Instruction[0]);
125         return fixup((Instruction[])ret.toArray(new Instruction[0]), startcbd);
126     }
127
128     private Instruction[] fixup(Instruction[] instructions, long startcbd) {
129         ArrayList<Instruction> ret = new ArrayList<Instruction>();
130         Fleet fpga = fleet;
131
132         Dock inAddrWrite = null;
133         Dock inDataWrite = null;
134         Dock inCBD       = null;
135         Dock out         = null;
136         Dock debugIn     = null;
137         Dock ihorn       = null;
138
139         for(Ship ship : fpga) {
140             if ("Memory".equals(ship.getType()) && ship.getOrdinal()==0) {
141                 inAddrWrite = ship.getDock("inAddrWrite");
142                 inDataWrite = ship.getDock("inDataWrite");
143                 inCBD = ship.getDock("inCBD");
144                 out = ship.getDock("out");
145                 ihorn = ship.getDock("outIhorn");
146             }
147             if ("Debug".equals(ship.getType()) && ship.getOrdinal()==0) {
148                 debugIn = ship.getDock("in");
149             }
150         }
151
152         for(int i=0; i<instructions.length; i++) {
153             long lit = ((Fpga)fpga).writeInstruction(instructions[i], out);
154             ret.add(discard(out));
155             ret.add(new Instruction.Shift(inDataWrite, false, IgnoreOLC, new BitVector(fpga.getWordWidth()).set(getField(36, 19, lit))));
156             ret.add(new Instruction.Shift(inDataWrite, false, IgnoreOLC, new BitVector(fpga.getWordWidth()).set(getField(18,  0, lit))));
157             ret.add(deliver(inDataWrite));
158             ret.add(new Instruction.Shift(inAddrWrite, false, IgnoreOLC, new BitVector(fpga.getWordWidth()).set(getField(36, 19, i))));
159             ret.add(new Instruction.Shift(inAddrWrite, false, IgnoreOLC, new BitVector(fpga.getWordWidth()).set(getField(18,  0, i))));
160             ret.add(deliver(inAddrWrite));
161         }
162         ret.add(new Instruction.Shift(inCBD, false, IgnoreOLC, new BitVector(fpga.getWordWidth()).set(getField(36, 19, startcbd))));
163         ret.add(new Instruction.Shift(inCBD, false, IgnoreOLC, new BitVector(fpga.getWordWidth()).set(getField(18,  0, startcbd))));
164         ret.add(wait(inCBD));
165         ret.add(deliver(inCBD));
166         ret.add(sendto(out, out.getPath(inCBD.getDataDestination(),null)));
167         ret.add(new Instruction.Set(ihorn, false, IgnoreOLC, SetDest.InnerLoopCounter, SetSource.Infinity));
168         ret.add(new Instruction.Move(ihorn, false, IgnoreOLC, false, null,false,true,true,true,true,false));
169         return (Instruction[])ret.toArray(new Instruction[0]);
170     }
171
172     /** in the first pass, codebags are assigned "addresses" in arbitrary order */
173     void walk(Tree<String> t, CodeBag cb) {
174
175         String head = t.head();
176         if (head==null) {
177         } else if (head.equals("Program")) {
178             for(Tree<String> tc : t.child(0))
179                 walk(tc, cb);
180             if (t.size()>1)
181                 for(Tree<String> statement : t.child(1))
182                     fillCodeBag(statement, cb);
183    
184         } else if (head.equals("#import")) {
185             // ignored
186
187         } else if (head.equals("#ship")) {
188             String name = name(t.child(0));
189             String type = string(t.child(1));
190             Ship ship = null;
191
192             if (fleet instanceof FleetWithDynamicShips) {
193                 FleetWithDynamicShips dyn = ((FleetWithDynamicShips)fleet);
194                 ship = dyn.createShip(type, name);
195                 if (ship==null)
196                     throw new RuntimeException("couldn't find a ship called \""+type+"\"");
197             } else {
198                 ship = allocateShip(type);
199             }
200             shipMap.put(name, ship);
201
202         } else if (head.equals("#include")) {
203             try {
204                 walk(parseIt(new InputStreamReader(new FileInputStream(string(t.child(0))))), cb);
205             } catch (Exception e) {
206                 throw new RuntimeException(e);
207             }
208             
209         } else if (head.equals("#expect")) {
210             expect.add(number(t.child(0)));
211         } else if (head.equals("#skip")) {
212             skip = true;
213
214         }
215     }
216
217     String string(Tree<String> t) {
218         String ret = "";
219         if (t.head() != null) ret += t.head();
220         for(Tree<String> c : t)
221             ret += string(c);
222         return ret;
223     }
224
225     String stringBody(Tree<String> t) {
226         String ret = "";
227         for(Tree<String> c : t)
228             ret += string(c);
229         return ret;
230     }
231
232     String name(Tree<String> t) {
233         return string(t.child(0))+string(t.child(1));
234     }
235
236     Path path(Dock dock, Tree<String> t) {
237         if (!"Dock".equals(t.head()) && !"Destination".equals(t.head()) && !"ShipSpecificLiteral".equals(t.head())) return null;
238         t = t.child(0);
239         String shipName = name(t.child(0));
240         String portName = name(t.child(1));
241         String subPort = t.size()<3 ? null : name(t.child(2));
242         Ship ship = shipMap.get(shipName);
243         if (ship==null) throw new RuntimeException("no such ship \""+shipName+"\"");
244         Destination ret = null;
245         Dock bb = null;
246         for(Dock b : ship)
247             if (b.getName().equals(portName)) {
248                 bb = b;
249             }
250         if (bb==null)
251             throw new RuntimeException("no such pump \""+portName+"\"");
252         if (subPort==null) subPort="";
253         if (":i".equals(t.head())) return dock.getPath(bb.getInstructionDestination(),SIGNAL_ZERO);
254         if (":1".equals(t.head())) return dock.getPath(bb.getDataDestination(),SIGNAL_ONE);
255         if (":0".equals(t.head())) return dock.getPath(bb.getDataDestination(),SIGNAL_ZERO);
256         return dock.getPath(bb.getDataDestination(),SIGNAL_ZERO);
257     }
258
259     Dock dock(Tree<String> t) {
260         if (!"Dock".equals(t.head()) && !"Destination".equals(t.head()) && !"ShipSpecificLiteral".equals(t.head()))
261             throw new RuntimeException(t+"");
262         String shipName = name(t.child(0));
263         String portName = name(t.child(1));
264         Ship ship = shipMap.get(shipName);
265         if (ship==null) throw new RuntimeException("no such ship \""+shipName+"\"");
266         Dock bb = null;
267         for(Dock b : ship)
268             if (b.getName().equals(portName))
269                 return b;
270         throw new RuntimeException("no such pump \""+portName+"\"");
271     }
272
273     private HashMap<String,Integer> numAllocated = new HashMap<String,Integer>();
274
275     Ship allocateShip(String shipType) {
276         int allocated = 0;
277         if (numAllocated.get(shipType) != null)
278             allocated = numAllocated.get(shipType);
279         numAllocated.put(shipType, allocated+1);
280         for(Iterator<Ship> it = fleet.iterator();
281             it.hasNext();
282             ) {
283             Ship s = it.next();
284             if (s.getType().equals(shipType)) {
285                 if (allocated == 0) return s;
286                 allocated--;
287             }
288         }
289         throw new RuntimeException("no more ships of type \""+shipType+"\"");
290     }
291
292     private long parseSSL(Tree t) {
293         String shipType = name(t.child(0));
294         String portName = name(t.child(1));
295         Ship chosenship = null;
296         for(Ship ship : fleet) {
297             if (ship.getType().equals(shipType)) {
298                 chosenship = ship;
299                 break;
300             }
301         }
302         if (chosenship==null) throw new RuntimeException("no ships of type " + shipType);
303         Dock chosenport = chosenship.getDock(portName);
304         Tree specs = t.child(2);
305         long literal = 0;
306         for(int i=0; i<specs.size(); i++) {
307             Tree tt = specs.child(i);
308             literal |= resolveLiteral(chosenport, stringBody(tt));
309         }
310         return literal;
311     }
312
313     private static long resolveLiteral(Dock dd, String s) {
314         long val = 0;
315         long ret = 0;
316         boolean hasval = false;
317         if (s.indexOf('=') != -1) {
318             val = Long.parseLong(s.substring(s.indexOf('=')+1));
319             s = s.substring(0, s.indexOf('='));
320             hasval = true;
321         }
322         ShipDescription.Constant c = ((FleetTwoDock)dd).getConstant(s);
323         if (c==null) throw new RuntimeException("no constant " + s + " on dock " + dd);
324         ret |= c.setbits;
325         ret &= ~c.clearbits;
326         if (hasval)
327             ret |= ((~(0xffffffffffffffffL << c.numberWidth)) & val) << c.numberOffset;
328         return ret;
329     }
330
331     private static FlagFunction parseFlags(Tree<String> t) {
332         FlagFunction ret = FlagFunction.ZERO;
333         for(int i=0; i<t.size(); i++) {
334             String s = t.child(i).head();
335             if (s.equals("0"))  ret = ret.add(FlagFunction.ZERO);
336             if (s.equals("1"))  ret = ret.add(FlagFunction.ONE);
337             if (s.equals("a"))  ret = ret.add(FlagA);
338             if (s.equals("!a")) ret = ret.add(NotFlagA);
339             if (s.equals("b"))  ret = ret.add(FlagB);
340             if (s.equals("!b")) ret = ret.add(NotFlagB);
341             if (s.equals("c"))  ret = ret.add(FlagC);
342             if (s.equals("!c")) ret = ret.add(NotFlagC);
343         }
344         return ret;
345     }
346
347     private int anoncount = 1;
348     void fillCodeBag(Tree<String> t, CodeBag cb) {
349         if (t.head()==null) return;
350         else if (t.head().equals("CodeBagDef")) {
351             CodeBag cb2 = getCodeBag(name(t.child(0)));
352             for(Tree<String> statement : t.child(1))
353                 fillCodeBag(statement, cb2);
354
355         } else if (t.head().equals("Fiber")) {
356             Dock dock = (Dock)dock(t.child(0));
357             
358             OUTER: for(Tree tt : t.child(1)) {
359                 int count = 1;
360                 Predicate predicate = Default;
361                 boolean looping = false;
362                 boolean interruptible = false;
363                 for(int i=0; i<tt.child(0).size(); i++) {
364                     Tree ttt = tt.child(0).child(i);
365                     if ("[a]".equals(ttt.head()))  predicate = FlagA;
366                     if ("[b]".equals(ttt.head()))  predicate = FlagB;
367                     if ("[c]".equals(ttt.head()))  predicate = FlagC;
368                     if ("[!a]".equals(ttt.head())) predicate = NotFlagA;
369                     if ("[!b]".equals(ttt.head())) predicate = NotFlagB;
370                     if ("[!c]".equals(ttt.head())) predicate = NotFlagC;
371                     if ("[+]".equals(ttt.head()))  predicate = IgnoreOLC;
372                     if ("[I]".equals(ttt.head()))  interruptible = true;
373                     if ("[L]".equals(ttt.head()))  looping = true;
374                 }
375                 tt = tt.child(1);
376                 if ("tail".equals(tt.head()))    {
377                     cb.add(new Tail(dock));
378                     continue;
379                 } else if ("setflags".equals(tt.head()))    {
380                     cb.add(new Set(dock, looping, predicate, parseFlags(tt.child(0)), parseFlags(tt.child(1))));
381                     continue;
382                 } else if ("tapl".equals(tt.head()))    {
383                     cb.add(new Set(dock, looping, predicate, SetDest.TAPL, path(dock, tt.child(0))));
384                     continue;
385                 } else if ("load".equals(tt.head()) && "loop".equals(tt.child(0).head()))    {
386                     cb.add(new Set(dock, looping, predicate, SetDest.OuterLoopCounter, SetSource.DataLatch));
387                     continue;
388                 } else if ("load".equals(tt.head()) && "repeat".equals(tt.child(0).head()))    {
389                     cb.add(new Set(dock, looping, predicate, SetDest.InnerLoopCounter, SetSource.DataLatch));
390                     continue;
391                 } else if ("*".equals(tt.head()))    {
392                     cb.add(new Set(dock, looping, predicate, SetDest.InnerLoopCounter, SetSource.Infinity));
393                     continue;
394                 } else if ("with".equals(tt.head()) && "loop".equals(tt.child(0).head()))    {
395                     cb.add(new Set(dock, looping, predicate, SetDest.OuterLoopCounter, (number(tt.child(1)))));
396                     continue;
397                 } else if ("with".equals(tt.head()) && "repeat".equals(tt.child(0).head()))    {
398                     cb.add(new Set(dock, looping, predicate, SetDest.InnerLoopCounter, (number(tt.child(1)))));
399                     continue;
400                 } else if ("decrement".equals(tt.head())) {
401                     cb.add(new Set(dock, looping, predicate, SetDest.OuterLoopCounter, SetSource.Decrement));
402                     continue;
403                 } else if ("literal".equals(tt.head())) {
404                     long literal = 0;
405                     if (tt.child(0).head().equals("CodeBagBody")) {
406                         Tree<String> tq = tt;
407                         CodeBag cb2 = getCodeBag("anon"+(anoncount++));
408                         for(Tree<String> statement : tq.child(0))
409                             fillCodeBag(statement, cb2);
410                         cb.add(new Set(dock, looping, predicate, SetDest.DataLatch, (cb2.getFakeAddress())), true);
411                         continue OUTER;
412                     } else if (tt.child(0).head().equals("Name")) {
413                         String refname = name(tt.child(0));
414                         CodeBag cb2 = getCodeBag(refname);
415                         cb.add(new Set(dock, looping, predicate, SetDest.DataLatch, (cb2.getFakeAddress())), true);
416                         continue OUTER;
417                     } else if (tt.child(0).head().equals("[")) {
418                         literal = parseSSL(tt.child(0));
419                     } else {
420                         literal = number(tt.child(0));
421                     }
422                     count = 1;
423                     if ("int".equals(tt.child(1).head())) {
424                         count = (int)number(tt.child(1));
425                     } else if ("forever".equals(tt.child(1).head())) {
426                         count = 0;
427                     }
428
429
430                     if (FleetTwoFleet.isSmallEnoughToFit(literal)) {
431                         cb.add(new Set(dock, looping, predicate, SetDest.DataLatch, (literal)));
432                     } else {
433                         // FIXME bitwidth hardwired!
434                         cb.add(new Shift(dock, looping, predicate, new BitVector(37).set(getField(36, 19, literal))));
435                         cb.add(new Shift(dock, looping, predicate, new BitVector(37).set(getField(18,  0, literal))));
436                     }
437                         
438                     continue;
439                 }
440                 Tree ttx = null;
441                 boolean requeue = false;
442                 ttx = tt.child(1).head().equals("Commands") ? tt.child(1) : tt;
443                 if ("int".equals(tt.child(2).head())) {
444                     count = (int)number(tt.child(2));
445                     requeue = true;
446                 } else if ("forever".equals(tt.child(2).head())) {
447                     count = 0;
448                     requeue = true;
449                 }
450                 tt = tt.child(0);
451                 if (tt.head().equals("[*]")) {
452                     cb.add(new Set(dock, looping, predicate, SetDest.InnerLoopCounter, SetSource.Infinity));
453                     //count = 0;
454                     requeue = false;
455                 } else if (tt.head().equals("int")) {
456                     count = (int)number(tt);
457                     requeue = false;
458                 }
459                 boolean tokenIn = false;
460                 boolean dataIn = false;
461                 boolean latch = false;
462                 boolean dataOut = false;
463                 boolean tokenOut = false;
464                 boolean dispatch = false;
465                 boolean localLiteral = false;
466                 boolean ignoreUntilLast = false;
467                 long literal = 0;
468                 Path path = null;
469                 for(int i=0; i<ttx.size(); i++) {
470                     Tree ttt = ttx.child(i);
471                     if      ("wait".equals(ttt.head()))    { tokenIn = true; }
472                     else if ("nop".equals(ttt.head()))     { }
473                     else if ("discard".equals(ttt.head())) { dataIn = true; latch = false; }
474                     else if ("take".equals(ttt.head()))    { dataIn = true; latch = true; }
475                     else if ("recv".equals(ttt.head()))    { dataIn = true; latch = true; }
476                     else if ("collect".equals(ttt.head()))    { dataIn = true; latch = true; }
477                     else if ("recieve".equals(ttt.head()))    { dataIn = true; latch = true; }
478                     else if ("send".equals(ttt.head()))  { dispatch = true; dataOut = true; }
479                     else if ("sendto".equals(ttt.head()))  { dataOut = true; path = path(dock, ttt.child(0)); }
480                     else if ("deliver".equals(ttt.head())) { dataOut = true;  }
481                     else if ("notify".equals(ttt.head()))     { tokenOut = true; path = path(dock, ttt.child(0)); }
482                     else if ("notifyLast".equals(ttt.head()))     { tokenOut = true; ignoreUntilLast = true; path = path(dock, ttt.child(0)); }
483                 }
484                 cb.add(new Move(dock, looping, predicate,
485                                             interruptible, path, tokenIn, dataIn,
486                                             latch, dispatch, dataOut, tokenOut));
487             }
488         }
489     }
490
491     private class CodeBag extends ArrayList<Instruction> {
492         public long address = -1;
493         public final String name;
494         private HashSet<Integer> isCBD = new HashSet<Integer>();
495         public CodeBag() { codeBags.add(this); this.name = "root"; }
496         public CodeBag(String name) { codeBags.add(this); codeBagsByName.put(name, this); this.name = name; }
497         public long getFakeAddress() { return codeBags.indexOf(this); }
498         public boolean equals(Object o) { return this==o; }
499         public void add(Instruction i, boolean isCBD) {
500             if (isCBD) this.isCBD.add(size());
501             add(i);
502         }
503     }
504
505     // hideous hack
506     public static ArrayList<Long> expect;
507     public static boolean         skip;
508
509     private static long number(Tree t) {
510         String ret = "";
511         for(Object c : t.child(2)) ret += ((Tree)c).head();
512         boolean negative = "-".equals(t.child(0).head());
513         ret = ret.trim();
514         long val = 0;
515         if      ("0x".equals(t.child(1).head())) val = Long.parseLong(ret, 16);
516         else if ("0b".equals(t.child(1).head())) val = Long.parseLong(ret, 2);
517         else                                     val = Long.parseLong(ret);
518         if (negative) val = -1L * val;
519         return val;
520     }
521     /**
522      *  This interface marks Fleets which can create ships on the fly, like the fleeterpreter;
523      *  if available, the parser will use this interface to create ships out of #ship definitions.
524      */
525     public static interface FleetWithDynamicShips {
526         public Ship createShip(String shiptype, String shipname);
527     }
528
529     private static Move discard(Dock dock)           { return new Move(dock, false, IgnoreOLC, false, null, false, true,  false, false, false, false); }
530     private static Move deliver(Dock dock)           { return new Move(dock, false, IgnoreOLC, false, null, false, false, false, false, true,  false); }
531     private static Move wait(Dock dock)              { return new Move(dock, false, IgnoreOLC, false, null, true,  false, false, false, false, false); }
532     private static Move sendto(Dock dock, Path path) { return new Move(dock, false, IgnoreOLC, false, path, false, false, false, false, true,  false); }
533 }