From 8cd7e5066f72d9fafff50dc8ab58cc0cd29b88ce Mon Sep 17 00:00:00 2001
From: Maurus Item <itemm@student.ethz.ch>
Date: Fri, 14 Jun 2024 11:20:55 +0200
Subject: [PATCH] Fixed Various internals that caused problems when bitflips
 occur. - Removed recursive assignments that can cause trouble in simulation -
 Removed repeated assignments in always_comb of classifier that cause trouble
 in simulation - Fixed format selection can evaluate to X when faults are
 injected into Enum in simulation.

---
 src/fpnew_classifier.sv    | 21 +++++++++++----------
 src/fpnew_fma.sv           | 18 ++++++++++++------
 src/fpnew_fma_multi.sv     | 17 ++++++++++++-----
 src/fpnew_opgroup_block.sv |  2 +-
 src/fpnew_pkg.sv           |  2 +-
 5 files changed, 37 insertions(+), 23 deletions(-)

diff --git a/src/fpnew_classifier.sv b/src/fpnew_classifier.sv
index a322946d..927cf051 100644
--- a/src/fpnew_classifier.sv
+++ b/src/fpnew_classifier.sv
@@ -55,20 +55,21 @@ module fpnew_classifier #(
       is_boxed      = is_boxed_i[op];
       is_normal     = is_boxed && (value.exponent != '0) && (value.exponent != '1);
       is_zero       = is_boxed && (value.exponent == '0) && (value.mantissa == '0);
-      is_subnormal  = is_boxed && (value.exponent == '0) && !is_zero;
       is_inf        = is_boxed && ((value.exponent == '1) && (value.mantissa == '0));
+      is_subnormal  = is_boxed && (value.exponent == '0) && !is_zero;
       is_nan        = !is_boxed || ((value.exponent == '1) && (value.mantissa != '0));
       is_signalling = is_boxed && is_nan && (value.mantissa[MAN_BITS-1] == 1'b0);
       is_quiet      = is_nan && !is_signalling;
-      // Assign output for current input
-      info_o[op].is_normal     = is_normal;
-      info_o[op].is_subnormal  = is_subnormal;
-      info_o[op].is_zero       = is_zero;
-      info_o[op].is_inf        = is_inf;
-      info_o[op].is_nan        = is_nan;
-      info_o[op].is_signalling = is_signalling;
-      info_o[op].is_quiet      = is_quiet;
-      info_o[op].is_boxed      = is_boxed;
     end
+
+    // Assign output for current input
+    assign info_o[op].is_normal     = is_normal;
+    assign info_o[op].is_subnormal  = is_subnormal;
+    assign info_o[op].is_zero       = is_zero;
+    assign info_o[op].is_inf        = is_inf;
+    assign info_o[op].is_nan        = is_nan;
+    assign info_o[op].is_signalling = is_signalling;
+    assign info_o[op].is_quiet      = is_quiet;
+    assign info_o[op].is_boxed      = is_boxed;
   end
 endmodule
diff --git a/src/fpnew_fma.sv b/src/fpnew_fma.sv
index c6ef899a..992dbadd 100644
--- a/src/fpnew_fma.sv
+++ b/src/fpnew_fma.sv
@@ -147,22 +147,28 @@ module fpnew_fma #(
   // | MUL      | \c 0        | MUL: Set operand C to +0.0 or -0.0 depending on the rounding mode
   // | *others* | \c -        | *invalid*
   // \note \c op_mod_q always inverts the sign of the addend.
-  always_comb begin : op_select
 
+  // Fix for InjectaFault
+  fp_t                 operand_a_base, operand_b_base, operand_c_base;
+  assign operand_a_base = inp_pipe_operands_q[NUM_INP_REGS][0];
+  assign operand_b_base = inp_pipe_operands_q[NUM_INP_REGS][1];
+  assign operand_c_base = inp_pipe_operands_q[NUM_INP_REGS][2];
+
+  always_comb begin : op_select
     // Default assignments - packing-order-agnostic
-    operand_a = inp_pipe_operands_q[NUM_INP_REGS][0];
-    operand_b = inp_pipe_operands_q[NUM_INP_REGS][1];
-    operand_c = inp_pipe_operands_q[NUM_INP_REGS][2];
+    operand_a = operand_a_base;
+    operand_b = operand_b_base;
+    operand_c = operand_c_base;
     info_a    = info_q[0];
     info_b    = info_q[1];
     info_c    = info_q[2];
 
     // op_mod_q inverts sign of operand C
-    operand_c.sign = operand_c.sign ^ inp_pipe_op_mod_q[NUM_INP_REGS];
+    operand_c.sign = operand_c_base.sign ^ inp_pipe_op_mod_q[NUM_INP_REGS];
 
     unique case (inp_pipe_op_q[NUM_INP_REGS])
       fpnew_pkg::FMADD:  ; // do nothing
-      fpnew_pkg::FNMSUB: operand_a.sign = ~operand_a.sign; // invert sign of product
+      fpnew_pkg::FNMSUB: operand_a.sign = ~operand_a_base.sign; // invert sign of product
       fpnew_pkg::ADD: begin // Set multiplicand to +1
         operand_a = '{sign: 1'b0, exponent: BIAS, mantissa: '0};
         info_a    = '{is_normal: 1'b1, is_boxed: 1'b1, default: 1'b0}; //normal, boxed value.
diff --git a/src/fpnew_fma_multi.sv b/src/fpnew_fma_multi.sv
index 77886424..89dce97f 100644
--- a/src/fpnew_fma_multi.sv
+++ b/src/fpnew_fma_multi.sv
@@ -196,22 +196,29 @@ module fpnew_fma_multi #(
   // | MUL      | \c 0        | MUL: Set operand C to +0.0 or -0.0 depending on the rounding mode
   // | *others* | \c -        | *invalid*
   // \note \c op_mod_q always inverts the sign of the addend.
+
+  // Fix for InjectaFault
+  fp_t                 operand_a_base, operand_b_base, operand_c_base;
+  assign operand_a_base = {fmt_sign[src_fmt_q][0], fmt_exponent[src_fmt_q][0], fmt_mantissa[src_fmt_q][0]};
+  assign operand_b_base = {fmt_sign[src_fmt_q][1], fmt_exponent[src_fmt_q][1], fmt_mantissa[src_fmt_q][1]};
+  assign operand_c_base = {fmt_sign[dst_fmt_q][2], fmt_exponent[dst_fmt_q][2], fmt_mantissa[dst_fmt_q][2]};
+
   always_comb begin : op_select
 
     // Default assignments - packing-order-agnostic
-    operand_a = {fmt_sign[src_fmt_q][0], fmt_exponent[src_fmt_q][0], fmt_mantissa[src_fmt_q][0]};
-    operand_b = {fmt_sign[src_fmt_q][1], fmt_exponent[src_fmt_q][1], fmt_mantissa[src_fmt_q][1]};
-    operand_c = {fmt_sign[dst_fmt_q][2], fmt_exponent[dst_fmt_q][2], fmt_mantissa[dst_fmt_q][2]};
+    operand_a = operand_a_base;
+    operand_b = operand_b_base;
+    operand_c = operand_c_base;
     info_a    = info_q[src_fmt_q][0];
     info_b    = info_q[src_fmt_q][1];
     info_c    = info_q[dst_fmt_q][2];
 
     // op_mod_q inverts sign of operand C
-    operand_c.sign = operand_c.sign ^ inp_pipe_op_mod_q[NUM_INP_REGS];
+    operand_c.sign = operand_c_base.sign ^ inp_pipe_op_mod_q[NUM_INP_REGS];
 
     unique case (inp_pipe_op_q[NUM_INP_REGS])
       fpnew_pkg::FMADD:  ; // do nothing
-      fpnew_pkg::FNMSUB: operand_a.sign = ~operand_a.sign; // invert sign of product
+      fpnew_pkg::FNMSUB: operand_a.sign = ~operand_a_base.sign; // invert sign of product
       fpnew_pkg::ADD: begin // Set multiplicand to +1
         operand_a = '{sign: 1'b0, exponent: fpnew_pkg::bias(src_fmt_q), mantissa: '0};
         info_a    = '{is_normal: 1'b1, is_boxed: 1'b1, default: 1'b0}; //normal, boxed value.
diff --git a/src/fpnew_opgroup_block.sv b/src/fpnew_opgroup_block.sv
index 18bbb17c..76b2912b 100644
--- a/src/fpnew_opgroup_block.sv
+++ b/src/fpnew_opgroup_block.sv
@@ -177,7 +177,7 @@ module fpnew_opgroup_block #(
 
     logic in_valid;
 
-    assign in_valid = in_valid_i & (FmtUnitTypes[dst_fmt_i] == fpnew_pkg::MERGED);
+    assign in_valid = in_valid_i & (FmtUnitTypes[dst_fmt_i] == fpnew_pkg::MERGED && dst_fmt_i < dst_fmt_i.num());
 
     fpnew_opgroup_multifmt_slice #(
       .OpGroup       ( OpGroup          ),
diff --git a/src/fpnew_pkg.sv b/src/fpnew_pkg.sv
index 47366dc3..7b545654 100644
--- a/src/fpnew_pkg.sv
+++ b/src/fpnew_pkg.sv
@@ -99,7 +99,7 @@ package fpnew_pkg;
       INT64: return 64;
       default: begin
         // pragma translate_off
-        $fatal(1, "Invalid INT format supplied");
+        $error(1, "Invalid INT format supplied");
         // pragma translate_on
         // just return any integer to avoid any latches
         // hopefully this error is caught by simulation