fix awful c-flag bug in Memory.ship
[fleet.git] / ships / Alu.ship
index 9cc5e77..3b2117f 100644 (file)
@@ -11,6 +11,9 @@ data  in:   inOp
   constant MAX: 4
   constant MIN: 5
   constant CMP: 6
+  constant DROP1: 7
+  constant DROP2: 8
+  constant MAXMERGE: 9
 
 data  out:  out
 
@@ -36,13 +39,16 @@ is then made available at {\tt out}.
 \subsection*{C-Flag}
 
 \begin{verbatim}
-IN1 - undefined
-IN2 - undefined
-ADD - carry-out
-SUB - undefined
-MAX - 0 if in1>in2, else 1
-MIN - 1 if in1>in2, else 0
-CMP - 0 if in1!=in2, else 1
+IN1      - undefined; drain in1 only
+IN2      - undefined; drain in2 only
+ADD      - carry-out
+SUB      - undefined
+MAX      - if in1>in2 cflag=0 and drain in1, else cflag=1 and drain in2
+MIN      - if in1>in2 cflag=1 and drain in2, else cflag=0 and drain in1
+CMP      - if in1==in2 cflag=1, else cflag=0
+DROP1    - consume in1, produce no output
+DROP2    - consume in2, produce no output
+MAXMERGE - if (in1<0 && in2<0) consume both, emit either, cflag=undef else act as MAX
 \end{verbatim}
 
 \subsection*{To Do}
@@ -56,29 +62,56 @@ yet implemented.
 
 == Fleeterpreter ====================================================
 public void service() {
-  if (box_in1.dataReadyForShip() &&
+  if (box_inOp.dataReadyForShip() &&
+      box_in1.dataReadyForShip() &&
       box_in2.dataReadyForShip() &&
-      box_inOp.dataReadyForShip() &&
       box_out.readyForDataFromShip()) {
-      long a      = box_in1.removeDataForShip();
-      long b      = box_in2.removeDataForShip();
+      long a;
+      long b;
       long op     = box_inOp.removeDataForShip();
       switch((int)op) {
-          case 0: box_out.addDataFromShip(a); // IN1
+          case 0:
+              a = box_in1.removeDataForShip();
+              box_out.addDataFromShip(a); // IN1
               break;
-          case 1: box_out.addDataFromShip(b); // IN2
+          case 1:
+              b = box_in2.removeDataForShip();
+              box_out.addDataFromShip(b); // IN2
               break;
-          case 2: box_out.addDataFromShip(a+b); // ADD
+          case 2:
+              a = box_in1.removeDataForShip();
+              b = box_in2.removeDataForShip();
+              box_out.addDataFromShip(a+b); // ADD
               break;
-          case 3: box_out.addDataFromShip(a-b); // SUB
+          case 3:
+              a = box_in1.removeDataForShip();
+              b = box_in2.removeDataForShip();
+              box_out.addDataFromShip(a-b); // SUB
               break;
-          case 4: box_out.addDataFromShip(Math.max(a,b)); // MAX
+          case 4:
+              a = box_in1.peekDataForShip();
+              b = box_in2.peekDataForShip();
+              box_out.addDataFromShip(Math.max(a,b)); // MAX
               box_out.flag_c = !(a>b);
+              if (a<b) box_in1.removeDataForShip(); else box_in2.removeDataForShip();
               break;
-          case 5: box_out.addDataFromShip(Math.min(a,b)); // MIN
+          case 5:
+              a = box_in1.peekDataForShip();
+              b = box_in2.peekDataForShip();
+              box_out.addDataFromShip(Math.min(a,b)); // MIN
               box_out.flag_c = a>b;
+              if (a>b) box_in1.removeDataForShip(); else box_in2.removeDataForShip();
               break;
-          default: box_out.addDataFromShip(0);
+          case 6:
+              a = box_in1.removeDataForShip();
+              b = box_in2.removeDataForShip();
+              box_out.addDataFromShip(0); // CMP
+              box_out.flag_c = a==b;
+              break;
+          default:
+              a = box_in1.removeDataForShip();
+              b = box_in2.removeDataForShip();
+              box_out.addDataFromShip(0);
               break;
       }
   }
@@ -88,59 +121,74 @@ public void service() {
 
 == FPGA ==============================================================
 
-  wire [`DATAWIDTH:0]     sum;
+  wire [`WORDWIDTH:0]     sum;
   wire                    cin;
-  wire [(`DATAWIDTH-1):0] in2_inverted;
+  wire [(`WORDWIDTH-1):0] in2_inverted;
 
-  wire [(`DATAWIDTH-1):0] res;
+  wire [(`WORDWIDTH-1):0] res;
   wire                    isplus;
   wire                    eq;
   wire                    cout;
 
-  assign isplus       = inOp_d[2:0]==2;
-  assign cin          = isplus ? 0 : 1;
-  assign in2_inverted = isplus ? in2_d : ~in2_d;
-  assign sum          = {in1_d,cin} + {in2_inverted,cin};
-  assign res          = sum[`DATAWIDTH:1];
-  assign greater      = !res[`DATAWIDTH-1];
-  assign eq           = in1_d == in2_d;
-  assign cout         = sum[`DATAWIDTH];
-
-  assign out_d_[`DATAWIDTH] =
-          (inOp_d==0) ? 1'b0 :
-          (inOp_d==1) ? 1'b0 :
-          (inOp_d==2) ? cout :
-          (inOp_d==3) ? 1'b0 :
-          (inOp_d==4) ? ~greater :
-          (inOp_d==5) ?  greater :
-          (inOp_d==6) ?  eq :
+  wire [3:0]              inOp_d_trunc;
+  assign                  inOp_d_trunc = inOp_d[3:0];
+
+  assign isplus        = inOp_d_trunc[2:0]==2;
+  assign cin           = isplus ? 0 : 1;
+  assign in2_inverted  = isplus ? in2_d : ~in2_d;
+  assign sum           = {in1_d,cin} + {in2_inverted,cin};
+  assign res           = sum[`WORDWIDTH:1];
+  assign greater       = !res[`WORDWIDTH-1];
+  assign both_negative = in1_d[`WORDWIDTH-1] && in2_d[`WORDWIDTH-1];
+  assign eq            = in1_d == in2_d;
+  assign cout          = sum[`WORDWIDTH];
+
+  assign out_d_[`WORDWIDTH] =
+          (inOp_d_trunc==0) ? 1'b0 :
+          (inOp_d_trunc==1) ? 1'b0 :
+          (inOp_d_trunc==2) ? cout :
+          (inOp_d_trunc==3) ? cout :
+          (inOp_d_trunc==4) ? ~greater :
+          (inOp_d_trunc==5) ?  greater :
+          (inOp_d_trunc==6) ?  eq :
+          (inOp_d_trunc==9) ? ~greater :
           0;
 
-  assign out_d_[(`DATAWIDTH-1):0] =
-          (inOp_d==0) ? (in1_d)  :
-          (inOp_d==1) ? (in2_d)  :
-          (inOp_d==2) ? (res)  :
-          (inOp_d==3) ? (res)  :
-          (inOp_d==4) ? (greater ? in1_d : in2_d)  :
-          (inOp_d==5) ? (greater ? in2_d : in1_d)  :
-          (inOp_d==6) ? {{ (`DATAWIDTH-1) {1'b0 }}, eq  } :
+  assign out_d_[(`WORDWIDTH-1):0] =
+          (inOp_d_trunc==0) ? (in1_d)  :
+          (inOp_d_trunc==1) ? (in2_d)  :
+          (inOp_d_trunc==2) ? (res)  :
+          (inOp_d_trunc==3) ? (res)  :
+          (inOp_d_trunc==4) ? (greater ? in1_d : in2_d)  :
+          (inOp_d_trunc==5) ? (greater ? in2_d : in1_d)  :
+          (inOp_d_trunc==6) ? {{ (`WORDWIDTH-1) {1'b0 }}, eq  } :
+          (inOp_d_trunc==9) ? (both_negative ? in1_d : (greater ? in1_d : in2_d)) :
           0;
 
   always @(posedge clk) begin
     if (!rst) begin
       `reset
     end else begin
-      if (!in1_r   && in1_a)    in1_a    <= 0;
-      if (!in2_r   && in2_a)    in2_a    <= 0;
-      if (!inOp_r  && inOp_a)   inOp_a   <= 0;
-      if (out_r    && out_a) begin
-        out_r    <= 0;
-        in1_a <= 1;
-        in2_a <= 1;
-        inOp_a <= 1;
+      `flush
+      `cleanup
+      if (`out_draining) begin
+        `drain_inOp
+        if      (inOp_d_trunc==0) `drain_in1
+        else if (inOp_d_trunc==1) `drain_in2
+        else if (inOp_d_trunc==9 &&  both_negative) begin `drain_in1 `drain_in2 end
+        else if (inOp_d_trunc==4 &&  greater) `drain_in1
+        else if (inOp_d_trunc==5 &&  greater) `drain_in2
+        else if (inOp_d_trunc==9 &&  greater) `drain_in1
+        else if (inOp_d_trunc==4 && !greater) `drain_in2
+        else if (inOp_d_trunc==5 && !greater) `drain_in1
+        else if (inOp_d_trunc==9 && !greater) `drain_in2
+        else begin
+          `drain_in1
+          `drain_in2
+        end
       end
-      if (!out_r && !out_a && in1_r && !in1_a && in2_r && !in2_a && inOp_r && !inOp_a) begin
-        out_r <= 1;
+      if (`out_empty && `in1_full && `in2_full && `inOp_full) begin
+        `fill_out
       end
     end
   end
@@ -161,21 +209,19 @@ public void service() {
 #expect 9
 #expect 0
 #expect 0
-#expect 0
-#expect 1
 #expect 1
 
 debug.in:   set ilc=*;  recv, deliver;
 alu.in1:
   set word= 9;
-  set ilc=7;
+  set ilc=5;
   deliver;
   set word= 9;
   deliver;
 
 alu.in2:
   set word= 8;
-  set ilc=7;
+  set ilc=5;
   deliver;
   set word= 9;
   deliver;
@@ -188,8 +234,6 @@ alu.inOp:
  set word= Alu.inOp[SUB]; deliver;
  set word= Alu.inOp[IN1]; deliver;
  set word= Alu.inOp[IN2]; deliver;
-
-alu.inOp:
  set word= Alu.inOp[MIN]; deliver;
  set word= Alu.inOp[MAX]; deliver;
  set word= Alu.inOp[CMP]; deliver;
@@ -208,13 +252,13 @@ alu.out:
   [!a] set word= 0;
   send to debug.in;
 
-  collect, send to debug.in;        // CMP
+  collect;        // CMP
   set flags a=c, b=b;
   [a]  set word= 1;
   [!a] set word= 0;
   send to debug.in;
 
-  collect, send to debug.in;        // CMP
+  collect;        // CMP
   set flags a=c, b=b;
   [a]  set word= 1;
   [!a] set word= 0;