文章目录
- 使用function名称作为“常量”
- numeric_std包集中使用乘法的注意项
- variable的使用
- 对于entity设置属性的方法
- 在entity声明中嵌入function的定义
- VHDL仿真
- 读写文件
- File declaration/File handing
- File reading
- File writing
- 小例子
- 使用函数
- 模块中打印出调试信息
使用function名称作为“常量”
测试代码如下,function仅有名称,没有输入,在function内部使用全局constant进行参数处理,后续代码中可以直接使用function名称作为常量
numeric_std包集中使用乘法的注意项
近日看到一个VHDL Coding Style中提示说,使用numeric_std包集时,不要直接将unsigned/signed数据与natural/integer类型的数据相乘。
今天看了一下numeric_std的源码发现,如果直接直接将无符号数/有符号数与整数相乘的话,乘积很有可能会溢出。主要原因是由于,包集在实现整数与符号数相乘的时候,是先将整数转成了无符号数/有符号数,之后再进行的乘法运算,而整数转换后的位宽是与输入的符号数的位宽相一致的,这就可能导致在整数进行类型转换的过程中,出现数据溢出的情况。
这其实算不上bug,因为源码中对此进行了明确说明,主要是在使用的时候需要注意规避这一点,不要让符号数与整数直接相乘,可以手动进行位宽转换后再做运算。相应的源码如下图所示,
variable的使用
在网上流传的介绍VHDL Coding Style的文章中,一般是不建议在可综合的代码中使用变量的,这大概是由于variable具有局部作用域、赋值立即生效、仿真工具支持的不够等几个原因。但最近看到几段VHDL代码,大量使用variable,且使用方式非常规范。在一个prcoess中进行组合逻辑的设计,在另一个prcoess中使用寄存器进行时序逻辑的设计。在使用变量的process中,一般是如下的处理流程,
- Latch the current value
- 各类组合逻辑
- Combinatorial outputs before the reset
- Reset
- Register the variable for next clock cycle
- Registered Outputs
comb : process (localMac, r, rst, rxMaster, txSlave) isvariable v : RegType;variable i : natural;
begin-- Latch the current valuev := r;-- Reset the flagsv.rxSlave := AXI_STREAM_SLAVE_INIT_C;if txSlave.tReady = '1' thenv.txMaster.tValid := '0';v.txMaster.tLast := '0';v.txMaster.tUser := (others => '0');v.txMaster.tKeep := (others => '1');end if;-- State Machinecase r.state is-- end case;-- Combinatorial outputs before the resetrxSlave <= v.rxSlave;-- Resetif (rst = '1') thenv := REG_INIT_C;end if;-- Register the variable for next clock cyclerin <= v;-- Registered Outputs txMaster <= r.txMaster;end process comb;seq : process (clk) is
beginif rising_edge(clk) thenr <= rin after TPD_G;end if;
end process seq;
free_range_vhdl.pdf
11.4 Signals vs. Variables
对于entity设置属性的方法
类似的,对于verilog的module设置attribute的方法如下,
在entity声明中嵌入function的定义
VHDL仿真
有时写vhdl时,使用了record、array等数据类型,此时使用verilog进行仿真时略有不便,用vhdl仿真倒是方便不少。
读写文件
File declaration/File handing
File reading
File writing
小例子
使用函数
library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;entity test is
end test;architecture Behavioral of test is-- convert a hex string to a std_logic_vectorfunction hex_string_to_std_logic_vector(inp: string; width : integer)return std_logic_vector isconstant strlen : integer := inp'LENGTH;variable result : std_logic_vector(width-1 downto 0);variable bitval : std_logic_vector((strlen*4)-1 downto 0);variable posn : integer;variable ch : character;variable vec : string(1 to strlen);beginvec := inp;-- default value is zeroresult := (others => '0');posn := (strlen*4)-1;for i in 1 to strlen loopch := vec(i);case ch iswhen '0' => bitval(posn downto posn-3) := "0000";when '1' => bitval(posn downto posn-3) := "0001";when '2' => bitval(posn downto posn-3) := "0010";when '3' => bitval(posn downto posn-3) := "0011";when '4' => bitval(posn downto posn-3) := "0100";when '5' => bitval(posn downto posn-3) := "0101";when '6' => bitval(posn downto posn-3) := "0110";when '7' => bitval(posn downto posn-3) := "0111";when '8' => bitval(posn downto posn-3) := "1000";when '9' => bitval(posn downto posn-3) := "1001";when 'A' | 'a' => bitval(posn downto posn-3) := "1010";when 'B' | 'b' => bitval(posn downto posn-3) := "1011";when 'C' | 'c' => bitval(posn downto posn-3) := "1100";when 'D' | 'd' => bitval(posn downto posn-3) := "1101";when 'E' | 'e' => bitval(posn downto posn-3) := "1110";when 'F' | 'f' => bitval(posn downto posn-3) := "1111";when others => bitval(posn downto posn-3) := "XXXX";-- synthesis translate_offASSERT falseREPORT "Invalid hex value" SEVERITY ERROR;-- synthesis translate_onend case;posn := posn - 4;end loop;if (width <= strlen*4) then-- bitval larger than desired widthresult := bitval(width-1 downto 0);else-- bitval smaller than desired width-- MSB is padded with zeros since default value for result is all 0sresult((strlen*4)-1 downto 0) := bitval;end if;return result;end;-- convert a binary string into a std_logic_vector (e.g., 0b10.1 = 101)function bin_string_to_std_logic_vector (inp : string)return std_logic_vectorisvariable pos : integer;variable vec : string(1 to inp'length);variable result : std_logic_vector(inp'length-1 downto 0);beginvec := inp;pos := inp'length-1;-- Set default valueresult := (others => '0');for i in 1 to vec'length loop-- synthesis translate_offif (pos < 0) and (vec(i) = '0' or vec(i) = '1' or vec(i) = 'X' or vec(i) = 'U') thenassert falsereport "Input string is larger than output std_logic_vector. Truncating output.";return result;end if;-- synthesis translate_onif vec(i) = '0' thenresult(pos) := '0';pos := pos - 1;end if;if vec(i) = '1' thenresult(pos) := '1';pos := pos - 1;end if;-- synthesis translate_offif (vec(i) = 'X' or vec(i) = 'U') thenresult(pos) := 'U';pos := pos - 1;end if;-- synthesis translate_onend loop;return result;end;signal data_1 : std_logic_vector(5 downto 0);signal data_2 : std_logic_vector(7 downto 0);begindata_1 <= bin_string_to_std_logic_vector("101001");data_2 <= hex_string_to_std_logic_vector("45",8);end Behavioral;
模块中打印出调试信息
VHDL的仿真不如verilog方便,因此一般我都是用verilog对整个模块做仿真。但有的时候,想在某个可综合的VHDL模块内部嵌入仿真调试信息,这样在仿真时可以更直观的观测到运行结果。这在verilog中可以直接使用display和monitor函数,在VHDL中则需要借用report函数或者自己编写函数实现。
library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;
library work;
-- use work.stdio_h.all;entity counter is
generic(SIM_VERBOSE : natural := 1
);
port ( clk : in std_logic;cnt : out std_logic_vector(15 downto 0)
);
end counter;architecture Behavioral of counter issignal cnt_i : unsigned(15 downto 0) := (others=>'0');begincnt <= std_logic_vector(cnt_i);process(clk)beginif rising_edge(clk) thencnt_i <= cnt_i + 1;-- if(SIM_VERBOSE=1) then
-- if(cnt_i = 20) then
-- printf("The time is %d ns\n",now);
-- printf("The cnt_i value is %u\n",std_logic_vector(cnt_i));
-- printf("-------------------------\n");
-- end if;
-- end if;end if;end process;-- synthesis translate_offgen_sim_info : if SIM_VERBOSE=1 generatebeginprocess(cnt_i)use work.stdio_h.all;beginif(cnt_i = 20) thenprintf("The time is %d ns\n",now);printf("The cnt_i value is %u\n",std_logic_vector(cnt_i)); printf("-------------------------------------------------------\n");printf("The cnt_i value is %s,the cnt_i part value is %u \n",std_logic_vector(cnt_i),std_logic_vector(cnt_i(3 downto 0)));printf("-------------------------------------------------------\n");end if;end process;end generate;-- synthesis translate_onend Behavioral;
Modelsim运行结果如下所示,