import java.util.*;
import java.io.*;
+/*
+You should note the following:
+I haven't implemented all the link-out policies.
+You can give the SHIP a single cmd with up to four operations. For
+example, "ADD ZERO 0 SUBTRACT SIGN 1 MAX MAX 0". These will be done
+in left-to-right order.
+You can use any link-out policy with any operation, though some don't
+make much sense.
+*/
+
+/**
+ * @author Dominic Antonelli <dantonel@berkeley.edu>
+ */
public class ArithmeticShip extends Ship {
- TokenOutbox tout = new TokenOutbox(this, "tout");
- TokenInbox tin = new TokenInbox(this, "tin");
- DataOutbox dout = new DataOutbox(this, "dout");
- DataInbox din = new DataInbox(this, "din");
+ private int link;
+
+ DataInbox A = new DataInbox(this, "A");
+ DataInbox B = new DataInbox(this, "B");
+ DataInbox cmd = new DataInbox(this, "cmd");
+ DataOutbox out = new DataOutbox(this, "out");
public ArithmeticShip(Fleet fleet, String name) {
super(fleet, name);
}
- public void service() {
+ public enum Operation {
+ // NOTE: NOP is not to be used, but rather simply prevents other ops from using opcode 0
+ // This is so that we can detect the "end" of a command - when the command is all zero
+ NOP { int eval(int a, int b, int link) { System.out.println("ERROR: Arith_NOP\n"); return 0; } },
+ ADD { int eval(int a, int b, int link) { return a + b + link; } },
+ SUBTRACT { int eval(int a, int b, int link) { return a - b + link; } },
+ COPY_A { int eval(int a, int b, int link) { return a + link; } },
+ COPY_B { int eval(int a, int b, int link) { return b + link; } },
+ SELECT { int eval(int a, int b, int link) { return ((link==1) ? b : a); } },
+ NEGATE_A { int eval(int a, int b, int link) { return -(a+link); } },
+ NEGATE_B { int eval(int a, int b, int link) { return -(b+link); } },
+ ABS_A { int eval(int a, int b, int link) { a+=link; return (a<0 ? -a : a); } },
+ ABS_B { int eval(int a, int b, int link) { b+=link; return (b<0 ? -b : b); } },
+ MAX { int eval(int a, int b, int link) { return (a>b ? a : b) + link; } },
+ MIN { int eval(int a, int b, int link) { return (a<b ? a : b) + link; } },
+ INC_A { int eval(int a, int b, int link) { return a+1+link; } },
+ INC_B { int eval(int a, int b, int link) { return b+1+link; } },
+ RESERVED1 { int eval(int a, int b, int link) { System.out.println("ERROR: Arith_RESERVED0\n"); return 0; } },
+ RESERVED2 { int eval(int a, int b, int link) { System.out.println("ERROR: Arith_RESERVED1\n"); return 0; } };
- // dominic, pretend this method is inside an infinite loop;
- // every time it is invoked you should:
- // 1. check your input ports to see if they have stuff
- // 2. make sure your output ports don't still have stuff stuck
- // in them (if they do, just return and wait until later)
+ // Do arithmetic op represented by this constant
+ abstract int eval(int a, int b, int link);
+ public static Operation convertInt( int i ) {
+ return values()[i];
+ }
+ }
- // 3. do your thing
+ public enum LinkOutPolicy {
+ LINK_IN, ZERO, CARRY, SIGN, OLD_SIGN, OVERFLOW, MAX, MIN;
+ public static LinkOutPolicy convertInt( int i ) {
+ return values()[i];
+ }
+ }
- // here's some sample code snippets that should cover all the
- // cases you need
+ private long savedCommand = 0;
- if (!din.dataReadyForShip())
- return;
- /*
- if (!tin.tokenReadyForShip())
+ public void service() {
+ if (!out.readyForDataFromShip()) return;
+ if (!A.dataReadyForShip()) return;
+ if (!B.dataReadyForShip()) return;
+
+ long command;
+
+ if (savedCommand != 0) {
+ command = savedCommand;
+ } else if (!cmd.dataReadyForShip()) {
return;
- */
-
- int mydat = din.removeDataForShip();
- Log.println("ArithmeticShip: got a " + mydat);
- /*
- tin.removeTokenForShip();
- */
-
- /*
- if (tout.readyForTokenFromShip())
- tout.addTokenFromShip();
- if (dout.readyForDataFromShip())
- dout.addDataFromShip(123);
- */
+ } else {
+ command = cmd.removeDataForShip();
+ }
+
+ int inA = A.removeDataForShip();
+ int inB = B.removeDataForShip();
+ int linkInPolicy = (int)(command & 0x1);
+ LinkOutPolicy linkOutPolicy = LinkOutPolicy.convertInt((int)((command >> 1) & 0x7));
+ Operation op = Operation.convertInt((int)((command >> 4) & 0xf));
+ int result = 0;
+
+ int oldLink = link;
+ if (op == Operation.SELECT) {
+ link = link ^ linkInPolicy; // LinkInPolicy = 1 mean flip the selection for the SELECT op.
+ } else {
+ link = link & linkInPolicy; // If linkInPolicy is zero, unset the link bit for the upcoming computation.
+ // NOTE: The final value of link will be computed after eval.
+ }
+
+ result = op.eval(inA, inB, link);
+
+ switch (linkOutPolicy) {
+ case LINK_IN:
+ link = oldLink;
+ break;
+ case ZERO:
+ link = (result == 0) ? 1 : 0;
+// link = 0;
+ break;
+ case SIGN:
+ link = (result >> 31) & 0x1;
+ break;
+ case MAX:
+ if (inA > inB) link = 1; else link = 0;
+ break;
+ case MIN:
+ if (inA < inB) link = 1; else link = 0;
+ break;
+ case CARRY:
+ case OLD_SIGN:
+ case OVERFLOW:
+ System.out.println("ERROR: non-implemented linkOutPolicy selected");
+ break;
+ default:
+ System.out.println("ERROR: Unknown linkOutPolicy selected");
+ break;
+ };
+ out.addDataFromShip(result);
+
+ savedCommand = command >> 8;
+
+// System.out.println("Link is now " + link);
}
public int resolveShipSpecificConstant(String shipSpecificData) {
- // normally you would want to parse shipSpecificData somehow
- return shipSpecificData.length();
- }
+ String[] data = shipSpecificData.split("\\s");
+ int result = 0;
+ if ((data.length % 3) != 0) {
+ System.out.println("ERROR: ArithmeticShip received invalid ShipSpecificConstant");
+ }
+ for (int i = data.length - 1; i >= 2; i-=3) {
+ result <<= 8;
+ if (data[i].equals("1")) {
+ result |= 1;
+ }
+ for (LinkOutPolicy policy : LinkOutPolicy.values()) {
+ if (data[i-1].equals(policy.toString())) {
+ result |= (policy.ordinal() << 1);
+ }
+ }
+ for (Operation op : Operation.values()) {
+ if (data[i-2].equals(op.toString())) {
+ result |= (op.ordinal() << 4);
+ }
+ }
+ }
+ return result;
+ }
}