`define SIX_MUX

// Case Statement Synthesis Directives  (Leonardo Spectrum v1999.1f)
//
// Purpose:
//   Tell synthesis program which case expression values are impossible.
//   With this information unnecessary hardware omitted.
//
// Directives:
//   parallel_case: At most one case item is true.
//   full_case:     At least one case item is true.
//
// full_case
//   At least one case item is true.
//   With this directive synthesis program will omit latches under
//   certain circumstances.
//
// parallel_case
//   At most one case item is true.
//   Simplifies case logic.
//
// Automatic Detection of Case Item Possibilities
//   Leonardo can automatically detect when full_case and parallel_case
//     apply to case statements.
//   Its detection capabilities are limited though:
//     In some cases it cannot detect parallel and full case even though
//      there is enough information in the case statement to do so.
//     In other cases information not present in the module (and
//      unavailable to the synthesizer) is needed to prove that cases
//      are parallel or full.




`ifdef SIX_MUX
module six_mux(x,sel,a,b,c,d,e,f);

   input sel, a, b, c, d, e, f;
   output x;

   wire [2:0] sel; // Values limited to 0-5.
   reg        x;
   wire       a, b, c, d, e, f;

   // Because the case items are constants and the case
   // expression is an integer, Leonardo can automatically
   // detect the parallel case.  Leonardo has no way of knowing
   // that sel cannot take on values of 6 or 7, so it cannot
   // detect the full_case.  That is specified explicitly. Without
   // it latches would be inserted to hold the value of x updated
   // that last time sel was less than 6.

   always @( sel or a or b or c or d or e or f )
     // exemplar full_case
     case( sel )
       0: x = a;
       1: x = b;
       2: x = c;
       3: x = d;
       4: x = e;
       5: x = f;
     endcase 

endmodule // six_mux
`endif 

`ifdef MUX2
module mux2(x,sel,a,b,c,d);

   input sel, a, b, c, d;
   output x;

   wire [2:0] sel;
   reg        x;
   wire       a, b, c, d;

   // A complete analysis of the cases below would show that the
   // cases are full and parallel (if the case items are appropriately
   // modified, as in mux3).  Leonardo 1999.1f, however, cannot detect
   // this and so synthesizes logic that sequentially checks the case
   // items and uses latches in case none are true.

   // With a parallel_case directive incorrect hardware will be synthesized
   // since Leonardo will check the case items as given here, not as
   // specified in mux3, which would be correct.
   
   always @( sel or a or b or c or d )
     casez( sel )
       3'b??1: x = a;  // Odd case
       3'b000: x = b;  // Zero
       3'b1??: x = c;  // Even, nonzero, >= 4
       3'b0??: x = d;  // Even, nonzero, < 4;
     endcase

endmodule // case1
`endif // ifdef mux2

`ifdef MUX3
module mux3(x,sel,a,b,c,d);

   input sel, a, b, c, d;
   output x;

   wire [2:0] sel;
   reg        x;
   wire       a, b, c, d;

   // Here Leonardo can detect that the case items are parallel
   // and full and so will automatically detect the parallel and full
   // cases.

   always @( sel or a or b or c or d )
     casez( sel )
       3'b??1: x = a;  // Odd case
       3'b000: x = b;  // Zero
       3'b1?0: x = c;  // Even, nonzero, >= 4
       3'b010: x = d;  // Even, nonzero, < 4;
     endcase 

endmodule 
`endif 

`ifdef RANGE
module range(x1,x2,x3,v1,v2,v3);
   input v1, v2, v3;
   output x1, x2, x3;

   reg    x1, x2, x3;
   wire [3:0] v1, v2, v3;

   // This module will be connected such that exactly one of the
   // inputs (v1,v2,v3) will be equal to 12.  Because of this exactly
   // one of the case items below will be true.  Leonardo has no way
   // of knowing this property of the inputs so parallel and full case
   // must be specified in the directives.

   always @( v1 or v2 or v3 )
     // exemplar parallel_case
     // exemplar full_case
     case( 12 )
       v1 : begin x1 = 1; x2 = 0; x3 = 0; end
       v2 : begin x1 = 0; x2 = 1; x3 = 0; end
       v3 : begin x1 = 0; x2 = 0; x3 = 1; end
     endcase 

endmodule // range
`endif // ifdef RANGE

`ifdef RANGEIF
module rangeif(x1,x2,x3,v1,v2,v3);
   input v1, v2, v3;
   output x1, x2, x3;

   reg    x1, x2, x3;
   wire [3:0] v1, v2, v3;

   // The code below is functionally equivalent to the code above, but
   // it uses if .. else if.. instead of a case statement.  There is
   // no way to tell Leonardo that the cases are full.  There is no
   // way to tell Leonardo that the cases are parallel either, but if
   // they are the "else"s can be removed. (The elses below could be
   // removed.)  Leonardo can automatically detect full case in if statements
   // under certain circumstances, but not in the code below.

   // Synthesis directives full_case and parallel_case are ignored for if's.
   always @( v1 or v2 or v3 )
     if( v1 == 12 )
       begin x1 = 1; x2 = 0; x3 = 0; end
     else if( v2 == 12 )
       begin x1 = 0; x2 = 1; x3 = 0; end
     else if( v3 == 12 )
       begin x1 = 0; x2 = 0; x3 = 1; end

endmodule 
`endif 



`ifdef SIX_MUX_IF_ELSE
module six_mux_if_else(x,sel,a,b,c,d,e,f);

   input sel, a, b, c, d, e, f;
   output x;

   wire [2:0] sel; // Values limited to 0-5.
   reg        x;
   wire       a, b, c, d, e, f;

   // The code above is equivalent to mux6 above.  Leonardo is able to
   // detect that the if conditions are parallel and so it does not,
   // for example, check that sel != 0 when assigning x = b for sel ==
   // 1.
   //
   // Leonardo cannot detect that the cases are full and so it will
   // synthesize a latch. (That could be worked around by adding a
   // last else condition and assigning some dummy value to x.)
   //
   // Leonardo cannot infer that a multiplexor with a binary input
   // would be appropriate. (It is able to do this for the case
   // statement.)  This is not a problem because the optimization
   // steps, performed "between" the RTL and technology schematics,
   // replace the explicit comparators with much simpler logic.

   always @( sel or a or b or c or d or e or f )
     begin
        if( sel === 0 ) x = a; else
        if( sel === 1 ) x = b; else
        if( sel === 2 ) x = c; else
        if( sel === 3 ) x = d; else
        if( sel === 4 ) x = e; else
        if( sel === 5 ) x = f;
     end
   
endmodule // six_mux_if_else
`endif 

`ifdef SIX_MUX_IF
module six_mux_if(x,sel,a,b,c,d,e,f);

   input sel, a, b, c, d, e, f;
   output x;

   wire [2:0] sel; // Values limited to 0-5.
   reg        x;
   wire       a, b, c, d, e, f;

   // The code above is functionally equivalent to the code above.  By
   // removing the else's we are making explicit that the conditions
   // are parallel, but Leonardo already knew that.  (Simulation is
   // slightly less efficient here since every condition must always
   // be tested.)  As with the code above, a latch will be synthesized,
   // which is a problem.
   
   always @( sel or a or b or c or d or e or f )
     begin
        if( sel === 0 ) x = a;
        if( sel === 1 ) x = b;
        if( sel === 2 ) x = c;
        if( sel === 3 ) x = d;
        if( sel === 4 ) x = e;
        if( sel === 5 ) x = f;
     end
   
endmodule // six_mux_if
`endif 

`ifdef SIX_MUX_IF_ELSE_FULL
module six_mux_if_else_full(x,sel,a,b,c,d,e,f);

   input sel, a, b, c, d, e, f;
   output x;

   wire [2:0] sel; // Values limited to 0-5.
   reg        x;
   wire       a, b, c, d, e, f;

   // In the code below a dummy assignment is added after the
   // last else.  With this dummy assignment the synthesis program
   // will not synthesize a latch and so the synthesize module
   // will be correct, although with extra logic.

   always @( sel or a or b or c or d or e or f )
     begin
        if( sel === 0 ) x = a; else
        if( sel === 1 ) x = b; else
        if( sel === 2 ) x = c; else
        if( sel === 3 ) x = d; else
        if( sel === 4 ) x = e; else
        if( sel === 5 ) x = f; else
          x = a;  // Dummy case, added to synthesis program omits latch.
     end
   
endmodule // six_mux_if_else_full
`endif 

`ifdef FOUR_MUX_IF_ELSE
module four_mux_if_else(x,sel,a,b,c,d);

   input sel, a, b, c, d;
   output x;

   wire [1:0] sel; 
   reg        x;
   wire       a, b, c, d;

   // Though the synthesis program is documented as doing "full
   // coverage analysis" for if-then-else statements (synthesis
   // manual, page 6-28) it cannot detect that x will always be
   // assigned (full case) in the code below and so it will synthesize
   // a latch.  The workaround is to add a dummy assignment.
   
   always @( sel or a or b or c or d )
     if( sel === 0 ) x = a; else
       if( sel === 1 ) x = b; else
         if( sel === 2 ) x = c; else
           if( sel === 3 ) x = d; 
   
endmodule 
`endif