1、前言
上一章大体上已经完成了顶层模块的转换,若后期编译有语法上或者其他报错再继续进行修改和注释。 继续上一章的转换,咱们进入到工程的第一个模块。
2、进入转换
端口定义和赋值按照之前的步骤直接转换,这里就不在做过多的赘述,直接上图
端口定义:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
library UNISIM;
use UNISIM.VComponents.all;
entity CLK_RST_CTRL is
port (
OSC_CLK : in std_logic;
FPGA_RST : in std_logic;
SYS_CLK : out std_logic;
module rst_ctrl(
input osc_clk ,
input fpga_rst ,
output sys_clk ,
赋值
signal s_osc_clk : std_logic;
signal s_osc_rst : std_logic;
signal s_dcm_rst : std_logic;
reg s_osc_clk ;
reg s_osc_rst ;
reg s_dcm_rst ;
接下来又遇到例化模块,不同之前的,这里多出另一个语法generic和vhdl的进制转换,这里就先介绍vhdl转verilog的进制转化,后面在讲generic的转换。
U_SRL16_0 : SRL16E
generic map (
init => x"0000"
)
port map (
D => FPGA_RST ,
CLK => s_osc_clk ,
Q => s_osc_rst ,
CE => '1' ,
A3 => '1' ,
A2 => '1' ,
A1 => '1' ,
A0 => '1'
);
这里用到了移位寄存器,就给大家普及一下Xilinx 的SRL16E ,它本质就是一个移位寄存器,顾名思义就是一个16位的移位寄存器。它这个移位寄存器可以是固定的、静态的长度,移位寄存器的长度可以从 1位到 16位不等,由下面公式决定:
长度 =(8 x A3)+(4 x A2)+(2 x A1)+A0+1
如果 A3,A2,A1,A0都是 0(0000),移位寄存器的长度就是 1位长;如果它们 都是 1(1111),移位寄存器的长度就是 16位长。这里就简单介绍,想要了解更多用法可以自行搜索。
回到主题,开始对vhdl的进制数转换为veriong的进制数,在转换之前也得先了解vhdl的数位字符串
数位字符串(位矢量):代表的是二进制,8进制,16进制的数组,长度为等值的二进制数位数。
B:二进制, O:八进制, X:十六进制,
例如:
B’1_1110_1111 表示二进制数数组,位矢数组长度是9
X’27 表示十六进制数数组,位矢数组长度是8
O’AD0 表示八进制数数组,位矢数组长度是6
结合verilog的用法上述几个字符串可以这样换:
B’1_1110_1111 verilog表示为 9'b1_1110_1111
X’27 verilog表示为 8'h27
O’AD0 verilog表示为 6'OAD0
上述vhdl例化模块用verilog表示为下面代码
srl16e #(.init(16'h0000)
) u_srl16_0(
.d (fpga_rst ),
.clk (s_osc_clk ),
.q (s_osc_rst ),
.ce (1'b1 ),
.a3 (1'b1 ),
.a2 (1'b1 ),
.a1 (1'b1 ),
.a0 (1'b1 )
);
generic map
接下来就用到了vhdl中generic map和 port map 用法,二者都是vhdl中例化元件。前者是类属参数传递,也就是类属名称的例化,后者也就是一般的元件端口例化。而generic map的用法用verilog里面的参数parameter声明常量。所以直接用
U_DCM_SP : DCM_SP
generic map (
CLKDV_DIVIDE => 8.0 ,
CLKFX_DIVIDE => 5 ,
CLKFX_MULTIPLY => 4 ,
CLKIN_DIVIDE_BY_2 => FALSE ,
CLKIN_PERIOD => 20.0 ,
CLKOUT_PHASE_SHIFT => "NONE" ,
CLK_FEEDBACK => "1X" ,
DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS" ,
DFS_FREQUENCY_MODE => "LOW" ,
DLL_FREQUENCY_MODE => "LOW" ,
DSS_MODE => "NONE" ,
DUTY_CYCLE_CORRECTION => TRUE ,
FACTORY_JF => X"c080" ,
PHASE_SHIFT => 0 ,
STARTUP_WAIT => FALSE
)
port map (
CLK0 => s_dcm1_clk0 ,
CLK180 => open ,
CLK270 => open ,
CLK2X => s_dcm1_clk2x ,
CLK2X180 => open ,
CLK90 => open ,
CLKDV => s_dcm1_clkdv ,
CLKFX => open ,
CLKFX180 => open ,
LOCKED => s_dcm1_locked ,
PSDONE => open ,
STATUS => open ,
CLKFB => s_dcm1_clk0_bufg ,
CLKIN => s_osc_clk ,
DSSEN => '0' ,
PSCLK => '0' ,
PSEN => '0' ,
PSINCDEC => '0' ,
RST => s_dcm_rst
);
dcm_sp #( //
.CLKDV_DIVIDE (8.0 ),
.CLKFX_DIVIDE (5 ),
.CLKFX_MULTIPLY (4 ),
.CLKIN_DIVIDE_BY_2 (FALSE ),
.CLKIN_PERIOD (20.0 ),
.CLKOUT_PHASE_SHIFT (NONE ),
.CLK_FEEDBACK (1X ),
.DESKEW_ADJUST (SYSTEM_SYNCHRONOUS ),
.DFS_FREQUENCY_MODE (LOW ),
.DLL_FREQUENCY_MODE (LOW ),
.DSS_MODE (NONE ),
.DUTY_CYCLE_CORRECTION (TRUE ),
.FACTORY_JF (16'hc080 ),
.PHASE_SHIFT (0 ),
.STARTUP_WAIT (FALSE )
) u_dcm_sp(
.CLK0 (s_dcm1_clk0 ),
.CLK180 (open ),
.CLK270 (open ),
.CLK2X (s_dcm1_clk2x ),
.CLK2X180 (open ),
.CLK90 (open ),
.CLKDV (s_dcm1_clkdv ),
.CLKFX (open ),
.CLKFX180 (open ),
.LOCKED (s_dcm1_locked ),
.PSDONE (open ),
.STATUS (open ),
.CLKFB (s_dcm1_clk0_bufg ),
.CLKIN (s_osc_clk ),
.DSSEN (0 ),
.PSCLK (0 ),
.PSEN (0 ),
.PSINCDEC (0 ),
.RST (s_dcm_rst )
);
这里引用到了数字时钟管理器(DCM),感兴趣的可以了解了解,这里不过多叙述。
assign
在vhdl例化模块后面或者其他地方会出现下面这样单独的几句赋值语句
SYS_RST <= not s_sys_locked ;
SYS_CLK <= s_dcm1_clk2x_bufg;
CAMMERA_PCLK <= s_dcm1_clk0_bufg ;
CMOS_XCLK <= s_dcm1_clkdv_bufg;
这个用法及等同于verilog里面的assign赋值,直接转换
assign sys_rst = ~s_sys_locked ;
assign sys_clk = s_dcm1_clk2x_bufg ;
assign camera_pclk = s_dcm1_clk0_bufg ;
assign cmos_xclk = s_dcm1_clkdv_bufg ;
是不是一目了然,除此之外,里面也少不了运算符的应用,接下来就讲解一下几个简单的运算符转换。
运算符
1,vhdl是没有&&、||、!这几个逻辑运算符,而verilog是有的;
2,vhdl是采用and、or、not、nor、xor进行位运算的,而verilog中则是采用与C/C++采用相同的:&、|、~、^、^~.
3,vhdl的关系运算符中等于和不等于分别是:= 、 /=,verilog中是:==、!=。
4,vhdl的连接运算符是&,用来连接不同的位/矢量,而verilog中使用的是{ , , ,}的方式。
所以上面遇到的例子可以这样转换
SYS_RST <= not s_sys_locked ;
assign sys_rst = ~s_sys_locked ;
常量constant与parameter
前面有说到过在vhdl例化模块中generic map类属名称例化等同于verilog中常量赋值parameter,现在就来说说vhdl中的常量赋值constant,谈及到vhdl中的赋值constant,固然少不了另外两种赋值signal、variable。
Signal即是“信号”的意思,它具有特定的物理意义,一般对应电路中特定的物理连线或存储单元。Signal是VHDL语法中最重要、最常用的一种可赋值对象。当程序中需要用到signal时,我们一般需要在VHDL基本程序框架中的architecture语法的声明与定义部分先声明一个signal,然后才能在architecture的语句部分使用它。 Signal的声明语法如下:
signal <signal_name> : := ; – 有初值
或
signal <signal_name> : ; – 无初值
Variable即是“变量”的意思,它不具有特定的物理意义,对应关系也不太直接,通常只代表暂存某些值的载体。** 在之前介绍的VHDL基本程序框架中,可以看到variable出现在process语句中,作为process的局部变量来使用。** 当程序中要用到variable时,只需要在process语法的敏感量列表与begin关键字之间先声明一个variable,然后就能在process的语句体中使用它。Variable的声明语法如下:
variable : := ; – 有初值
或
variable : ; – 无初值
Constant即是“常量”的意思,它具有特定的物理意义,通常对应数字电路中的电源或者地。Constant能出现在所有signal和variable出现的场合中,它的声明语法如下:
constant : := ;
可以注意到,常量是不能单独赋值的,仅仅能在声明的同时被初始化赋值。
vhdl中常量赋值Constant对应verilog中的常量赋值parameter,所以遇到直接转换
constant c_cam_pix_cnt : std_logic_vector(15 downto 0) := x"04ff";
constant c_cam_line_cnt : std_logic_vector(15 downto 0) := x"03FF";
parameter [15:0] c_cam_pix_cn = 16'h04ff;
parameter [15:0] c_cam_line_cnt = 16'h03ff;
怎么样?改过来是不是简单明了多了?今天就先到这里,同样有什么问题或者你也像我一样很不幸也需要翻译的话,遇到问题也可以在评论区交流探讨一下,后续再翻译的结果会继续跟上的。