1 package edu.berkeley.fleet.marina;
2 /* -*- tab-width: 4 -*- */
3 import com.sun.electric.tool.simulation.test.*;
5 import edu.berkeley.fleet.api.Instruction;
6 import edu.berkeley.fleet.marina.MarinaPath;
8 /** The Marina object will eventually represent the Marina test chip.
9 * Right now, it doesn't do much of anything. It just helps me exercise
10 * my test infrastructure. */
13 public static final int INDEX_OF_ADDRESS_BIT_COPIED_TO_C_FLAG_WHEN_DC_EQUALS_ONE = 5;
14 public static final int INDEX_OF_ADDRESS_BIT_COPIED_TO_C_FLAG_WHEN_DC_EQUALS_ZERO = MarinaPath.SIGNAL_BIT_INDEX;
17 public static int TOKEN_FIFO_CAPACITY = 3;
19 //public static final boolean kesselsCounter = true;
20 public static final boolean kesselsCounter = false;
21 public static final boolean omegaCounter = false;
23 public static final String DATA_CHAIN = kesselsCounter ? "marina.marina_data" : "marina.ivan_data";
24 public static final String CONTROL_CHAIN = kesselsCounter ? "marina.marina_control" : "marina.ivan_control";
25 public static final String REPORT_CHAIN = kesselsCounter ? "marina.marina_report" : "marina.ivan_report";
26 public static final String DUKE_CHAIN = "marina.duke";
28 public static String prefix = "marinaGu@0.outDockW@"+(kesselsCounter?"3":"0")+".marinaOu@"+(kesselsCounter?"1":"0")+".";
29 public static String MASTER_CLEAR = "mc";
33 private static String prefix = "outDockW@"+(kesselsCounter?"3":"0")+".marinaOu@1.";
34 private static String MASTER_CLEAR = "EXTmasterClear";
37 private static final String OLC_PATH_EVEN =
38 prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.olcWcont@0.scanEx3h@1"; // bits 2,4,6
39 private static final String OLC_PATH_ODD =
40 prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.olcWcont@0.scanEx3h@2"; // bits 1,3,5
41 public static final String OLC_PATH_KESSEL =
42 prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.counte@0.adamScan@1.scanEx6h@";
43 private static final String ILC_PATH_ODD =
44 prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.ilcMoveO@0.scanEx4h@0"; // bits 1,3,5,7
45 private static final String ILC_PATH_EVEN =
46 prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.ilcMoveO@0.scanEx4h@1"; // bits 2,4,6,8
47 private static final String FLAGS_PATH =
48 prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flags@0.scanEx3h@0";
50 private static final String INSTR_RING_CONTROL_PATH =
51 prefix+"southFif@1.tapPropS@1.tapStage@2";
52 private static final String TOK_FIFO_PATH =
54 private static final String INSTRUCTION_COUNTER_PATH =
55 prefix+"southFif@1.tapPropS@1.instruct@0";
56 private static final String DATA_COUNTER_PATH =
57 prefix+"northFif@1.fillDrai@1.instruct@0";
58 private static final String TOK_PRED_PATH =
59 prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.ilcMoveO@0.scanEx2h@0.scanCell@10";
61 private static final int COUNTER_LENGTH = 34;
62 private static final int INSTRUCTION_SEND_NDX = 1;
63 private static final int INSTRUCTION_RECIRCULATE_NDX = 0;
65 public static final int INSTRUCTION_LENGTH = 36;
67 private static final int A_FLAG_NDX = 0;
68 private static final int B_FLAG_NDX = 1;
70 public static final int SOUTH_RING_CAPACITY = 11;
72 // ILC appears in scan chain as "count[1:6], zLo, i, dLo"
74 // value is bit reversed and complemented
77 shiftReport(true, false);
78 BitVector odd = reportChain.getOutBits(REPORT_CHAIN+"."+ILC_PATH_ODD).bitReverse().not();
79 BitVector even = reportChain.getOutBits(REPORT_CHAIN+"."+ILC_PATH_EVEN).bitReverse().not();
80 BitVector ret = new BitVector(8, "olc");
81 for(int i=0; i<4; i++) {
82 ret.set(i*2+1, odd.get(i));
83 ret.set(i*2, even.get(i));
85 value = (int)ret.toLong();
87 /** Get the inner loop counter done bit. */
88 public boolean getDone() {
89 return (value & 0x40) != 0;
91 /** Get the inner loop counter infinity bit */
92 public boolean getInfinity() {
93 return (value & 0x80) != 0;
95 /** Get the 6 bits of count of the inner loop counter */
96 public int getCount() {
99 public String toString() {
100 return "[ilc, count="+getCount()+", infinity="+getInfinity()+", done="+getDone()+"]";
104 private final Indenter indenter;
106 // The name of the scan chain
107 // The instance path, from the top cell of the netlist, of the instance of infinityWithCover
108 public final ChainControl controlChain;
109 public final ChainControl dataChain;
110 public final ChainControl dukeChain;
111 public final ChainControl reportChain;
113 private final ChipModel model;
114 public final ProperStopper data;
115 public final InstructionStopper instrIn;
117 private void prln(String msg) {indenter.prln(msg);}
118 private void pr(String msg) {indenter.pr(msg);}
120 /** Shift the report scan chain */
121 public void shiftReport(boolean readEnable, boolean writeEnable) {
122 reportChain.shift(REPORT_CHAIN, readEnable, writeEnable);
125 /** Shift the report scan chain */
126 private void shiftControl(boolean readEnable, boolean writeEnable) {
127 controlChain.shift(CONTROL_CHAIN, readEnable, writeEnable);
130 /** Shift the data scan chain */
131 private void shiftData(boolean readEnable, boolean writeEnable) {
132 dataChain.shift(DATA_CHAIN, readEnable, writeEnable);
135 /** Shift the data scan chain */
136 public void shiftDuke(boolean readEnable, boolean writeEnable) {
137 dukeChain.shift(DUKE_CHAIN, readEnable, writeEnable);
140 public Marina(ChainControl controlChain,
141 ChainControl dataChain,
142 ChainControl dukeChain,
143 ChainControl reportChain,
144 ChipModel model, boolean clockHack, Indenter indenter) {
145 this.controlChain = controlChain;
146 this.dataChain = dataChain;
147 this.dukeChain = dukeChain;
148 this.reportChain = reportChain;
150 this.indenter = indenter;
151 data = new ProperStopper("north fifo",
152 prefix+"northFif@1.fillDrai@1.properSt@1",
156 model, clockHack, indenter,
157 prefix+"northFif@1.fillDrai@1.instruct@0.cntScnTh@1.cntScnOn@1");
158 instrIn = new InstructionStopper("south fifo",
159 prefix+"southFif@1.tapPropS@1.properSt@1",
163 model, clockHack, indenter,
164 prefix+"southFif@1.tapPropS@1.instruct@0.cntScnTh@1.cntScnOn@1");
170 public void stopAndResetCounters() {
171 instrIn.setCounterEnable(false);
172 data.setCounterEnable(false);
173 dataChain.shift(DATA_CHAIN, true, false);
174 northCount = data.getCounterValue();
175 southCount = instrIn.getCounterValue();
176 data.setCounterValue(0);
177 instrIn.setCounterValue(0);
179 public void startCounters() { startCounters(true, true); }
180 public void startCounters(boolean south, boolean north) {
181 instrIn.setCounterEnable(south);
182 data.setCounterEnable(north);
184 public int getNorthCount() { return northCount; }
185 public int getSouthCount() { return southCount; }
188 public void masterClear() {
189 final double WIDTH = 10; // ns
190 // Put a high going pulse on the internal chip master clear signal
191 if (model instanceof VerilogModel) {
196 VerilogModel vm = (VerilogModel)model;
198 // In real life the flags come up with some undefined
199 // value. In verilog we need to prevent the X'es from
200 // propagating, so we force the flags to a known value
202 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flag_A__set_", 0);
203 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flag_A__clr_", 1);
204 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flag_B__set_", 0);
205 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flag_B__clr_", 1);
207 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flag_D__set_", 1);
208 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flag_D__clr_", 0);
210 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flags@0.aFlag@0.net_50", 0); // A
211 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flags@0.aFlag@1.net_50", 0); // B
212 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.litDandP@0.latch2in@0.hi2inLat@0.latchKee@0.out_B_", 0); // C
214 // possible C-flag inputs
215 vm.setNodeState(prefix+"northFif@1.upDown8w@2.weakStag@22.ain["+(INDEX_OF_ADDRESS_BIT_COPIED_TO_C_FLAG_WHEN_DC_EQUALS_ONE+1)+"]", 0);
216 vm.setNodeState(prefix+"northFif@1.upDown8w@2.weakStag@22.ain["+(INDEX_OF_ADDRESS_BIT_COPIED_TO_C_FLAG_WHEN_DC_EQUALS_ZERO+1)+"]", 0);
218 // force the OLC to zero
220 for(int i=1; i<=6; i++)
221 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.olcWcont@0.olc@0.inLO["+i+"]", (i==1)?0:1);
223 // set the ILC input to 1
224 for(int i=1; i<=8; i++) {
226 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.ilcMoveO@0.ilc@0.\\inLO["+i+"]", (i==1)?0:1);
229 vm.setNodeState(prefix+"northFif@1.upDown8w@2.weakStag@22.addr1in2@0.fire", 1);
231 vm.setNodeState(prefix+"northFif@1.upDown8w@2.weakStag@22.addr1in2@0.fire", 0);
234 vm.setNodeState(MASTER_CLEAR, 1);
236 vm.setNodeState(MASTER_CLEAR, 0);
239 // pulse ilc[load] and olc[load]
240 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.ilcMoveO@0.ilc@0.ilc_load_", 1);
241 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.ilcMoveO@0.ilc@0.ilc_decLO_", 1);
242 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.ilcMoveO@0.ilc@0.ilc_torpLO_", 1);
244 vm.setNodeState(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.olcWcont@0.olc@0.olc_load_", 1);
247 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.ilcMoveO@0.ilc@0.ilc_load_");
248 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.ilcMoveO@0.ilc@0.ilc_decLO_");
249 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.ilcMoveO@0.ilc@0.ilc_torpLO_");
251 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.olcWcont@0.olc@0.olc_load_");
253 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flag_A__set_");
254 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flag_A__clr_");
255 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flag_B__set_");
256 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flag_B__clr_");
258 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flag_D__set_");
259 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flag_D__clr_");
261 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flags@0.aFlag@0.net_50");
262 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.flags@0.aFlag@1.net_50");
264 // Every move instruction, even those with Ti=0,Di=0,
265 // loads the C-flag. It will get loaded with an "X",
266 // which will then leak into the flags and from there the
268 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.litDandP@0.latch2in@0.hi2inLat@0.latchKee@0.out_B_");
269 vm.releaseNode(prefix+"northFif@1.upDown8w@2.weakStag@22.ain["+(INDEX_OF_ADDRESS_BIT_COPIED_TO_C_FLAG_WHEN_DC_EQUALS_ONE+1)+"]");
270 vm.releaseNode(prefix+"northFif@1.upDown8w@2.weakStag@22.ain["+(INDEX_OF_ADDRESS_BIT_COPIED_TO_C_FLAG_WHEN_DC_EQUALS_ZERO+1)+"]");
271 vm.releaseNode(prefix+"northFif@1.upDown8w@2.weakStag@22.addr1in2@0.fire");
273 for(int i=1; i<=8; i++) {
275 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.ilcMoveO@0.ilc@0.\\inLO["+i+"] ");
280 for(int i=1; i<=6; i++)
281 vm.releaseNode(prefix+"outputDo@0.outM1Pre@0.outDockP@0.outDockC@0.olcWcont@0.olc@0.inLO["+i+"]");
283 // the proper stopper states come up in an undefined ("X")
284 // state, so under Verilog we need to force them to a
290 } else if (model instanceof NanosimModel) {
291 NanosimModel nModel = (NanosimModel) model;
293 nModel.setNodeVoltage(prefix+"sid[9]",1.0);
294 nModel.setNodeVoltage(prefix+"sic[9]",1.0);
295 nModel.setNodeVoltage(prefix+"sir[9]",1.0);
296 nModel.waitNS(WIDTH);
297 nModel.setNodeVoltage(prefix+"sid[9]",0.0);
298 nModel.setNodeVoltage(prefix+"sic[9]",0.0);
299 nModel.setNodeVoltage(prefix+"sir[9]",0.0);
302 nModel.setNodeVoltage(MASTER_CLEAR,1.0);
303 nModel.waitNS(WIDTH);
304 nModel.setNodeVoltage(MASTER_CLEAR,0.0);
308 mc0.setLogicState(true);
309 mc1.setLogicState(true);
311 mc0.setLogicState(false);
312 mc1.setLogicState(false);
316 resetAfterMasterClear();
322 private void resetAfterMasterClear() {
323 // The following call to ChainControl.resetInBits() is vital!
324 // If you forget, then the inBits member initializes
325 // with random data. Then when you do your first write,
326 // some bits are written randomly.
327 dataChain.resetInBits();
328 dukeChain.resetInBits();
329 reportChain.resetInBits();
330 controlChain.resetInBits();
332 // For reset, I want to clear all the stoppers simultaneously
341 data.resetAfterMasterClear();
342 //tokOut.resetAfterMasterClear();
343 instrIn.resetAfterMasterClear();
347 /** Get the 6 bit outer loop counter. */
348 public int getOLC() {
349 shiftReport(true, false);
351 BitVector bits = null;
352 for(int i=0; i<4; i++) {
353 BitVector x = reportChain.getOutBits(REPORT_CHAIN+"."+OLC_PATH_KESSEL+i);
354 //System.out.println("bits are: " + x);
355 bits = bits==null ? x : bits.cat(x);
357 System.out.print(" kesselsCounter = ");
361 for(int bit=5; bit>=0; bit--) {
362 boolean zeroOrTwo = bits.get(4+bit*3);
363 boolean zeroOrDone = bits.get(4+bit*3+1);
364 if ( zeroOrTwo && !zeroOrDone) {
366 System.out.print("2");
368 } else if (!zeroOrTwo && !zeroOrDone) {
370 System.out.print("1");
372 } else if ( zeroOrTwo && zeroOrDone) {
373 System.out.print("0");
376 } else if (!zeroOrTwo && zeroOrDone) {
377 System.out.print("_");
378 if (!done) bad = true;
380 // FIXME: check for unreduced counter and warn about it
382 if (bad) System.out.print(" WARNING: UNREDUCED COUNTER VALUE!!!!!!");
383 System.out.println();
385 } else if (kesselsCounter) {
386 BitVector bits = null;
387 for(int i=0; i<4; i++) {
388 BitVector x = reportChain.getOutBits(REPORT_CHAIN+"."+OLC_PATH_KESSEL+i);
389 //System.out.println("bits are: " + x);
390 bits = bits==null ? x : bits.cat(x);
392 //System.out.println("kesselsCounter = " + bits);
399 for(int i=0; i<6; i++) {
400 first |= bits.get(4+i*3) ? (1<<i) : 0;
401 second |= bits.get(4+i*3+2) ? (1<<i) : 0;
402 hi = (bits.get(4+i*3) ? "1" : "0") + hi;
403 lo = (bits.get(4+i*3+2) ? "1" : "0") + lo;
405 ( bits.get(4+i*3) && !bits.get(4+i*3+2) ? "X"
406 : !bits.get(4+i*3) && !bits.get(4+i*3+2) ? "0"
407 : !bits.get(4+i*3) && bits.get(4+i*3+2) ? "1"
410 latched = (bits.get(4+i*3+1) ? "0" : "1") + latched;
412 System.out.println("kesselsCounter: "+
415 " latched="+latched +
417 " do[ins]="+(bits.get(0) ? "1" : "0")+
418 " dec="+(bits.get(1) ? "1" : "0")+
419 " flag[D][set]="+(bits.get(2) ? "1" : "0")+
420 " resetting="+(bits.get(3) ? "1" : "0")+
423 return (first+second);
425 BitVector odd = reportChain.getOutBits(REPORT_CHAIN+"."+OLC_PATH_ODD).bitReverse();
426 BitVector even = reportChain.getOutBits(REPORT_CHAIN+"."+OLC_PATH_EVEN).bitReverse();
429 BitVector bv = new BitVector(6, "olc");
430 for(int i=0; i<3; i++) {
431 bv.set(i*2, odd.get(i));
432 bv.set(i*2+1, even.get(i));
434 return (int)bv.toLong();
437 /** Get the 7 bit inner loop counter. The MSB is the zero bit.
438 * The low order 6 bits are the count */
439 public Ilc getILC() {
442 /** Get the A flag */
443 public boolean getFlagA() {
444 shiftReport(true, false);
445 return reportChain.getOutBits(REPORT_CHAIN+"."+FLAGS_PATH).get(A_FLAG_NDX);
447 /** Get the B flag */
448 public boolean getFlagB() {
449 shiftReport(true, false);
450 return reportChain.getOutBits(REPORT_CHAIN+"."+FLAGS_PATH).get(B_FLAG_NDX);
452 /** return value of instruction counter. Instruction counter counts
453 * the instructions flowing through 1/2 of alternating FIFO.
454 * Caution: instruction counter is written by all scans,
455 * regardless of readEnable or writeEnable! */
456 public long getInstructionCounter() {
457 shiftData(true, false);
458 BitVector count = dataChain.getOutBits(DATA_CHAIN+"."+INSTRUCTION_COUNTER_PATH);
459 int sz = count.getNumBits();
460 MarinaTest.fatal(sz!=COUNTER_LENGTH, "wrong number of counter bits: "+sz+
461 " expected: "+COUNTER_LENGTH);
462 return count.bitReverse().toLong();
464 /** return value of data counter. Data counter counts items flowing
465 * through drain stage of data proper stopper.
466 * Caution: data counter is written by all scans,
467 * regardless of readEnable or writeEnable! */
468 public long getDataCounter() {
469 shiftData(true, false);
470 BitVector count = dataChain.getOutBits(DATA_CHAIN+"."+DATA_COUNTER_PATH);
471 int sz = count.getNumBits();
472 MarinaTest.fatal(sz!=COUNTER_LENGTH, "wrong number of counter bits: "+sz+
473 " expected: "+COUNTER_LENGTH);
474 return count.bitReverse().toLong();
476 /** Fill the "North" Fifo ring */
477 public void fillNorthProperStopper() {
478 BitVector data = new BitVector(37, "empty");
479 BitVector addr = new BitVector(14, "empty");
480 for(int i=0; i<data.getNumBits(); i++) data.set(i, false);
481 for(int i=0; i<addr.getNumBits(); i++) addr.set(i, false);
482 fillNorthProperStopper(new MarinaPacket(data, false, addr));
484 /** Fill the "North" Fifo ring */
485 public void fillNorthProperStopper(MarinaPacket mp) {
486 prln("inserting into north: " + mp);
487 this.data.fill(mp.toSingleBitVector());
489 /** Enable the transmission of instructions from the instruction
490 * ring test structure to the EPI FIFO. */
491 public void enableInstructionSend(boolean b) {
492 BitVector bv = controlChain.getInBits(CONTROL_CHAIN+"."+INSTR_RING_CONTROL_PATH);
493 bv.set(INSTRUCTION_SEND_NDX, b);
494 controlChain.setInBits(CONTROL_CHAIN+"."+INSTR_RING_CONTROL_PATH, bv);
495 shiftControl(false, true);
497 /** Enable the recirculation of instructions within the South FIFO */
498 public void enableInstructionRecirculate(boolean b) {
499 BitVector bv = controlChain.getInBits(CONTROL_CHAIN+"."+INSTR_RING_CONTROL_PATH);
500 bv.set(INSTRUCTION_RECIRCULATE_NDX, b);
501 controlChain.setInBits(CONTROL_CHAIN+"."+INSTR_RING_CONTROL_PATH, bv);
502 shiftControl(false, true);
504 /** get the number of tokens in the token FIFO.
505 * This includes the Token successor wire, the token FIFO wires,
506 * and Token predecessor wire.
507 * Master clear clears the token FIFO. */
508 public int getNumTokens() {
509 shiftReport(true, false);
510 // get the token successor and token FIFO wires
511 BitVector bv = reportChain.getOutBits(REPORT_CHAIN+"."+TOK_FIFO_PATH);
512 int sz = bv.getNumBits();
513 MarinaTest.fatal(sz!=3, "wrong token FIFO size: "+sz+" expected: 3");
515 // get the token predecessor wire
516 BitVector pred = reportChain.getOutBits(REPORT_CHAIN+"."+TOK_PRED_PATH);
517 sz = pred.getNumBits();
518 MarinaTest.fatal(sz!=1, "wrong token predecessor size: "+sz+" expected: 1");
522 sz = bv.getNumBits();
523 prln("Token state wires: "+bv.getState());
526 for (int i=0; i<sz; i++) if (bv.get(i)) nbTok++;
529 /** Configure the test probe so it measures the throughput of
530 * the north data FIFO. The test probe frequency is 8192
531 * times slower than the FIFO throughput. This control has
532 * highest priority. */
533 public void probeDataCounter(Boolean b) {
534 data.setGeneralPurposeOutput(b);
536 /** Configure the test probe so it measures the throughput of
537 * the alternating instruction FIFO. The test probe frequency is
538 * 1/16384 of the FIFO throughput. This control has second
539 * highest priority. Thus the following two calls probe the
540 * instruction counter:
541 * probeDataCounter(false);
542 * probeInstructionCounter(true)
544 public void enableInstructionCounter(Boolean b) {
545 instrIn.setGeneralPurposeOutput(b);
548 public void fillSouthProperStopper(Instruction i) {
551 public void fillSouthProperStopper(Instruction[] instructions) { fillSouthProperStopper(instructions, false); }
552 public void fillSouthProperStopper(Instruction[] instructions, boolean repeat) { fillSouthProperStopper(instructions, repeat, false); }
553 public void fillSouthProperStopper(Instruction[] instructions, boolean repeat, boolean leaveStopped) {
554 enableInstructionSend(false);
555 enableInstructionRecirculate(true);
556 for(Instruction i : instructions)
560 instrIn.fillTorpedo();
562 enableInstructionRecirculate(repeat);
563 enableInstructionSend(true);
564 if (!leaveStopped) instrIn.run();