为您推荐:
精华内容
最热下载
问答
  • 5星
    838KB qq_43729828 2021-08-09 15:56:48
  • 5星
    13.66MB pudn01 2021-08-11 12:19:46
  • 5星
    12KB u014627020 2020-11-24 18:16:41
  • 5星
    10KB u014627020 2020-11-24 18:12:58
  • VHDL中,串行语句的顺序执行只是一种帮助开发者、编译器、仿真器等理解代码、描述功能的一个辅助“思路”,而代码真正对应的硬件结构肯定是并行的!

    前言

    所谓的串行语句,不过是形式上的串行,映射为硬件电路时仍然为并行的。

    VHDL的串行语句

    串行语句的执行方式是顺序执行的,一般高级编程语言中的语句执行方式都是顺序执行的,例如C语言,由此可见,顺序执行的语句更容易帮助我们来抽象和表达我们的设计思想,尤其是这样能够使时序逻辑的描述变得容易。所以,虽然FPGA的设计思路都是并行的,architecture中也仅支持并行语句的调用,但是为了方便设计者表达自己的思想,尤其是表达时序逻辑的思路,VHDL中的一些并行语句中的子语句体允许是顺序执行的,例如process。
    除此以外,由于我们的代码是需要运行在PC机上的编译器来“读懂”并“翻译”成为数字电路的,而PC机上的运行的程序都是顺序执行的,所以,VHDL也必须支持串行的思路,否则编译器也无法工作。还有,仿真VHDL代码的工作也是在PC机上来执行的,所以VHDL本身也必须支持顺序的执行思路来达到仿真的目的。但是请注意,在VHDL中,串行语句的顺序执行只是一种帮助开发者、编译器、仿真器等理解代码、描述功能的一个辅助“思路”,而代码真正对应的硬件结构肯定是并行的!
    到底VHDL里面有哪些串行语句可以供我们使用呢?以process为例描述如下:
    process(<sensitive_list>)
    begin
    <VHDL直接信号赋值语句>;
    <VHDL变量赋值语句>;
    <VHDL条件语句>;
    <VHDL空语句>;
    <VHDL循环语句>;
    <VHDL等待语句>;
    <VHDL过程调用语句>;
    end process;

    VHDL直接信号赋值语句

    直接信号赋值语句,也知道它是可以直接写在architecture中的并行语句,不过直接信号赋值语句具有双重身份,那就是它还可以当做串行语句来使用,例如:
    process(a, b)
    begin
    c <= a and b; – 直接信号赋值语句
    end process;

    VHDL变量赋值语句

    变量的特性就是赋值立即生效,由此也决定了它的执行结果必然跟语句的先后顺序有关,因此,变量赋值语句肯定是串行语句的一种。而变量的声明语句也是不能出现在architecture下的,而只能出现process、function、procedure等语句体的内部,所以变量的赋值语句也必然只能出现在这些语句体的内部。例如:

    process(a, b)
    	variable c : std_logic;
    begin
    	c := a and b; -- 变量赋值语句
    	d <= c;
    end process;
    

    VHDL条件语句

    条件语句是一种典型的串行语句。VHDL中共有两种条件语句——if-else和case-when,它们的根本区别是if-else中的各个条件分支是具有优先级的,且分支优先级按照书写顺序从高至低,而case-when语句是没有优先级的。关于它们的具体语法介绍如下:

    优先级条件语句

    优先级条件语句即if-else语句,它的完全语法如下:

    if <expression1> then
    		<statements>
    elsif <expression2> then
    		<statements>
    <other elsif branchs>
    else
    		<statements>
    end if;
    

    其中的 elsif和else分支都不是必须的,可以根据具体情况来确定。举例如下:
    – 求A、B、C三者中的最大值

    if (A >= B and A >= C) then
    	max <= A;
    elsif (B >= C) then
    	max <= B;
    else
    	max <= C;
    end if;
    

    注意,上例中,if、then(elsif、then)之间的条件判断表达式可以省略最外层的括号。
    为什么说if-else语句是具有优先级的条件语句呢?需要从两个方面来说:

    • 第一,从语句的功能描述来分析。如果要描述上述求最大值的例子,我们可以这样翻译代码:首先,判断数A是不是大于等于B和C,如果成立,则最大值是A,结束判断;否则说明A不是最大值,那么这时候只需判断数B是不是大于等于C,如果成立,则最大值是B,判断结束;否则,由于之前已经得出A、B两数都不是最大值,那么最大值只能是C了。由此可见,每一个分支的判断都是建立在写在它之前的所有分支的基础上的。
    • 第二,从硬件实现上来说。上述求最大值的例子,对应到门级电路上,肯定是从A到max之间的路径最短,即所经过的逻辑门最少,而从B到max之间的路径次之,从C到max之间的路径最长。关于门级实现可以参考如下示意图:
      在这里插入图片描述
      由此可见,基于优先级条件语句的特点,如果我们知道A、B、C三个数中最大值的概率是B大于C大于A,那么我们应该把对B的判断放在第一个分支,然后C放在第二个分支,而A放在最后一个分支。这样,今后的仿真效率会更高,且对于具体的FPGA实现,也能保证最短路径得到最充分的利用,这样芯片即使工作在比较恶劣的环境下,也能保证故障率达到最低。

    无优先级条件语句

    无优先级条件语句即是case-when语句,它的完全语法如下:

    case (<expression>) is
    	when <constant_value1> =>
    		<statements>;
    	when <constant_value2> =>
    		<statements>;	
    	<other branchs>	
    	when others =>
    		<statements>;	
    end case;
    

    其中,的值必须互相不同,这和选择式信号赋值语句的要求是一样的。举例如下:
    – 四选一多路选择器

    case (sel) is -- sel is type of std_logic_vector(1 downto 0) 
          when "00" =>
             data <= channel0;
          when "01" =>
             data <= channel1;
          when "10" =>
             data <= channel2;
          when "11" =>
             data <= channel3;
          when others =>
             data <= channel0;
    end case;
    

    注意,上例中,case后的判断表达式也可以省略括号。
    上述例子中的分支已经覆盖完全,但是还是有一个when others分支,这虽然有些画蛇添足,但确是一个编程的好习惯,请大家注意!
    为什么说case-when语句是无优先级的条件语句呢?也需要从两方面来说:

    • 第一,从语句的功能描述来分析。如果要描述上述多路选择器的例子,我们可以这样翻译代码:如果sel等于”00”,那么选择第一路输出;如果sel等于”01”,那么选择第二路输出;如果sel等于”10”,那么选择第三路输出;如果sel等于”11”那么选择第四路输出。可见这四个分支的判断之间没有任何相互关系,也互不为前提。
    • 第二,从硬件实现上来说。上述多路复用器的例子,对应到门级电路上,无论是channel0~3中的任何一个,到data的路径都是等长的。关于门级实现可以参考如下示意图:
      在这里插入图片描述
      由此可见,在使用无优先级条件语句时,分支的顺序是无关的,不会影响电路的最终实现。

    优先级条件语句与无优先级条件语句的对比

    为了进一步说明if-else与case-when的不同,我们将之前用if-else编写的求最大值的例子用case-when重写如下:

    x <=1’ when A >= B else0;
    y <=1’ when A >= C else0; 
    z <=1’ when B >= C else0;
    
    judge <= x & y & z;
    case (judge) is 
          when "000" =>
             max <= C;
          when "001" =>
             max <= B;
          when "010" =>
             max <= A; -- unreachable
          when "011" =>
             max <= B;
          when "100" =>
             max <= C;
          when "101" =>
             max <= A; -- unreachable
          when "110" =>
             max <= A;
          when "111" =>
             max <= A;
          when others =>
             <statement>;
    end case;
    

    关于其门级实现可参考如下电路图:
    在这里插入图片描述
    可见,此时,A、B、C到max的路径都是完全相等的。当然,由于上图并不是最简形式,所以此处我们没必要深究它与【优先级条件语句】小节中的例子到底孰优孰劣,但是请注意,由于目前的编译器都会对我们的代码有一定优化或修改作用,因此有时候if和case也可能会被综合成为一样的电路结构。

    从上例可以看出,case结构中有很多分支输出结果完全一样,还有一些分支本身就不可达,例如,不可能A大于等于B,B大于等于C,然后A却小于C的。那么其实我们有时候为了书写方便,可以对case语句做一些变形。

    case-when的一些变形

    首先,利用特殊的“或”符号——“|”来简化代码,例如, 上述最大值无优先级条件语句可以变形为:

    case (judge) is 
          when "110" | "111" =>
             max <= A;
          when "001" | "011"=>
             max <= B;
          when "000" | "100" =>
    max <= C;
          when others =>
    max <= A;
    end case;
    

    其次,对于整数类型的表达式,还可以使用to关键字,例如:

    case (number) is -- number is type integer
          when 0 to 100=>
             data <= A;
          when 101 to 200 =>
             data <= B;
          when others =>
    data <= C;
    end case;
    

    第三,对于非整数类型的表达式,例如常用的std_logic_vector,可以通过类型转换函数先转成整数类型,然后再利用to关键字简化代码。
    第四,切忌不可以利用std_logic的不关心态“-”来简化状态,例如,如果想当然的将上述最大值无优先级条件语句变形为:
    – this is not right!

    case (judge) is 
          when "11-" =>
             max <= A;
          when "0-1" =>
             max <= B;
          when "-00" =>
    max <= C;
          when others =>
    max <= A;
    end case;
    

    虽然编译器不会报错,但是它的行为肯定是不对的,代码会始终停留在others分支。其原因是编译器对VHDL的不关心态“-”的理解跟我们预想的不一样。例如:
    if (a = ‘-’) then
    我们可能以为任何情况都能匹配,其实不然,目前为止的编译器还是把它理解为
    if (FALSE) then
    即,该条分支永远不可达。所以建议大家在平时的代码设计中尽量不要使用不关心态,如果非要使用,请参考下一点。
    第五,不关心态在case中的应用。从第四点我们可以知道不关心态不能用于状态的简化,但是它的一个正确用法也是和case-when相关的,请看下面这个地址译码的例子:

    case (address) is 
          when "00" =>
             d <= "0001";
          when "01" =>
             d <= "0010";
          when "10" =>
             d <= "0100";
          when "11" =>
             d <= "1000";
          when others =>
             d <= "0000";
    end case;
    

    上例中,为了避免引入锁存,必须添加others分支,可是如果将others分支改为
    d <= “----”;
    那么会带来一定程度的逻辑电路简化。究其原因,是因为在本例的情况下,others分支本身就是我们不关心的分支,所以在此分支里面d到底等于多少都不影响程序的正常功能。可是如果强行给d赋一个确定的值"0000",那么编译器就会为不能匹配的address分支强行把d变为"0000"。可是也许此时让d等于"0010"更能简化我们的逻辑电路。所以,一个偷懒的方法就是给d赋值"----",告诉编译器我们不关心这个值,然后让编译器自己去优化这个分支的数字电路。所以,我们之前在讲逻辑数据类型时说过,不关心态“-”指的是我们不关心,而不是编译器不关心。

    VHDL空语句

    空语句本身不做任何的处理,仅仅是将程序的执行引导到下一个串行语句而已,它的语法如下:
    null;
    老实说,空语句其实没有什么作用,最多就是个占位符号而已。有些人习惯在条件语句的无处理动作分支中加入null语句,以达到列举完全所有分支的目的。不过这仅仅是你编写代码时列举出来了而已,只有null语句的分支对于编译器来说跟没有是一样的,所以如果用于组合逻辑还是会产生锁存器。

    VHDL循环语句

    VHDL中有两种循环语句,即for-loop语句和while-loop语句,语法分别为
    for in <lower_limit> to <upper_limit> loop
    ;
    end loop;

    while loop
    ;
    end loop;
    关于循环语句,使用的时候有以下几点建议:
    1、循环语句主要是起到简化代码书写和增加代码可读性的作用,此时,循环语句中控制循环次数的变量不会跟元件中的任何输入、输出端口或者信号量或者变量进行运算或比较,所以无论其它信号怎么变化都不会影响循环实现的功能,例如:
    for i in 0 to 15 loop
    a(i) <= b(15 - i);
    end loop;

    i <= 0;
    while (i <= 15) loop
    a(i) <= b(15 - i);
    i <= i + 1;
    end loop;
    这样就省得我们写上16行代码,或者用一条长长的映射或连接赋值语句了,并且日后程序需求有变动时,修改起来也很容易。
    2、循环语句的循环次数必须是有限的,因为循环语句是串行的,它必须依附于进程、过程或者函数语句,而进程本身就是一个不断循环的语句体,那么如果一个循环内部套了一个无限循环,那么显然,从代码上面我们就无法解释我们描述的到底是一个什么东西,并且从硬件上也得不到有意义的解。
    3、循环语句通常不应该作为功能语句使用,因为所有的循环功能都可以通过进程的循环特性来描述和表示。而循环语句作为功能描述时的抽象层级过高,很难确定编译器到底会怎么理解。例如,可以接受的例子如下:
    for i in 0 to 15 loop – 其实可以用一个针对t的case-when结构来实现
    if(i < conv_integer(t))then – t is an input signal
    c(i) <= b(15 - i);
    else
    c(i) <= b(i);
    end if;
    end loop;
    而有问题的例子如下:
    process(sel,b,c)
    begin
    while sel = ‘1’ loop
    if(c = b)then
    a <= b;
    else
    a <= c;
    end if;
    end loop;
    end process;
    首先,这段代码无法仿真,因为,一旦sel为’1’,那么循环将会一直运行,所以进程无法执行到末尾,从而也就无法响应sel、b、c的变化,从而即使外部的信号值已经改变,可是内部的代码仍然无法得到这个变化,因此代码将会无休止的在一个时刻点上被仿真器不停的调用同一个分支,从而产生死循环。
    其次,这段代码的初衷可能是要完成这样的工作:
    process(sel,b,c)
    begin
    if sel = ‘1’ then
    if(c = b)then
    a <= b;
    else
    a <= c;
    end if;
    end if;
    end process;
    只不过忘记了process的循环特性,才写成的while。
    最后,建议大家主要还是用循环语句来做一些简化代码方面的工作,至于功能上的事情,完全可以交给process的循环机制来完成。

    VHDL等待语句

    VHDL中有四种等待语句,分别介绍如下:

    wait;
    

    表示永远挂起,用于仿真;

    wait on <sensitive signal list>; 
    

    –信号发生变化将结束挂起,置于进程最下方代替进程开始的敏感量表,例如:

    process
    begin
    	a <= b and c;
    	wait on b, c;        -- b, c任一信号发生变化时,进程重新开始
    end process;
    
    wait until <condition>; 
    

    条件表达式中的信号发生变化且满足条件时结束挂起,它可以用来描述触发、锁存等时序相关逻辑,例如:

    process
    begin
    	wait until clk = '1';
    	a <= b;
    	wait until clk = '0';
    end process;
    

    它等效于

    Process(clk)
    Begin
    	If(clk'event and clk = '1')then
    a <= b;
    		end if;
    end process;
    

    不过通常情况下,还是建议大家使用第二种方式来描述时序逻辑,而对wait until语句仅作了解即可。

    wait for <time expressions>;
    

    超时等待语句,它主要用于仿真,等待够时间表达式中的时间后结束挂起。

    VHDL过程调用语句

    过程——procedure,也是VHDL子程序的一种过程的调用是一种串行的调用,它不可以直接出现在architecture的语句部分当中,一般需要依附于process等内部支持顺序执行的语句,例如:

    	-- procedure min() is predefined  
    	process(a,b)
    	begin
    min(a, b, c); -- a,b is input and c is the output
    end process;
    
    展开全文
    Reborn_Lee 2020-02-13 01:17:47
  • 上次我们了解了VHDL语言的并行语句,现在我们来学习VHDL的顺序语句。 顺序语句与并行语句共同构成了VHDL的描述语言,是VHDL作为硬件描述语句的一个特点。顺序语句只在仿真时间上是相对并行语句而言的,实际硬件的...

    上次我们了解了VHDL语言的并行语句,现在我们来学习VHDL的顺序语句。
    顺序语句与并行语句共同构成了VHDL的描述语言,是VHDL作为硬件描述语句的一个特点。顺序语句只在仿真时间上是相对并行语句而言的,实际硬件的运行不一定是顺序执行的。
    VHDL语言支持的并行语句主要有以下几种:

    • 赋值语句
    • wait语句
    • after语句
    • if语句
    • case语句
    • null语句
    • loop语句
    • exit语句
    • next语句
    • assertion/report语句
    • return语句

    顺序语句在VHDL程序中的位置
    顺序语句只出现在进程、过程和函数中,举例如下:

    --在进程中出现的位置
    process(敏感信号列表)
    --声明部分
    begin
    		顺序语句1;
    		顺序语句2;
    		...
    		顺序语句n;
    end process;
    --在过程中出现的位置
    procedure 过程名(参数列表)is
    --声明部分
    begin
    		顺序语句1;
    		顺序语句2;
    		...
    		顺序语句n;
    end process;
    --在函数中的位置
    function 函数名(参数列表)return 返回值类型 is
    --声明部分
    begin
    		顺序语句1;
    		顺序语句2;
    		...
    		顺序语句n;
    		return 返回值
    end 函数名;
    

    顺序语句的并行执行
    顺序语句是VHDL描述语言重要组成部分,但是不能从字面意义上面理解为顺序语句在硬件上就是一条一条地顺序执行,应该从硬件的角度理解顺序语句只是一种描述方式,不要在意顺序性。

    一、顺序赋值语句

    顺序赋值语句出现在进程、过程和函数中的赋值语句。由于进程、过程和函数中可以出现变量处理,所以顺序赋值语句不仅可以给信号赋值,还可以给变量赋值,它们的赋值格式如下:
    信号<=表达式;
    变量名:<=表达式;

    信号与变量在赋值更新上有区别,信号赋值更新至少有delta延时,而变量的赋值更新是立即执行的。

    二、wait语句

    wait语句的功能是把一个进程挂起,直到满足等待的条件成立才开始该进程的执行。wait语句一般有以下3种基本形式:

    • wait on(敏感信号列表)
    • wait until(判断条件表达式)
    • wait for(时间)

    1、wait on语句
    wait on(敏感信号列表)用于挂起进程,直到敏感信号列表中的信号发生变化时再次启动进程。使用格式如下:
    *

    process
    begin
    		顺序语句1;
    		顺序语句2;
    		...
    		顺序语句n;
    		wait on(敏感信号列表);
    end process;*
    

    2、wait until语句
    wait until(判断条件表达式)功能是当判断条件式信号发生变化且判断条件表达式的值为真时,wait until(判断条件表达式)所在的进程或过程将重新执行,直到wait until(判断条件表达式)所在的进程或是过程将被挂起。wait until(判断条件表达式)的基本格式如下:

    *process
    begin
    		顺序语句1;
    		顺序语句2;
    		...
    		顺序语句n;
    		wait until 判断条件表达式;
    end process;*
    

    3、wait for语句
    wait for时间t语句功能是把进程挂起时间t,之后再启动进程。wait for语句一般用VHDL测试文件,综合工具一般不支持。格式如下:

    *process
    begin
    		顺序语句1;
    		顺序语句2;
    		...
    		顺序语句n;
    		wait for 时间t;
    end process;*
    

    三、after语句

    after语句是信号赋值延时语句,一般只在仿真或仿真测试时使用,基本格式如下:
    信号<=表达式 after 时间;
    举例如下:
    data<=da or db after 10ns;//功能是da与db取或后延时10ns赋给data。

    四、if语句

    if语句是顺序语句中最常用的语句之一,功能是通过对分支条件的判断来决定执行哪个分支的顺序语句。一般有以下3种形式:

    • 单分支if语句
    • 两分支if语句
    • 多分支if语句

    1、单分支if语句
    如果if的判断条件为真,则执行下面的相关语句;否则,不做任何操作。格式如下:

    if 条件判断表达式 then
    			顺序语句;
    end if;
    

    2、两分支if语句
    如果if的判断条件为真,则执行分支1的相关语句;否则执行分支2的相关语句。所以,两分支if语句可以看成一个二选一选择器。基本格式如下:

    if 条件判断表达式 then
    			顺序语句1;
    else
    			顺序语句2;
    end if;
    

    两分支if语句不会产生锁存器。

    3、多分支if语句
    如果第一个条件判断为真,则执行分支1语句;否则,如果判断第二个条件判断为真,则执行分支2的语句。以此类推,如果所有条件为假,如果有else分支,则执行else分支的语句;如果没有,则不做任何操作。基本格式如下:

    --有else分支
    if 条件判断表达式1 then
    			顺序语句1;
    elseif 条件判断表达式2 then
    			顺序语句2;
    ...
    elseif 条件判断表达式n then
    			顺序语句n;
    else
    			顺序语句n+1;
    end if;
    --或是没有else 分支
    if 条件判断表达式1 then
    		顺序语句1;
    elseif 条件判断表达式2 then
    			顺序语句2;
    ...
    elseif 条件判断表达式n then
    			顺序语句n;
    end if	
    

    五、case语句

    功能是通过对分支条件得到判断来决定执行哪个分支的顺序语句。一般形式如下:

    case 判断表达式 is
    when 选择项 1=>
    		顺序语句1;
    when 选择项 2=>
    		顺序语句2;
    ...
    when 选择项 n=>
    		顺序语句n+1;
    when others=>
    		顺序语句n+1;
    		end case;
    

    当执行case语句时,首先要计算表达式的值,如果表达式的值与选择项1相等,则执行顺序语句1;否则,如果表达式的值与选择项2相等,则执行顺序语句;依次比较,如果所有选择项都与判断表达式的值不相等,则执行others分支下的顺序语句n+1。选择项可以是一个值,也可以是多个值“|”相连,也可以是用to约束的一个范围,但选择项不能有重复。
    有关case选择项有以下几点说明:

    1. 选择项取值必须在判断表达式的取值范围内
    2. 各个选择项不能有重复
    3. 如果选择项不能列举完判断表达式的所有情况,最后必须加others选择项

    六、null语句

    null语句语法意义在于不做任何操作,也没对应的综合结果。只是显示说明在某些情况下不做任何操作,在一定程序上能提高VHDL程序的可读性,一般格式如下:
    null;

    七、loop语句

    loop语句功能是循环执行一条或多条顺序语句,主要有3种基本形式:

    • for循环形式
    • while循环形式
    • 条件跳出形式

    1、for/loop语句
    一般格式如下:

    for 循环变量 in 循环变量的范围 loop
    		顺序语句;
    end loop;
    

    2、while/loop语句
    while循环形式一般格式如下:

    标号:while 循环的条件 loop
    		顺序语句;
    end loop 标号;
    

    while循环形式的loop语句在循环条件为假时跳出循环。

    八、exit语句

    exit语句格式有3种:
    1、exit //第一种
    2、exit loop 标号 //第二种
    3、exit loop 标号 when条件表达式 //第三种

    条件跳出形式一般格式如下:

    标号:loop
    				顺序语句;
    				exit when 跳出循环条件;
    end loop 标号;
    

    九、next语句

    主要用在loop语句执行中进行有条件的或无条件的转向控制,基本格式有以下三种:

    1. next (当loop内的顺序语句执行到next语句时,则无条件终止当前的循环并跳回到本次循环loop语句处开始下一次循环)
    2. next loop 标号 (在next旁边加loop标号后的语句功能与未加loop标号的功能相同,只是有多重loop语句嵌套时,前者可跳转到指定标号的loop语句处重新开始执行循环操作)
    3. next loop 标号 when条件表达式(分句“when条件表达式”是执行语句的条件,如果条件表达式的值为true,则执行next语句进入跳转操作;否则,继续向下执行)

    10、return 语句

    只能在函数中使用,用于返回函数的返回值,基本格式如下:

    return 表达式;
    

    表达式就是函数的返回值;

    展开全文
    qhs414 2021-05-30 15:23:18
  • 进程语句begin进程语句包含在结构体中,一个结构体可以有多个进程语句,多个进程语句间是并行的,并可访问结构体或实体中定义的信号。因此进程语句称为并行描述语句。进行语句结构内部所有语句都是顺序执行的进程...

    VHDL的并行语句用来描述一组并发行为,它是并发执行的,与程序的书写顺序无关。

    进程语句

    begin
    进程语句包含在结构体中,一个结构体可以有多个进程语句,多个进程语句间是并行的,并可访问结构体或实体中定义的信号。因此进程语句称为并行描述语句。

    进行语句结构内部所有语句都是顺序执行的
    进程语句的启动是由process后敏感信号表中所标明的敏感信号触发来的。
    各进程间的通信是由信号来传递的
    语法如下:
    标记:

    process(敏感信号表)
                              变量说明语句;
    begin 
                               一组顺序语句;
    end process 标记;

    标记:为进程标号
    敏感信号表:是进程用来读取所有敏感信号(包括端口)的列表。
    变量说明:主要包括变量的数据类型说明、子程序说明等
    从begin到end process之间是一组顺序执行语句。

    敏感信号表
    所 谓敏感信号表:就是用来存放敏感信号的列表。在进程语句中,敏感信号指那些发生改变后能引起进程语句执行的信号。敏感信号表中可以使用一个或多个信号,当 其中一个或多个信号值改变时,就在进程内部引起语句执行。敏感信号表也可忽略,但程序中必须有其他形式的敏感信号激励。例如wait、wait for、wait until和wait on。

    进程语句的启动
    在VHDL语言中,进程有两种工作状态:等待和执行。当敏感信号表中的信号没有变化时,进程处于等待状态;当敏感信号表中的信号有变化时,进程处于执行状态
    进程语句的同步
    同一个结构体中不仅可以有多个进程存在,同一个结构体中的多个进程还可以同步。VHDL中通常采用时钟信号来同步进程,具体方法是:结构体中的几个进程共用同一个时钟信号来进行激励。

    并发信号赋值语句
    信号赋值语句在进程内部出现时,它是一种顺序描述语句。

    信号赋值语句在结构体的进程之外出现时,它将以一种并发语句的形式出现。它们在结构体中是并行执行的。

    注意:并发信号赋值语句是靠事件来驱动的,因此对于并发信号赋值语句来说,只有当赋值符号“<=”右边的对象有事件发生时才会执行该语句。

    条件信号赋值语句
    语法结构:
    目标信号<=表达式1 when 条件1 else
                         表达式2 when 条件2 else
                         表达式3 when 条件3 else
                          ...
                         表达式n-1 when 条件n-1 else
                         表达式n;
     
    VHDL 语言程序执行到该语句时,首先要进行条件判断,之后才进行信号赋值。如果满足条件,就将该条件前面那个表达式的值赋给目标信号;如果不满足条件按,就继续 判断,直到最后一个表达式,如果前面的条件均不满足就无条件的赋值给最后一个表达式,因为最后一个表达式赋值无需条件。

    选择信号赋值语句
    语法结构:
    with 表达式 select
              目标信号<=表达式1 when 选择条件1,
                                   表达式2 when 选择条件2,
                                    ...
                                    表达式n when 选择条件n;
     
    该语句在赋值之前需要对条件进行判断,附和条件则赋值,否则继续判断,直到最后一个语句。选择赋值语句需要把表达式的值在条件中都列举出来。

    元件例化语句
    在VHDL中,引用元件或者模块的说明采用component语句,他的作用是在结构体说明部分说明引用的元件或者模块,是元件说明语句。
    语法格式:
    component 引用的元件名
                     generic 参数说明;
                     port 端口说明;
    end componet;
    引用的元件名 :

    是将一个设计现成的实体定义为一个元件,是已经设计好的实体名,用来制定要在结构体中使用的元件名称
    如果结构体中要进行参数的传递,那么component语句中需要类属参数说明--可选项;
    引用元件端口的说明,是已经设计好的实体端口名表;
    元件说明语句在architecture和begin之间。

    元件例化引用
    采用componet语句对要引用的原件进行说明后,为了引用的元件正确地嵌入到高一层的结构体描述中,就必须把被引用的元件端口信号于结构体中相应端口信号正确地连接起来,这就是元件例化语句要实现的功能。
    语法结构:
    标号名:元件名
                    generic map(参数映射)
                    prot map(端口映射);
     
    其中标号:是元件例化语句的惟一标识,结构体中的标号名应该是惟一的
    generic map语句:它的功能是实现对参数的赋值操作,从而可以灵活地改变引用元件的参数,为可选项
    prot map:它的功能是把引用元件的端口信号与实际连接的信号对应起来,从而进行元件的引用操作。
    VHDL中,为了实现引用元件的端口信号与结构体中的实际信号相连接,往往采用两种映射方法:
    1、位置映射方法:指port map语句中实际信号的书写顺序于componet语句中端口说明的信号书写语句顺序一致
    2、名称映射方法:指在port map中将引用的元件的端口信号名称赋值给结构体中要使用例化元件的各个信号
    (名称映射语句的书写要求不是十分严格,只要把映射的对应信号连接起来就可以,顺序可以颠倒)。

    生成语句 
    规则结构
    某些电路部分是由同类元件组成的阵列,这些同类元件叫规则结构,例如:随机RAM、只读ROM、移位寄存器等规则结构一般用生成语句来描述。
    生成语句有两种形式:for_generate和if_generate
    for_generate主要用来描述规则
    if_generate主要用来描述结构在其端部表现出的不规则性,例如边界条件的特殊性
    for_generate语句
    标号:for 循环变量 in 离散范围 generate
                      并行处理语句;
                end generate 标号;
     
    标号:用来作为for_generate语句的唯一标识符,可选项;
    循环变量:它的值在每次循环中都将发生变化;
    离散范围:用来指定循环变量的取值范围,循环变量的取值将从取值范围最左边的值开始并且递增到取值范围的最右边,实际上限定了循环次数
    for_generate与for_loop语句很类似,但二者有区别。for_loop语句的循环体中的处理语句是顺序的,而for_generate语句中处理的语句是并行处理的,具有并发性。

    if_generate语句
    标号:if 条件 generate
                并行处理语句;
    end generate 标号;
    if_generate语句是并行处理语句,其中不允许出现else子语句

     

     

    初学VHDL,对一些问题总是感到困惑。比如,同样的赋值语句,在什么场合是并行的,什么时候又是顺序的?信号与变量有什么区别,为什么在PROCESS 里,对信号赋值的结果要等到进程挂起才起作用,而变量赋值却立刻起作用?其实,从语句产生的电路这个角度,可以更深刻地理解这些问题,下面是我自己摸索的 一些理解方法,有不妥之处请大虾们指正!

    1、赋值语句。
        同样a <= b的赋值语句,会形成什么电路,起关键作用的是敏感信号。
        a) 如果a <= b是在进程之外,那么隐含的敏感信号就是b,那么,这个赋值语句就形成一条连线。
        b) 如果是在一个同步进程中,如if (rising_edge(CLK)) then a <= b,这时候,就会形成一个触发器,因为敏感信号是时钟边沿。
       c) 如果敏感信号是一个电平信号,那么会形成一个锁存器。如一个不完整的if条件:if (cond = '1') then a <= b;

    2、并行语句和顺序语句。
        从形成的电路的角度,并行语句最终会有两种形式:
        a) 并联或不相联的逻辑门或组合电路。因为是并联或不相联的,当然是同时执行,这个好理解。
        b) 由同一个时钟边沿驱动的D触发器,不论D触发器之间是并联、串联或者不相连的。为什么呢?因为触发器是在同一个时钟边沿同时翻转的,也就是同时执行,所以本质上就是并行。
        顺序语句只有一种情况,就是形成串联的逻辑门或组合电路。

    3、信号与变量有什么不同?为什么信号赋值要等到进程挂起生效,变量赋值却立刻生效?
        其实,了解了上一点并行语句和顺序语句所生成的电路,这个问题就好理解了。因为在同步进程里的并行语句,大多是形成b的情况,就是多个由同一时钟驱动的触 发 器。由于从触发器的输入到翻转、输出需要一定的延时,这个延时基本就是进程执行完毕的时间,所以,触发器翻转后的输出在同一个时钟边沿中是看不到的,因为 它还没翻转过来呢。这就是信号赋值要等到进程挂起才生效的原因。
        那为什么变量赋值却能立刻生效呢?这是因为,变量其实是为了帮助在同步进程中生成一些逻辑门或组合电路用的。看一看代码:var1 := not i1; var2 := var1 and i2 ; sig <= var2; 生成的RTL,就会看到,两个变量赋值语句其实生成了一个非门、一个与门。而且,输入信号i1和i2到var2这段是个组合电路,是不受时钟边沿控制的, 而到信号赋值语句sig <= var2,才形成一个D触发器。所以,这两个变量赋值语句生成了一个串联的非门和与门,那当然var2取到的是var1赋值后的值了。
        最后顺便提一下为什么变量必须只能在进程内可见,我猜可能是为了防止在同步进程中输出异步信号,造成混乱吧。因为如果变量是外部可见的,如上面的 var2,那么var2的值就可以异步输出到进程外了。所以限制变量只能进程内可见后,要输出变量的值就只能赋值给一个信号,在同步进程中,就是加了一个 触发器了。

    展开全文
    Qiuzhongweiwei 2018-03-08 10:08:49
  • VHDL的并行语句 在VHDL的基本程序框架一节中,我们了解到,architecture语句部分里面的语句都是并行的。...<VHDL进程语句>; <VHDL块语句>; <VHDL元件例化语句>; <VHDL生成语句>; <VHDL函数调用语句

    前言

    VHDL的并行语句类似于Verilog的always块,下面摘自《FPGA之道》的讲解,一起学习。

    VHDL的并行语句

    在VHDL的基本程序框架一节中,我们了解到,architecture语句部分里面的语句都是并行的。 那么到底VHDL里面有哪些并行语句可以供我们使用呢?请看如下描述:
    architecture <arch_name> of <entity_name> is
    begin
    <VHDL直接信号赋值语句>;
    <VHDL条件式信号设置语句>;
    <VHDL选择式信号设置语句>;
    <VHDL进程语句>;
    <VHDL块语句>;
    <VHDL元件例化语句>;
    <VHDL生成语句>;
    <VHDL函数调用语句>;
    end <arch_name>;
    以上这些并行语句,没有哪一类是不可或缺的,但是一个architecture中怎么着也得至少有一条,否则虽然从语法上来讲没什么问题,但是这个architecture就不具有任何功能了。一般来说,只要有元件例化、进程语句和信号赋值语句这三类语句就足够描述FPGA的功能了 ,下面详细介绍一下这些并行语句。

    VHDL直接信号赋值语句

    直接信号赋值语句语法如下:
    <signal_name> <= ;
    entity中的非输入端口以及architecture声明与定义部分中声明的signal,都可以在这个地方进行赋值。例如:

    a <= (others => '0'); -- e.g. a is a signal, type std_logic_vector(3 downto 0);
    b <= c or d; -- e.g. b, c, d are type std_logic;	
    

    VHDL条件式信号设置语句

    条件式信号设置语句语法如下:
    
    <signal_name> <= <expression 1> When <logic_expression1> Else
        			   <expression 2> When <logic_expression2> Else
    				   ……
                       <expressions n>;
    
    举例如下:
    
    equal <= '1' when data1 = data2 else 
        	    '0';
    

    VHDL选择式信号设置语句

    除了条件式信号设置语句外,还有另一种语句可以实现类似的功能,那就是选择式信号设置语句。语法如下:

    with <expression> select
    <signal_name> <= <expression 1> When <constant_value 1> ,
                       <expression 2> When <constant_value 2>,
    				   ……	
    				   <expression n> When others;
    

    举例如下:

    	signal a, b : std_logic;
    	signal c : std_logic_vector(1 downto 0);
    	signal xorOfAB : std_logic;
    	c <= a & b;
    	With c Select
    xorOfAB <= '1' when "01",
    		  '1' when "10",
    		  '0' when others;
    

    那么,条件式赋值语句和选择式赋值语句到底有什么区别和联系呢?首先,将上例用条件赋值语句改写如下:

    xorOfAB <=0’ when a = b else1;
    

    对比这两种写法,从表面上来看,选择式赋值语句的语法要求更为严格点,且constant_value的值必须互不相同,而条件式赋值语句的logic_expression却没有这种严格的要求。从本质上来看,条件式赋值语句之所以对logic_expression没有严格的要求,是因为它是有优先级的,即写在前面的logic_expression优先级高于写在后面的。
    在VHDL基本程序框架一小节,我们说过,architecture中的独立语句其实就相当于只有一条代码的纯组合逻辑process。那么如果把条件式赋值语句和选择式赋值语句都改写为进程语句来实现的话,那么,条件式赋值语句就相当于if-else语法,而选择式赋值语句就相当于case语法。

    VHDL进程语句

    进程语句是VHDL中非常重要的一种语句体,在VHDL的基本程序框架一节中,我们已经有过简单介绍。Process是一种并行语句结构,位于一个architecture下的若干个process是并发执行的,但是Process内的语句却是顺序执行的顺序语句,process的语法结构如下:

    <lable> : process (<sensitive_signals_list>)
       variable <name>: <type> := <value>;
       <other variables>...
    begin  
       <statements>;
    end process;
    

    其中,是可选的,它是进程的标号,主要起到提高代码可读性的作用。之前已经介绍过,按照<sensitive_signals_list>的形式来分,process共有三个“纯种”的基本类型:纯组合process、纯同步时序逻辑process、具有异步复位的同步时序逻辑process。 不过如果从process的结构入手,我们的可以将process的语法划分可以更细一些,即:纯组合process、纯时序process、具有同步复位的process、具有异步复位的process以及具有混合复位的process。 可见,基于结构的划分比基于<sensitive_signals_list>的划分更细致一些、面更广一些。基于结构的划分其实就是基于时钟描述结构的划分,因此,首先来介绍一下在process中表示时钟事件的方法。

    时钟事件表示方法

    'event属性
    首先要介绍一下’event属性,这个属性是VHDL进程语句中常用的描述信号事件的手段(进程语句最开始的敏感量表也是描述信号事件的手段,只不过它们所处的位置不同)。一般来说,时序逻辑主要响应两种时钟事件,即时钟的上升沿和下降沿。在process中,要表示这两种事件,我们可以采用如下代码:

    	signal clk : std_logic;
    	if (clk'event and clk = '1') then – 表示时钟上升沿
    	if (clk'event and clk = '0') then – 表示时钟下降沿
    
    rising_edge() & falling_edge()
    

    除了’event属性之外,VHDL还提供了一种方法用来描述时钟事件,参考例子如下:

    signal clk : std_logic;
    if (rising_edge(clk)) then – 表示时钟上升沿
    if (falling_edge(clk)) then – 表示时钟下降沿

    切记!在一个process中,只能出现一个时钟信号的一种边沿事件,并且针对边沿事件的if(或elsif)条件分支,后续不得再有else或elsif分支存在。 这是由寄存器的结构决定的,因为一个寄存器只有一个时钟端口,并且只敏感这个端口的某一个边沿,因此凡是不尊重这个事实的代码都是不可综合的。并且,即便该寄存器存在异步复位信号,由于异步复位信号的优先级要高于时钟信号,而if语句是具有优先级的条件语句,故异步复位所处的条件分支也只能出现在时钟事件所处的分支之前(就像【具有异步复位的process】和【具有混合复位的process】中介绍的那样)。

    下面根据时钟描述结构的不同,分别介绍五种基本process代码结构如下:

    纯组合process

    纯组合process语法如下:

    process (<sensitive_signals_list>)
    begin  
       <statements>;
    end process;
    

    参考例子如下:
    – e.g. all signals are std_logic

    process(a, b)
    begin
    	c <= a and b;
    	d <= not c;
    end process;
    

    上述例子描述了一个与非门的结构,我们可以注意信号c并不在敏感量列表里面,因为c只是一个中间信号,而不是输入信号。

    纯时序process

    纯时序process的语法如下:

    process (clk) -- only clk in the sensitive list
    begin  
       if (clk'event and clk = '1') then -- or if (clk'event and clk = '0') then
          <statements>;
       end if;
    end process;
    

    参考例子如下:
    – all signals are std_logic

    process(clk)
    begin
    	if(clk’event and clk = '1')	then	
    		a <= b;
    	end if;
    end process;
    

    具有同步复位的process

    具有同步复位的process的语法如下:

    process (clk) -- only clk in the sensitive list
    begin  
       if (clk’event and clk = '1') then -- or if (clk’event and clk = '0') then
          if (rst = '1') then -- or if (rst = '0') then
             <reset statements>;
          else
             <function statements>;
          end if;
       end if;
    end process;
    

    参考例子如下:

    -- all signals are std_logic
    process(clk)
    begin
    if(clk'event and clk = '1') then	
    if (rst = '1') then
             a <= '0';
    else
    a <= b and c;
    end if;
    end if;
    	end process;
    

    具有异步复位的process

    具有异步复位的process语法如下:

    process (clk, aRst) -- clk and asynchronous reset
    begin  
       if (aRst = '1') then -- or if (aRst = '0') then 
          <reset statements>;
       elsif (clk'event and clk = '1') then -- or elsif (clk'event and clk = '0') then
             <function statements>;
          end if;
       end if;
    end process;
    

    也可以写成如下形式:

    process (clk, aRst) -- clk and asynchronous reset
    begin  
       if (aRst = '1') then -- or if (aRst = '0') then 
          <reset statements>;
       elsif (clk'event and clk = '1') then -- or elsif (clk'event and clk = '0') then
             <function statements>;
       end if;
    end process;
    

    参考例子如下:
    – all signals are std_logic

    process(clk, aRst)
    begin
    if (aRst = '1') then
          a <= '0';
    else
    if(clk'event and clk = '1') then
    a <= b and c;
    end if;
    end if;
    	end process;
    

    具有混合复位的process

    具有混合复位的process的语法如下:

    process (clk, aRst) -- clk and asynchronous reset
    begin  
       if (aRst = '1') then -- or if (aRst = '0') then 
          <asynchronous reset statements>;
       else
          if (clk'event and clk = '1') then -- or if (clk'event and clk = '0') then
             if (rst = '1') then -- or if (rst = '0') then
                < sync reset statements>;
             else
                <function statements>;
             end if;
          end if;
       end if;
    end process;
    

    也可以写成如下形式:

    process (clk, aRst) -- clk and asynchronous reset
    begin  
       if (aRst = '1') then -- or if (aRst = '0') then 
          <reset statements>;
       elsif (clk'event and clk = '1') then -- or elsif (clk'event and clk = '0') then
          if (rst = '1') then -- or if (rst = '0') then
             < sync reset statements>;
          else
             <function statements>;
          end if;
       end if;
    end process;
    

    参考例子如下:

    -- all signals are std_logic
    process(clk, aRst)
    begin
    if (aRst = '1') then
          a <= '0';
    elsif(clk'event and clk = '1') then
       if (rst = '1') then
          a <= '1';
       else
    a <= b and c;
    end if;
    end if;
    	end process;
    

    VHDL块语句

    块语句即block语句,语法如下:
    label:BLOCK <(expression)>

    BEGIN
    ;
    END BLOCK label;
    关于block语句有几点说明:
    首先,block中的语句都是并发执行的。
    其次,关键字后紧跟的表达式逻辑是可选的,如果有表达式,那么当表达式为真时内部语句才执行;如果没有表达式,则语句一直执行。
    第三,block中可以嵌套block。
    最后,建议大家尽量不要用block语句。因为它的功能仅仅是对原有代码进行区域分割,增强整个代码的可读性和可维护性。当我们的设计真的需要分模块时,我们完全可以写多个entity,而没有必要用block;当我们需要让代码结构清晰时,我们完全可以用注释和空白,而没有必要用block。所以,建议大家对于block只做了解即可。

    VHDL元件例化语句

    元件例化语句即是instance语句。关于它的语法及相关知识已经在VHDL基本程序框架中做了比较详细的介绍.在这里,关于instance语句,我们再做两点说明:

    • 第一点,在某些情况下,例化元件时可以只对元件的部分端口进行映射赋值。道理很简单,对于那些你不需要使用的引脚,你可以不去管它(尤其是输出引脚,但输入引脚是否可以忽略不管则取决于功能),最形象的例子就是FIFO,关于空、满有非常多的信号,而我们的设计中一般只能用到其中的一部分。
    • 第二点,元件例化的时候,映射给输入端口的值也可以是常数或者非常简单的表达式,例如:
    	-- all signals are of type std_logic_vector(3 downto 0)
    m0: And3 
    	PORT MAP(
    		a => "0000",
    		b => not b, -- this is ok!
    		c => a and c, -- this is not allowed!
    		d => d
    	);
    

    使用简单的表达式进行映射,有时候能够给我们带来一些便利,不过并不提倡大家这么去做,因为这样写有些不太规范。

    VHDL生成语句

    VHDL中的生成语句可分为三种,分别是参数生成、循环生成与条件生成,我们这里所说的并行语句主要指后两种。关于这三种生成语句分别介绍如下:

    • 参数生成
      参数生成的语法是generic,主要用在entity定义和元件例化时。

    • 循环生成
      循环生成也叫for-generate语句,主要用于生成一组信号赋值或元件例化语句。它的语法如下:

    <generate_LABEL>:
    for <name> in <lower_limit> to <upper_limit> generate
    begin
    <statements>;
    end generate;
    

    关于循环生成语句的语法,有一点需要注意,那就是<generate_LABEL>必须要有,也就是说一定要为循环生成语句定义一个标签,否则会被识别为for语句,而for语句是串行语句,不能单独出现在architecture中。
    先看一个循环生成语句在信号赋值方面的例子:

    	signal a, b : std_logic_vector(99 downto 0);
    invertVector:
    for i in 0 to 99 generate
    begin
    a(i) <= b(99 - i);
    end generate;
    

    由此可见,通过使用循环生成语句可以非常方便的实现a、b逻辑向量间的反转赋值,这样我们就不用写上100行啰嗦的直接信号赋值语句了。当然,这样的功能也可以通过在process中调用for循环语句来实现,不过下面这个利用循环生成语句进行元件例化的例子,就不那么容易找到同样简洁的替代方案了,代码入下:

    COMPONENT cellAdd
    PORT(
    		a : IN std_logic_vector(7 downto 0);
    		b : IN std_logic_vector(7 downto 0);          
    		c : OUT std_logic_vector(7 downto 0)
    		);
    	END COMPONENT;
    type rt is array (7 downto 0) of std_logic_vector (7 downto 0);
    signal arrayA, arrayB, arrayC: rt;
    	adderGen : for i in 7 downto 0 generate
        begin
             arrayAdder: cellAdd Port map(
    a => arrayA(i),
    b => arrayB(i), 
    c => arrayC(i));
    end generate;
    

    可见,本例的方式也极大的简化了我们的代码编写,并且这种代码节省更加不容易被替代,除非从cellAdd上下功夫,但是这样会复杂基本模块,不可取。

    条件生成

    条件生成语句也叫if-generate语句,主要用于一些预编译前的代码控制,类似于C语言中的条件选择宏定义,根据一些初始参数来决定载入哪部分代码来进行编译(即,有选择的让部分代码生效)。例如,我们有时候不确定这个地方是需要一个乘法还是一个除法,可是如果同时实现一个乘法器和一个除法器,那么资源的占用会很多,那么这个时候,可以通过条件生成语句,来方便的在乘法器与除法器之间切换,并且只占用一份资源。注意!这种切换不是动态的,它是通过修改设计中的参数来实现的,所以需要重新编译。if-generate语句的语法如下:

    < generate_LABEL >:
    if <condition> generate
    begin
    <statements>;
    end generate;
    

    举例如下:

    constant sel : integer := 0;
    signal a, b, c: std_logic_vector(15 downto 0);
    
    myMul:
       if sel = 1 generate
       begin
    c <= a * b;	
       end generate;
    myDiv:
       if sel = 0 generate
       begin
          c <= a / b;
       end generate;
    

    关于上例有四点需要注意:一、必须确保两个条件生成语句不能同时有效,否则就会出现c变量的赋值冲突错误。二、条件生成语句不支持else分支。三、判断条件必须为静态条件。四、标签不能省略。
    请大家仔细思考第三点注意,绝对不能利用条件分支做一些动态生成的事情,因为硬件不像软件,不支持对象的动态生成与释放。条件生成语句是为了辅助编译器来预先知道到底该加载哪些语句去进行编译、综合的,而不能根据变量来在编译后动态决定现在选择哪一个代码结构。例如,如果把上例的
    constant sel : integer := 0;
    改为
    signal sel : integer := 0;
    那么编译会报错,表示判断条件不是一个静态条件。如果真的需要根据条件来判断做乘法还是做除法,应该写成这样:
    signal sel : integer := 0;
    cMul <= a * b;
    cDiv <= a / b;
    c <= cMul when sel = ‘1’ else
    cDiv;
    但是注意,这个时候,在FPGA中可是需要调用相应资源来同时实现一个乘法器与一个除法器的,只不过会根据sel来判断此时需要的是乘法器还是除法器的输出。而如果用条件生成语句的话,每一次实现FPGA的设计中,只会有一个乘法器或者一个加法器,资源方面会有很多节省,不过带来的不便就是如果需要另外一种功能时,需要修改代码重新编译实现新的FPGA配置文件。
    需要强调一下,以上例子中,我们为了说明方便和代码简洁,直接使用了“*”、“/”符号来完成乘法与除法运算。在现实情况中,强烈不推荐如此简单的来处理乘、除运算.

    VHDL函数调用语句

    函数——function,是VHDL子程序的一种,函数的调用是一种并行的调用,它可以直接出现在architecture的语句部分当中,例如:
    – e.g. function min() is predefined

    smaller <= min(a, b);
    
    展开全文
    Reborn_Lee 2020-02-13 00:04:16
  • qhs414 2021-05-28 12:06:30
  • 6KB zongfabao 2012-04-29 21:27:30
  • weixin_36169900 2020-12-30 19:14:51
  • weixin_45624330 2020-05-30 21:06:48
  • zyboy2000 2009-05-11 20:57:00
  • zy010101 2019-03-20 12:56:25
  • zy010101 2019-04-07 22:37:16
  • QQ604666459 2017-02-23 12:46:05
  • weixin_45624330 2020-06-01 21:26:53
  • m0_46560857 2021-09-25 18:49:37
  • QQ604666459 2017-02-22 13:05:48
  • 225KB sfhgky 2009-08-24 13:00:40
  • qq_42759162 2021-09-19 14:31:16
  • 2.49MB peng_258 2017-12-30 13:19:21
  • u012761527 2015-04-09 10:17:48
  • kuzmaa 2020-05-14 12:22:57
  • qq_38237827 2020-02-21 23:43:35
  • qq_45396672 2020-12-15 22:23:58
  • yang_jiangning 2020-03-21 20:11:27
  • zxp123zxc 2013-11-27 14:59:13
  • dasdjkld 2021-05-12 18:43:21
  • qq_40310273 2020-08-12 09:14:38
  • qq_37668803 2018-03-31 03:00:15
  • 265KB ruoyun88 2020-03-20 03:00:49
  • weixin_50786207 2021-06-01 15:54:49

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,085
精华内容 434
关键字:

vhdl进程语句