一、前言
几个星期没有更新了,最近一直忙,现在能抽点时间继续补充了。其次我就是想吐槽一下这个csdn自带的文章编辑,已经习惯了撤销是ctrl+z,谁知道这里是从头到尾都撤销了,相当于删除了所有,已经两次了,想要恢复已经来不及了。心态直接炸了,没办法,再重新写吧,害!
二,进入转换
1,多个三目运算用法的转换
VHDL中单个三目运算还是能看来出来的,但是多个在一起的用法可能对于新手来说不是很友好,所以在这里遇到了就顺便提及一下,直接上代码
A <= '0' when (B = '0') else '1' when (B = '1') else '0';
其实理解了它想表达的意思,转换过来就不是很难,大体可以这样理解:当B = '0' 时,A <= '0' ;当B = '1' 时,A <= '1';else A <= '0',(反正我是这样理解的,有错误或者有异议的可以在评论区指点一下)转换后如下
assign A = ((B == 1'b0)) ? 1'b0 : ((B == 1'b1)) ? 1'b1 : 1'b0;
注意点就是转换过来时是assign赋值语句。
当然,为其他值的情况也一样,如下
A <= C when (B = '0') else D when (B = '1') else C;
assign A = ((B == 1'b0)) ? C: ((B == 1'b1)) ? D : C;
2,process和always
process相当于verilog中的always语句,直接转换就行,要注意的是上下沿的变化。
process (clk,rst_n) begin
if (rst_n='1') then
data <= '0';
elsif (clk'Event and clk='1') then
if (data_d1 = '0' and data_d2 = '1') then
data <= '1';
else
data <= '0';
end if;
end if;
end process;
上面这里process后面括号里面都为上升沿所以转换过来就是always@(posedge clk or posedge rst_n), 之后的(clk'Event and clk='1') then的意思可以理解为clk'event是指信号clk是否发生跳变,若发生了则返回ture,否则为假,clk=‘1’是跳变后clk为高电平。合起来就是当clk信号的上升沿则.... 都说VHDL严谨,从这里就可以看得出,但转换成verilog后这句基本是省略掉的,if条件语句变化不大,这里就不做过多的赘述,所以转换后的如下
always @(posedge clk or posedge rst_n)begin
if (rst_n== 1'b1)
data <= 1'b0;
else begin
if (data_d1 == 1'b0 && data_d2 == 1'b1)
data <= 1'b1;
else
data <= 1'b0;
end
end
转换过来后就比较清晰明了了,VHDL注重严谨,所以看起来就很繁琐,verilog只要逻辑语法正确,很好掌握的,对初学者也很友好。
3、case语句
在always语句也有经常会遇到多路条件分支的形式,一般用的就是case语句
process (sclk,rst_n) begin
if (rst_n='1') then
data1 <= (others => '0');
data2 <= (others => '0');
data3 <= (others => '0');
elsif (clk'event and clk='1') then
case (sel) is
when "00" =>
data1 <= channel0;
data2 <= channel0;
data3 <= channel0;
when "01" =>
data1 <= channel1;
data2 <= channel1;
data3 <= channel1;
when "10" =>
data1 <= channel2;
data2 <= channel2;
data3 <= channel2;
when "11" =>
data1 <= channel3;
data2 <= channel3;
data3 <= channel3;
when others =>
data1 <= (others => '0');
data2 <= (others => '0');
data3 <= (others => '0');
end case;
这里data1 <= (others => '0');它的意思是将data1的所有位都设为‘0’,前面也有提及到,这里就再补充一下另外一种写法,倘若data1定义为8位的数据,则转换成verilog后为:data1 <= {8{1'b0}};当然也可以用之前说过的写法,看个人喜好来理解。最终整个语句转换后如下
always @(posedge clk or posedge rst_n)
if (rst_n== 1'b1)
begin
data1 <= {8{1'b0}};
data2 <= {8{1'b0}};
data3 <= {8{1'b0}};
end
else
case (sel)
2'b00 :
begin
data1 <= channel0;
data2 <= channel0;
data3 <= channel0;
end
2'b01 :
begin
data1 <= channel1;
data2 <= channel1;
data3 <= channel1;
end
2'b10 :
begin
data1 <= channel2;
data2 <= channel2;
data3 <= channel2;
end
2'b11 :
begin
data1 <= channel3;
data2 <= channel3;
data3 <= channel3;
end
default :
begin
data1 <= {8{1'b0}};
data2 <= {8{1'b0}};
data3 <= {8{1'b0}};
end
endcase
另一种常见的用法
process (clk,rst_n) begin
if (rst_n='1') then
data <= (others => '0'); //16位的数据
elsif (clk'Event and clk='1') then
case sel (3 downto 0) is
when x"0" => data <= x"0" & channel0;
when x"1" => data <= x"0" & channel1;
when x"2" => data <= x"0" & channel2;
when x"3" => data <= x"0" & channel3;
when x"4" => data <= x"0" & channel4;
when x"5" => data <= x"0" & channel5;
when others => data <= (others => '0');
end case;
end if;
end process;
转换后
always @(posedge clk or posedge rst_n)
if (rst_n == 1'b1)
data <= {16{1'b0}};
else
case (sel[3:0])
4'h0 :
data <= {4'h0, channel0};
4'h1 :
data <= {4'h0, channel1};
4'h2 :
data <= {4'h0, channel2};
4'h3 :
data <= {4'h0, channel3};
4'h4 :
data <= {4'h0, channel4};
4'h5 :
data <= {4'h0, channel5};
default :
data <= {16{1'b0}};
endcase
4、VHDL数据类型(Data Types)
VHDL中共有4类类型:标量类型、复合类型、访问类型、文件类型。你可以基于上述类型的基础上自定义自己的类型,或者使用subtype关键字来约束已存在的类型。感兴趣的可以去了解一下,这里用到的是标量类型中的枚举类型。
枚举类型:枚举类型是一组具有明确值的集合。枚举中的值是一个命名项或者一个字符。 语法(Syntax)
type 枚举名 is ( 枚举元素, 枚举元素, ... );
type new_name is ( type_element, type_element, ... );
这里用来作为状态机的定义,很简单的用法
type FSM is (
IDLE ,
WRITE_1 ,
READ_1 ,
WRITE_2 ,
READ_2 ,
READ_WAIT
);
转换后就是这样
parameter [2:0] FSM_IDLE = 3'd0,
FSM_WRITE_1 = 3'd1,
FSM_READ_1 = 3'd2,
FSM_WRITE_2 = 3'd3,
FSM_READ_2 = 3'd4,
FSM_READ_WAIT = 3'd5;
这章就到这里吧,目前遇到的几个常用的语法也就这么多了,这只是字面上的转换,具体还得读懂代码会用代码,那样的话遇到或者用到就比较方便了,最后还是那句话,有错误或者异议的欢迎各位大佬在评论区留言探讨。