我们在写程序的时候,有没有考虑过编译器其实并不足够智能?那么程序语句能给编译器指明最简捷的道路尤为重要。下面以Quartus II v13.1为平台,举两个小例子说明。 例1:设计一个32位计数器,在计数器为全1时输出一个脉冲,输出不用组合逻辑实现。那么,这么个简单的功能,可以用4中写法列举如下: clock : instd_logic; q :out std_logic; signal cn :std_vector(0 to 31); Process(clock) begin if rising_edge(clock)then cn <= cn+ 1; 1 q <= STDZ(signed(cn)=-2); 2 q <= STDZ(signed(cn)=3-5); 3 q <= STDZ(signed(cn)+5 = 3); 4 q <= STDZ(cn = 2**cn'length-2); end if; End process; 最后综合的结果是,前两种消耗资源相同,速率也较高,第3种资源消耗大速率也低,第4种没有实现我们想要的功能,完全被综合掉了。当信号cn的比特长度小于32时,第4种写法与前2种是完全相同的,2**32超出了VHDL所能表示的整数范围被解释为0,用定义为std_vector型的cn与一个负数比较则永远不相等,所以被综合掉了。第3种写法不同于其他写法的原因是综合器(或者说编译器,就那么回事)并没有智能到会在等式两边移项的程度,况且在有些时候移项也是不合理的,在此,我们称之为移项问题。但综合器知道合并常数,即第1和第2写法完全相同。本例中只涉及一个变量cn,如果有两个或多个变量,那么移项问题依然存在。 例1告诉我们,注意不同类型数据的取值范围,移项问题完全由程序员自己决定。 例2:有一个8位计数器cnt,在不同数值下输出一个3位状态q,功能描述如下 q : outstd_vector(0 to 2); signal cnt : std_vector(0 to7); Process(clock) begin if rising_edge(clock)then cnt <=cnt+1; if cnt = 0then q<= "000"; elsif cnt =1 then q<= "001"; elsif cnt <= 8 then q<= "010"; elsif cnt =10 then q<= "011"; elsif cnt =20 then q<= "100"; elsif cnt>= 23 and cnt <= 32 then q<= "101"; else q<= "110"; end if; end if; End process; 在功能保持不变的情况下,也可以写成: Process(clock) begin if rising_edge(clock)then cnt <=cnt+1; caseSTDV_INT(cnt) is when 0 => q <="000"; when 1 => q <="001"; when 2 to 8 =>q <= "010"; when 10 => q <="011"; when 20 => q <="100"; when 23 to 32 =>q <= "101"; when others => q <= "110"; end case; end if; End process; 或者写成 with STDV_INT(cnt) select iq <= "000" when 0, "001" when 1, "010" when 2 to 8, "011" when 10, "100" when 20, "101" when 23 to 32, "110" when others; Process(clock) begin if rising_edge(clock)then cnt <=cnt+1; q <= iq; end if; End process; 综合后,后两种写法结果相同,但与第一种写法不同。例2告诉我们,代码的表述方式能用开关选择的逻辑就不用优先编码的逻辑。 一句话:编译器很听话,但不会懂你。 |