fix Counter.ship software implementation to exactly match semantics of FPGA
[fleet.git] / ships / Counter.ship
index 05f98a9..37aa452 100644 (file)
@@ -31,60 +31,68 @@ boolean op_c2 = false;
 boolean op_v1 = false;
 boolean op_v2 = false;
 long temp = 0;
+boolean out_draining;
 
 public void reset() {
   super.reset();
   full = false;
   temp = 0;
+  out_draining = false;
 }
 public void service() {
 
-  if (full) {
-    if (temp < 0) {
-      temp = 0;
-      full = false;
+  if (!box_inOp.dataReadyForShip()) full = false;
 
-      // ugly hack due to mishandling of resets
-      if (box_inOp.dataReadyForShip()) box_inOp.removeDataForShip();
+  if (out_draining && box_out.readyForDataFromShip()) {
+    if (op_count) temp = temp - box_in2.peekDataForShip();
+    else          temp--;
+    if (op_pass && op_v1) box_in1.removeDataForShip();
+    if (op_pass && op_v2) box_in2.removeDataForShip();
+    out_draining = false;
 
+  } else if (box_inOp.dataReadyForShip()) {
+    long op   = box_inOp.peekDataForShip();
+    op_count  = (op & 15)==12;
+    op_repeat = ((op>>2) & 3)==0;
+    op_pass   = ((op>>2) & 3)==1;
+    op_drop   = ((op>>2) & 3)==2;
+    op_c1     = (op_repeat || op_pass || op_drop) && !(((op>>1)&1)!=0);
+    op_c2     = (op_repeat || op_pass || op_drop) &&  (((op>>1)&1)!=0);
+    op_v1     = (op_repeat || op_pass || op_drop) && !(((op>>0)&1)!=0);
+    op_v2     = (op_repeat || op_pass || op_drop) &&  (((op>>0)&1)!=0);
+    if (!full) {
+      if (op_count && box_in1.dataReadyForShip() && box_in2.dataReadyForShip()) {
+        temp = box_in1.peekDataForShip() - box_in2.peekDataForShip();
+        box_in1.removeDataForShip();
+        full = true;
+      } else if (op_c1 && box_in1.dataReadyForShip()) {
+        temp = box_in1.peekDataForShip() - 1;
+        box_in1.removeDataForShip();
+        full = true;
+      } else if (op_c2 && box_in2.dataReadyForShip()) {
+        temp = box_in2.peekDataForShip() - 1;
+        box_in2.removeDataForShip();
+        full = true;
+      }
+    } else if (temp < 0) {
+      full = false;
+      box_inOp.removeDataForShip();
       if (op_count) box_in2.removeDataForShip();
       else if (op_repeat && op_v1) box_in1.removeDataForShip();
       else if (op_repeat && op_v2) box_in2.removeDataForShip();
 
     } else if (box_out.readyForDataFromShip()) {
       if (op_count) {
+        out_draining = true;
         box_out.addDataFromShip(temp, (temp - box_in2.peekDataForShip()) < 0);
-        temp = temp - box_in2.peekDataForShip();
       } else if (op_v1 && box_in1.dataReadyForShip()) {
         if (op_drop) { box_in1.removeDataForShip(); temp--; }
-        else         { box_out.addDataFromShip(op_pass ? box_in1.removeDataForShip() : box_in1.peekDataForShip(), temp<=0); temp--; }
+        else         { box_out.addDataFromShip(box_in1.peekDataForShip(), temp<=0); out_draining = true; }
       } else if (op_v2 && box_in2.dataReadyForShip()) {
         if (op_drop) { box_in2.removeDataForShip(); temp--; }
-        else         { box_out.addDataFromShip(op_pass ? box_in2.removeDataForShip() : box_in2.peekDataForShip(), temp<=0); temp--; }
+        else         { box_out.addDataFromShip(box_in2.peekDataForShip(), temp<=0); out_draining = true; }
       }
-      
     }
-
-  } else if (box_inOp.dataReadyForShip()) {
-    long op   = box_inOp.peekDataForShip();
-    op_count  = (op & 15)==12;
-    op_repeat = ((op>>2) & 3)==0;
-    op_pass   = ((op>>2) & 3)==1;
-    op_drop   = ((op>>2) & 3)==2;
-    op_c1     = (op_repeat || op_pass || op_drop) && !(((op>>1)&1)!=0);
-    op_c2     = (op_repeat || op_pass || op_drop) &&  (((op>>1)&1)!=0);
-    op_v1     = (op_repeat || op_pass || op_drop) && !(((op>>0)&1)!=0);
-    op_v2     = (op_repeat || op_pass || op_drop) &&  (((op>>0)&1)!=0);
-
-    if (op_count && (!box_in1.dataReadyForShip() || !box_in2.dataReadyForShip())) return;
-    if (op_c1    &&  !box_in1.dataReadyForShip()) return;
-    if (op_c2    &&  !box_in2.dataReadyForShip()) return;
-    
-    full = true;
-
-    if (op_count) temp = box_in1.removeDataForShip() - box_in2.peekDataForShip();
-    if (op_c1)    temp = box_in1.removeDataForShip()-1;
-    if (op_c2)    temp = box_in2.removeDataForShip()-1;
   }
 }