`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