一般情况下,DC把case语句综合成选择器电路,但也可能把case语句综合成优先权译码电路。有时,优先权译码电路是不必要的,这是可以使用“// synopsys parallel_case”引导语句强迫DC把case语句综合成选择器电路。这种引导格式在case状态声明没有完全列举时应用较多。
Example
always @(cs_state)
begin
case(cs_state) // synopsys parallel_case
2’b00: next_state = 2’b01;
2’b01: next_state = 2’b00;
2’b10: next_state = 2’b10;
default: next_state = 2’b00;
endcase
end
在case语句中,如果列举的条件不完全,DC将生成不必要的锁存单元。在状态机描述中,可能没有一些状态,此时如果不加声明,DC将认为条件没有完全列举。在这种情况下,设计者可以使用full_case引导语句。
Example 3.2
always @(cs_state)
begin
case(cs_state) // synopsys full_case
2’b00: next_state = 2’b01;
2’b01: next_state = 2’b00;
2’b10: next_state = 2’b10;
endcase
end
(一)“//synthesisparallel_case”
在Quartus中的实验表明, 当分支项包含变量X的所有取值情况,并且互相不重复时,case语句的各个分支选项的优先级是一样的,并且这时对case使用综合指令“//synthesis parallel_case”也不会起作用。
若某两个分支选项相互重叠,这时,case所暗含的优先级顺序就起作用了,在前面的分支项优先级高,并用在编译时Quartus会出现这样的警告:
Warning (10935): Verilog HDL Casex/Casezwarning at ddd.v(380): casex/casez item expression overlaps with a previouscasex/casez item expression
提醒你说分支项重叠了。
在这种情况下,若不使用“//synthesis parallel_case”指令,则重叠的分支项,将会按照“前面的分支项优先级高”的原则被综合。
若使用“//synthesis parallel_case”指令,则我们可以划分几个子集:A1(属于X1,但不属于其它),A2(属于X2,但不属于其它),依此类推,对子集A1,严格按照X1:下的语句执行,对子集A2,严格按照X2:下的语句执行,依此类推。对于其它不能划到任何子集的情况,即重叠部分,则被视为不可能出现的情况,或者说的不关心的情况,对于这种情况,怎么综合有利于简化电路就怎么综合。
所以“//synthesisparallel_case”在这里对于简化电路就很有用了,只要设计者确定重叠的情况不会出现,就可以利用这条指令来简化电路。这时Quartus会给出警告:
Warning (10935): Verilog HDL Casex/Casezwarning at Verilog1.v(15): casex/casez item expression overlaps with a previouscasex/casez item expression
Warning (10935): Verilog HDL Casex/Casezwarning at Verilog1.v(16): casex/casez item expression overlaps with a previouscasex/casez item expression
Warning (10209): Verilog HDL CaseStatement warning at Verilog1.v(13): honored parallel_case synthesis attribute- differences between design synthesis
and simulation may occur
(二)“//synthesisfull_case”
在以上的组合逻辑电路中,如果分支项没有包含所有的情况,则会综合成触发器,那么你可以用default来避免这种情况,对于不关心的情况,随便赋一个值就好了,但是这种随意的赋值付出的代价就是逻辑资源。若用
“//synthesisfull_case”则,综合器会自动对没列出的情况赋值,并且它赋的值有利于减少逻辑资源的消耗。至于原因嘛,我觉得可以用化简卡诺图的例子来说明,对于我们不关心的情况,就给它一个X好了,在化简的时候它既可以作为0,又可以作为1.显然比你给它一个0或者1要好点。这就是我们为什么要用“//synthesis full_case”的原因。
full_case举例~
Example 1 shows a case statement, with case default, for a 3-to-1 multiplexer. The case default
causes the case statement to be "full." During Verilog simulation, when binary pattern 2'b11 is
driven onto the select lines, the y-output will be driven to an unknown, but the synthesis will treat
the y-output as a "don't care" for the same select-line combination, causing a mismatch to occur
between simulation and synthesis. To insure that the pre-synthesis and post-synthesis simulations
match, the case default could assign the y-output to either a predetermined constant value, or to
one of the other multiplexer input values.
Example 2 shows a case statement for a 3-to-1 multiplexer that is not "full." The case statement
does not define what happens to the y-output when binary pattern 2'b11 is driven onto the select
lines. In this example, the Verilog simulation will hold the last assigned y-output value and
synthesis will infer a latch on the y-output as shown in the latch inference report of Figure 7.
When "// synopsys full_case" is added to a case statement header, there is no change in the
Verilog simulation for the case statement, since "// synopsys ..." is interpreted to be nothing more
than a Verilog comment; however, Synopsys parses all Verilog comments that start with "//
synopsys ..." and interprets the "full_case" directive to mean that if a case statement is not "full"
that the outputs are "don't care's" for all unspecified case items. If the case statement includes a
case default, the "full_case" directive will be ignored.
Example 3 shows a case statement for a 3-to-1 multiplexer that is not "full" but the case header
includes a "full_case" directive. During Verilog simulation, when binary pattern 2'b11 is driven
onto the select lines, the y-output will behave as if it were latched, the same as in Example 2, but
the synthesis will treat the y-output as a "don't care" for the same select-line combination,
causing a functional mismatch to occur between simulation and synthesis.
parallel_case举例~
A "parallel" case statement is a case statement in which it is only possible to match a case
expression to one and only one case item. If it is possible to find a case expression that would
match more than one case item, the matching case items are called "overlapping" case items and
the case statement is not "parallel."
总结
1. Coding priority encoders
Non-parallel case statements infer priority encoders. It is a poor coding practice to code priority
encoders using case statements. It is better to code priority encoders using if-else-if statements.
Guideline: Code all intentional priority encoders using if-else-if statements. It is easier for a
typical design engineer to recognize a priority encoder when it is coded as an if-else-if statement.
Guideline:Case statements can be used to create tabular coded parallel logic. Coding with case
statements is recommended when a truth-table-like structure makes the Verilog code more
concise and readable.
Guideline:Examine all synthesis tool case-statement reports.
Guideline:Change the case statement code, as outlined in the above coding guidelines, whenever
the synthesis tool reports that the case statement is not parallel (whenever the synthesis tool
reports "no" for "parallel_case") .
Although good priority encoders can be inferred from case statements, following the above
coding guidelines will help to prevent mistakes and mismatches between pre-synthesis and postsynthesis
simulations.
2. Synthesis coding styles
Sunburst Design Assumption: it is generally a bad coding practice to give the synthesis tool
different information about the functionality of a design than is given to the simulator.
Whenever either "full_case" or "parallel_case" directives are added to the Verilog source code,
more information is potentially being given about the design to the synthesis tool than is being
given to the simulator.
Guideline:In general, do not use "full_case parallel_case" directives with any Verilog case
statements.
Guideline: There are exceptions to the above guideline but you better know what you're doing if
you plan to add "full_case parallel_case" directives to your Verilog code.
Guideline:Educate (or fire) any employee or consultant that routinely adds "full_case
parallel_case" to all case statements in their Verilog code, especially if the project involves the
design of medical diagnostic equipment, medical implants, or detonation logic for thermonuclear
devices!
Guideline:only use full_case parallel_case to optimize onehot FSM designs.
Other exceptions might exist and will be acknowledged by the author as they are discovered.
3. Latch example using "full_case"
Myth:"// synopsys full_case" removes all latches that would otherwise be inferred from a case
statement.
Truth:The "full_case" directive only removes latches from a case statement for missing case
items. One of the most common ways to infer a latch is to make assignments to multiple outputs
from a single case statement but neglect to assign all outputs for each case item. Even adding the
"full_case" directive to this type of case statement will not eliminate latches.
Example 8 shows Verilog code for a simple address decoder that will infer a latch for the mce0_n
mce1_n and rce_n outputs, despite the fact that the "full_case" directive was used with the case
statement. In this example, the case statement is "full" but not all outputs are assigned for each
case item; therefore, latches were inferred for all three outputs. The easiest way to eliminate
latches is to make initial default value assignments to all outputs immediately beneath the
sensitivity list, before executing the case statement, as shown in Example 9.
Conclusion: "full_case" and "parallel_case" directives are most dangerous when they work! It is
better to code a full and parallel case statement than it is to use directives to make up for poor
coding practices.