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.*;
22 * @author Adam Megacz <megacz@cs.berkeley.edu>
26 private static final BitVector SIGNAL_ZERO = new BitVector(1);
27 private static final BitVector SIGNAL_ONE = new BitVector(1);
29 SIGNAL_ONE.set(0,true);
32 /** WARNING: this class may change in the future; it is not a stable interface */
33 public Parser(Fleet fleet) {
34 expect = new ArrayList<Long>();
38 //////////////////////////////////////////////////////////////////////////////
41 private ArrayList<String> imports = new ArrayList<String>();
43 private HashMap<String,Ship> shipMap = new HashMap<String,Ship>();
45 // codebags in numerical order
46 private ArrayList<CodeBag> codeBags = new ArrayList<CodeBag>();
47 private HashMap<String,CodeBag> codeBagsByName = new HashMap<String,CodeBag>();
49 private CodeBag getCodeBag(String name) {
50 CodeBag cb = codeBagsByName.get(name);
51 if (cb!=null) return cb;
52 return new CodeBag(name);
55 private static Union grammar;
56 private static synchronized Union getGrammar() throws Exception {
57 if (grammar != null) return grammar;
58 InputStream grammarStream =
59 Parser.class.getClassLoader().getResourceAsStream("edu/berkeley/fleet/assembler/fleet.g");
60 CharParser metaGrammarParser = new CharParser(GrammarAST.getMetaGrammar());
61 Tree<String> parsedGrammar = metaGrammarParser.parse(new CharInput(grammarStream)).expand1();
62 grammar = GrammarAST.buildFromAST(parsedGrammar, "s", new GrammarAST.ImportResolver() {
63 public InputStream getImportStream(String importname) { return null; }
68 // FIXME: this ought to be cached via serialization, I think
69 private static CharParser cp = null;
70 Tree<String> parseIt(Reader r) throws Exception {
72 cp = new CharParser(getGrammar());
73 CharInput ci = new CharInput(r);
74 Forest f = cp.parse(ci);
78 public Instruction[] parse(Reader r) throws Exception {
79 // this needs to be "code bag zero"
80 CodeBag baseCodeBag = new CodeBag();
81 CodeBag rootCodeBag = new CodeBag();
83 Tree<String> parsed = (Tree<String>)parseIt(r);
84 walk(parsed, rootCodeBag);
86 // map from arbitrary identifiers to actual addresses
87 int[] codeBagMap = new int[codeBags.size()];
89 for(int i=0; i<codeBags.size(); i++) {
90 CodeBag c = codeBags.get(i);
91 codeBagMap[i] = count;
92 for(Instruction inst : c) {
99 ArrayList<Instruction> ret = new ArrayList<Instruction>();
100 for(int i=0; i<codeBags.size(); i++) {
101 CodeBag c = codeBags.get(i);
102 for(int j=0; j<c.size(); j++) {
103 Instruction inst = c.get(j);
104 if (c.isCBD.contains(j)) {
107 lit = ((FleetTwoFleet)fleet).CBD_SIZE.setval(lit, codeBags.get((int)old.immediate).size());
108 lit = ((FleetTwoFleet)fleet).CBD_OFFSET.setval(lit, codeBagMap[(int)old.immediate]);
109 inst = new Set(old.dock, false, IgnoreFlagD, SetDest.DataLatch, lit);
116 for(int i=0; i<codeBags.size(); i++) {
117 if (codeBags.get(i)==rootCodeBag) {
119 lit = ((FleetTwoFleet)fleet).CBD_SIZE.setval(lit, codeBags.get(i).size());
120 lit = ((FleetTwoFleet)fleet).CBD_OFFSET.setval(lit, codeBagMap[i]);
124 if (codeBags.size()<=2)
125 return (Instruction[])ret.toArray(new Instruction[0]);
126 return fixup((Instruction[])ret.toArray(new Instruction[0]), startcbd);
129 private Instruction[] fixup(Instruction[] instructions, long startcbd) {
130 ArrayList<Instruction> ret = new ArrayList<Instruction>();
133 Dock inAddrWrite = null;
134 Dock inDataWrite = null;
140 for(Ship ship : fpga) {
141 if ("Memory".equals(ship.getType()) && ship.getOrdinal()==0) {
142 inAddrWrite = ship.getDock("inAddrWrite");
143 inDataWrite = ship.getDock("inDataWrite");
144 inCBD = ship.getDock("inCBD");
145 out = ship.getDock("out");
147 //ihorn = ship.getDock("outIhorn");
149 if ("Debug".equals(ship.getType()) && ship.getOrdinal()==0) {
150 debugIn = ship.getDock("in");
154 for(int i=0; i<instructions.length; i++) {
155 long lit = ((FleetTwoFleet)fpga).writeInstruction(instructions[i], out);
156 ret.add(discard(out));
157 ret.add(new Instruction.Shift(inDataWrite, false, IgnoreFlagD, new BitVector(fpga.getShiftWidth()).set(getField(36, 19, lit))));
158 ret.add(new Instruction.Shift(inDataWrite, false, IgnoreFlagD, new BitVector(fpga.getShiftWidth()).set(getField(18, 0, lit))));
159 ret.add(deliver(inDataWrite));
160 ret.add(new Instruction.Shift(inAddrWrite, false, IgnoreFlagD, new BitVector(fpga.getShiftWidth()).set(getField(36, 19, i))));
161 ret.add(new Instruction.Shift(inAddrWrite, false, IgnoreFlagD, new BitVector(fpga.getShiftWidth()).set(getField(18, 0, i))));
162 ret.add(deliver(inAddrWrite));
164 ret.add(new Instruction.Shift(inCBD, false, IgnoreFlagD, new BitVector(fpga.getShiftWidth()).set(getField(36, 19, startcbd))));
165 ret.add(new Instruction.Shift(inCBD, false, IgnoreFlagD, new BitVector(fpga.getShiftWidth()).set(getField(18, 0, startcbd))));
166 ret.add(wait(inCBD));
167 ret.add(deliver(inCBD));
168 ret.add(sendto(out, out.getPath(inCBD.getDataDestination(),null)));
170 int count = (int)((FleetTwoFleet)fleet).CBD_SIZE.getval(startcbd);
171 // FIXME FIXME FIXME!
175 int num = Math.min(count, MAX_ILC);
178 ret.add(new Instruction.Set(ihorn, false, IgnoreFlagD, SetDest.InnerLoopCounter, num));
179 ret.add(new Instruction.Move(ihorn, false, IgnoreFlagD, false, null,false,true,true,true,true,false));
181 if (num_instrs > ihorn.getInstructionFifoSize()) throw new RuntimeException();
183 return (Instruction[])ret.toArray(new Instruction[0]);
186 /** in the first pass, codebags are assigned "addresses" in arbitrary order */
187 void walk(Tree<String> t, CodeBag cb) {
189 String head = t.head();
191 } else if (head.equals("Program")) {
192 for(Tree<String> tc : t.child(0))
195 for(Tree<String> statement : t.child(1))
196 fillCodeBag(statement, cb);
198 } else if (head.equals("#ship")) {
199 String name = name(t.child(0));
200 String type = string(t.child(1));
201 Ship ship = allocateShip(type);
202 shipMap.put(name, ship);
204 } else if (head.equals("#expect")) {
205 expect.add(number(t.child(0)));
206 } else if (head.equals("#skip")) {
212 private static String string(Tree<String> t) {
214 if (t.head() != null) ret += t.head();
215 for(Tree<String> c : t)
220 private static String stringBody(Tree<String> t) {
222 for(Tree<String> c : t)
227 private static String name(Tree<String> t) {
228 return string(t.child(0))+string(t.child(1));
231 Path path(Dock dock, Tree<String> t) {
232 if (!"Dock".equals(t.head()) && !"Destination".equals(t.head()) && !"ShipSpecificLiteral".equals(t.head())) return null;
233 String shipName = name(t.child(0));
234 String portName = name(t.child(1));
235 Ship ship = shipMap.get(shipName);
236 if (ship==null) throw new RuntimeException("no such ship \""+shipName+"\"");
237 Destination ret = null;
240 if (b.getName().equals(portName)) {
244 throw new RuntimeException("no such dock \""+portName+"\"");
246 if (":i".equals(t.child(2).head())) return dock.getPath(bb.getInstructionDestination(),SIGNAL_ZERO);
247 if (":1".equals(t.child(2).head())) return dock.getPath(bb.getDataDestination(),SIGNAL_ONE);
248 if (":0".equals(t.child(2).head())) return dock.getPath(bb.getDataDestination(),SIGNAL_ZERO);
250 return dock.getPath(bb.getDataDestination(),SIGNAL_ZERO);
253 Dock dock(Tree<String> t) {
254 if (!"Dock".equals(t.head()) && !"Destination".equals(t.head()) && !"ShipSpecificLiteral".equals(t.head()))
255 throw new RuntimeException(t+"");
256 String shipName = name(t.child(0));
257 String portName = name(t.child(1));
258 Ship ship = shipMap.get(shipName);
259 if (ship==null) throw new RuntimeException("no such ship \""+shipName+"\"");
262 if (b.getName().equals(portName))
264 throw new RuntimeException("no such dock \""+portName+"\"");
267 private HashMap<String,Integer> numAllocated = new HashMap<String,Integer>();
269 Ship allocateShip(String shipType) {
271 if (numAllocated.get(shipType) != null)
272 allocated = numAllocated.get(shipType);
273 numAllocated.put(shipType, allocated+1);
274 for(Iterator<Ship> it = fleet.iterator();
278 if (s.getType().equals(shipType)) {
279 if (allocated == 0) return s;
283 if (fleet instanceof FleetWithDynamicShips) {
284 FleetWithDynamicShips dyn = ((FleetWithDynamicShips)fleet);
285 Ship ship = dyn.createShip(shipType, shipType+allocated);
287 throw new RuntimeException("couldn't find a ship called \""+shipType+"\"");
290 throw new RuntimeException("no more ships of type \""+shipType+"\"");
294 private long parseSSL(Tree t) {
295 String shipType = name(t.child(0));
296 String portName = name(t.child(1));
297 Ship chosenship = null;
298 for(Ship ship : fleet) {
299 if (ship.getType().equals(shipType)) {
304 if (chosenship==null) throw new RuntimeException("no ships of type " + shipType);
305 Dock chosenport = chosenship.getDock(portName);
306 Tree specs = t.child(2);
308 for(int i=0; i<specs.size(); i++) {
309 Tree tt = specs.child(i);
310 literal |= resolveLiteral(chosenport, stringBody(tt));
315 private static long resolveLiteral(Dock dd, String s) {
318 boolean hasval = false;
319 if (s.indexOf('=') != -1) {
320 val = Long.parseLong(s.substring(s.indexOf('=')+1));
321 s = s.substring(0, s.indexOf('='));
324 ShipDescription.Constant c = ((FleetTwoDock)dd).getDockConstant(s);
325 if (c==null) throw new RuntimeException("no constant " + s + " on dock " + dd);
329 ret |= ((~(0xffffffffffffffffL << c.numberWidth)) & val) << c.numberOffset;
333 private static FlagFunction parseFlags(Tree<String> t) {
334 FlagFunction ret = FlagFunction.ZERO;
335 for(int i=0; i<t.size(); i++) {
336 String s = t.child(i).head();
337 if (s.equals("0")) ret = ret.add(FlagFunction.ZERO);
338 if (s.equals("1")) ret = ret.add(FlagFunction.ONE);
339 if (s.equals("a")) ret = ret.add(FlagA);
340 if (s.equals("!a")) ret = ret.add(NotFlagA);
341 if (s.equals("b")) ret = ret.add(FlagB);
342 if (s.equals("!b")) ret = ret.add(NotFlagB);
343 if (s.equals("c")) ret = ret.add(FlagC);
344 if (s.equals("!c")) ret = ret.add(NotFlagC);
349 private int anoncount = 1;
350 void fillCodeBag(Tree<String> t, CodeBag cb) {
351 if (t.head()==null) return;
352 else if (t.head().equals("CodeBagDef")) {
353 CodeBag cb2 = getCodeBag(name(t.child(0)));
354 for(Tree<String> statement : t.child(1))
355 fillCodeBag(statement, cb2);
357 } else if (t.head().equals("Fiber")) {
358 Dock dock = (Dock)dock(t.child(0));
360 OUTER: for(Tree tt : t.child(1)) {
362 if ("tail".equals(tt.head())) {
363 cb.add(new Tail(dock));
365 } else if ("head".equals(tt.head())) {
366 cb.add(new Head(dock));
371 Predicate predicate = Default;
372 boolean looping = false;
373 boolean interruptible = false;
374 for(int i=0; i<tt.child(0).size(); i++) {
375 Tree ttt = tt.child(0).child(i);
376 if ("[a]".equals(ttt.head())) predicate = FlagA;
377 if ("[b]".equals(ttt.head())) predicate = FlagB;
378 if ("[c]".equals(ttt.head())) predicate = FlagC;
379 if ("[!a]".equals(ttt.head())) predicate = NotFlagA;
380 if ("[!b]".equals(ttt.head())) predicate = NotFlagB;
381 if ("[!c]".equals(ttt.head())) predicate = NotFlagC;
382 if ("[*]".equals(ttt.head())) predicate = IgnoreFlagD;
383 if ("[d]".equals(ttt.head())) predicate = FlagD;
384 if ("[Rq]".equals(ttt.head())) looping = true;
387 if ("flags".equals(tt.head())) {
388 cb.add(new Set(dock, looping, predicate, parseFlags(tt.child(0)), parseFlags(tt.child(1))));
390 } else if ("olc=word".equals(tt.head())) {
391 cb.add(new Set(dock, looping, predicate, SetDest.OuterLoopCounter, SetSource.DataLatch));
393 } else if ("ilc=word".equals(tt.head())) {
394 cb.add(new Set(dock, looping, predicate, SetDest.InnerLoopCounter, SetSource.DataLatch));
396 } else if ("*".equals(tt.head())) {
397 cb.add(new Set(dock, looping, predicate, SetDest.InnerLoopCounter, SetSource.Infinity));
399 } else if ("olc=int".equals(tt.head())) {
400 cb.add(new Set(dock, looping, predicate, SetDest.OuterLoopCounter, (number(tt.child(0)))));
402 } else if ("ilc=int".equals(tt.head())) {
403 cb.add(new Set(dock, looping, predicate, SetDest.InnerLoopCounter, (number(tt.child(0)))));
405 } else if ("--".equals(tt.head())) {
406 cb.add(new Set(dock, looping, predicate, SetDest.OuterLoopCounter, SetSource.Decrement));
408 } else if ("nop".equals(tt.head())) {
409 if (tt.size() > 0 && "[T]".equals(tt.child(0).head())) interruptible = true;
410 cb.add(new Move(dock, looping, predicate, interruptible, null, false, false, false, false, false, false));
411 } else if ("shift".equals(tt.head())) {
412 cb.add(new Shift(dock, looping, predicate,
413 new BitVector(dock.getShip().getFleet().getShiftWidth()).set(number(tt.child(0)))));
415 } else if ("flush".equals(tt.head())) {
416 cb.add(new Flush(dock, looping, predicate));
418 } else if ("abort".equals(tt.head())) {
419 cb.add(new Abort(dock, predicate));
421 } else if ("word".equals(tt.head())) {
423 if (tt.child(0).head().equals("CodeBagBody")) {
424 Tree<String> tq = tt;
425 CodeBag cb2 = getCodeBag("anon"+(anoncount++));
426 for(Tree<String> statement : tq.child(0))
427 fillCodeBag(statement, cb2);
428 cb.add(new Set(dock, looping, predicate, SetDest.DataLatch, (cb2.getFakeAddress())), true);
430 } else if (tt.child(0).head().equals("Name")) {
431 String refname = name(tt.child(0));
432 CodeBag cb2 = getCodeBag(refname);
433 cb.add(new Set(dock, looping, predicate, SetDest.DataLatch, (cb2.getFakeAddress())), true);
435 } else if (tt.child(0).head().equals("[")) {
436 literal = parseSSL(tt.child(0));
438 literal = number(tt.child(0));
442 if ("int".equals(tt.child(1).head())) {
443 count = (int)number(tt.child(1));
444 } else if ("forever".equals(tt.child(1).head())) {
450 if (((FleetTwoFleet)fleet).isSmallEnoughToFit(literal)) {
451 cb.add(new Set(dock, looping, predicate, SetDest.DataLatch, (literal)));
454 while(counter < dock.getShip().getFleet().getWordWidth()) counter += fleet.getShiftWidth();
456 cb.add(new Shift(dock, looping, predicate,
457 new BitVector(dock.getShip().getFleet().getShiftWidth())
458 .set(getField(counter-1, counter-fleet.getShiftWidth(), literal))));
459 counter -= fleet.getShiftWidth();
466 boolean requeue = false;
467 if ("[T]".equals(tt.child(0).head())) interruptible = true;
468 ttx = tt.child(tt.size()-1);
469 boolean tokenIn = false;
470 boolean dataIn = false;
471 boolean latch = false;
472 boolean dataOut = false;
473 boolean tokenOut = false;
474 boolean dispatch = false;
475 boolean localLiteral = false;
476 boolean ignoreUntilLast = false;
479 for(int i=0; i<ttx.size(); i++) {
480 Tree ttt = ttx.child(i);
481 if ("recv token".equals(ttt.head())) { tokenIn = true; }
482 else if ("discard".equals(ttt.head())) { dataIn = true; latch = false; }
483 else if ("take".equals(ttt.head())) { dataIn = true; latch = true; }
484 else if ("collect".equals(ttt.head())) {
485 if (dock.isInputDock())
486 throw new RuntimeException("you can't use \"collect\" at input docks; try \"recv\" instead");
490 else if ("collect path".equals(ttt.head())) {
491 if (dock.isInputDock())
492 throw new RuntimeException("you can't use \"collect\" at input docks; try \"recv\" instead");
497 else if ("collect packet".equals(ttt.head())) {
498 if (dock.isInputDock())
499 throw new RuntimeException("you can't use \"collect\" at input docks; try \"recv\" instead");
504 else if ("collect nothing".equals(ttt.head())) {
505 if (dock.isInputDock())
506 throw new RuntimeException("you can't use \"collect\" at input docks; try \"recv\" instead");
509 else if ("recv".equals(ttt.head())) {
510 if (dock.isOutputDock())
511 throw new RuntimeException("you can't use \"recv\" at input docks; try \"collect\" instead");
515 else if ("recv path".equals(ttt.head())) {
516 if (dock.isOutputDock())
517 throw new RuntimeException("you can't use \"recv\" at input docks; try \"collect\" instead");
522 else if ("recv packet".equals(ttt.head())) {
523 if (dock.isOutputDock())
524 throw new RuntimeException("you can't use \"recv\" at input docks; try \"collect\" instead");
529 else if ("recv nothing".equals(ttt.head())) {
530 if (dock.isOutputDock())
531 throw new RuntimeException("you can't use \"recv\" at input docks; try \"collect\" instead");
534 else if ("send".equals(ttt.head())) {
537 else if ("send to".equals(ttt.head())) { dataOut = true; path = path(dock, ttt.child(0)); }
538 else if ("deliver".equals(ttt.head())) { dataOut = true; }
539 else if ("send token".equals(ttt.head())) { tokenOut = true; }
540 else if ("send token to".equals(ttt.head())) { tokenOut = true; path = path(dock, ttt.child(0)); }
542 cb.add(new Move(dock, looping, predicate,
543 interruptible, path, tokenIn, dataIn,
544 latch, dispatch, dataOut, tokenOut));
549 private class CodeBag extends ArrayList<Instruction> {
550 public long address = -1;
551 public final String name;
552 private HashSet<Integer> isCBD = new HashSet<Integer>();
553 public CodeBag() { codeBags.add(this); this.name = "root"; }
554 public CodeBag(String name) { codeBags.add(this); codeBagsByName.put(name, this); this.name = name; }
555 public long getFakeAddress() { return codeBags.indexOf(this); }
556 public boolean equals(Object o) { return this==o; }
557 public void add(Instruction i, boolean isCBD) {
558 if (isCBD) this.isCBD.add(size());
564 public static ArrayList<Long> expect;
565 public static boolean skip;
567 private static long number(Tree t) {
569 for(Object c : t.child(2)) ret += ((Tree)c).head();
570 boolean negative = "-".equals(t.child(0).head());
573 if ("0x".equals(t.child(1).head())) val = Long.parseLong(ret, 16);
574 else if ("0b".equals(t.child(1).head())) val = Long.parseLong(ret, 2);
575 else val = Long.parseLong(ret);
576 if (negative) val = -1L * val;
580 * This interface marks Fleets which can create ships on the fly, like the fleeterpreter;
581 * if available, the parser will use this interface to create ships out of #ship definitions.
583 public static interface FleetWithDynamicShips {
584 public Ship createShip(String shiptype, String shipname);
587 private static Move discard(Dock dock) { return new Move(dock, false, IgnoreFlagD, false, null, false, true, false, false, false, false); }
588 private static Move deliver(Dock dock) { return new Move(dock, false, IgnoreFlagD, false, null, false, false, false, false, true, false); }
589 private static Move wait(Dock dock) { return new Move(dock, false, IgnoreFlagD, false, null, true, false, false, false, false, false); }
590 private static Move sendto(Dock dock, Path path) { return new Move(dock, false, IgnoreFlagD, false, path, false, false, false, false, true, false); }