2017-08-02 101 views
1

我在使用我的VHDL测试工作台中的聚合物时遇到了一些麻烦(如下图所示)。使用别名的VHDL聚合分配

library IEEE; 
use IEEE.std_logic_1164.all; 
use IEEE.numeric_std.all  

entity TB is 
end entity; 

architecture RTL of TB is 
    -- constant(s) 
    constant CLK_PERIOD : time       := 10 ns; -- 100 MHz 
    -- signal(s) 
    signal CLK   : std_logic     := '0'; 
    signal nRST   : std_logic     := '1'; 
    signal CONFIG_REG : std_logic_vector(7 downto 0) := (others => '0'); 
begin 
    -- clock driver 
    CLK <= NOT CLK after (CLK_PERIOD/2.0); 

    -- main process 
    process 
    begin 
     -- reset driver... 
     nRST <= 
      '1', 
      '0' after (CLK_PERIOD * 1); 

     -- set initial configuration... 
     CONFIG_REG <= (
      6   => '1',  
      3 downto 2 => "01", 
      7 | 0  => '1', 
      others  => '0' 
     ); 

     -- do test-bench stuff... 

     -- update configuration... 
     CONFIG_REG <= (
      6   => '0',  
      3 downto 2 => "10", 
      7 | 0  => '1', 
      others  => '0' 
     ); 

     -- do more test-bench stuff... 
    end process; 
end architecture; 

我真的想'命名'配置寄存器的部分,以便它实际上读取得很好。

所以我想说:

Bit[6] = ENABLE 
Bit[3:2] = MODE 
Bit[7|0] = READY_DONE 

我知道,我可以用一个常数6:

constant ENABLE : integer := 6; 

,然后我的代码看起来是这样的:

CONFIG_REG <= (
    ENABLE  => '1',  
    3 downto 2 => "01", 
    7 | 0  => '1', 
    others  => '0' 
); 

但我一直难住尝试获得名称为3 downto 27|0的范围,以便代码如下所示:

CONFIG_REG <= (
    ENABLE  => '1',  
    MODE  => "01", 
    READY_DONE => '1', 
    others  => '0' 
); 

我想我可能能够做到这一点使用别名,我一直在寻找的VHDL Golden Reference Guide (p.15)这一直是非常有益的,据了解别名和范围去,但我仍然无法弄清楚如何命名范围本身或值或'或'(|)。

目前,我有下面的“黑客”,我真的不喜欢...

constant ENABLE : integer := 6; 
alias MODE is CONFIG_REG(3 downto 2); 
-- what to do about the OR though??? 

CONFIG_REG <= (
    ENABLE  => '1',  
    MODE'RANGE => "01", 
    7 | 0  => '1', 
    others  => '0' 
); 

我真想让我的测试台可读这样,当我看它6个月。从现在开始,我会知道它在做什么,而不必去找出“现在又是什么[6]了?”或者如果我必须将我的代码交给另一个开发人员,他们可以轻松了解我想要完成的任务。

任何帮助/建议,将不胜感激如何做到这一点。

感谢您的阅读。


编辑:修正了7 | 0是有效的:

无效:

7 | 0  => "10", 

有效期:

7 | 0  => '1', 
+0

除@ user1155120的答案外,还可以使用索引类型为枚举类型的数组。 – Paebbels

+2

你有没有理由不使用记录类型?他们命名了字段。如果您还需要矢量化版本的数据,则可以非常轻松地在矢量和记录类型之间编写转换函数。 –

+0

@RenaudPacalet我没有使用记录,因为它对我来说没有任何意义,只要寄存器是什么(即一个位的集合)。你通常使用记录来表示设计中的寄存器而不是'std_logic_vector'? – bgarisn

回答

0

我喜欢在我的包中定义全宽常量:

subtype ConfigRegType is std_logic_vector(7 downto 0) ; 
constant CFG_ENABLE : ConfigRegType := B"0_1_000000" ; 
constant CFG_MODE0 : ConfigRegType := B"0000_00_00" ; 
constant CFG_MODE1 : ConfigRegType := B"0000_00_00" ; 
constant CFG_MODE2 : ConfigRegType := B"0000_10_00" ; 
constant CFG_MODE3 : ConfigRegType := B"0000_11_00" ; 
constant CFG_READY : ConfigRegType := B"1_0000000" ; 
constant CFG_DONE : ConfigRegType := B"0000000_1" ; 
. . . 

现在,当您准备好写,只是“或”值设置你想要的:

CONFIG_REG <= CFG_ENABLE or CFG_MODE1 or CFG_READY or CFG_DONE ; 

我也玩过其他的方式,但是,像你注意到他们似乎需要的知识实施细节。

+0

感谢您的建议。你是否发现当你不得不改变道路时这种方法是灵活的? – bgarisn

+0

当事情发生变化时,只需更新软件包中的子类型和常量即可。 –

+0

Imho不是那么简单。试想一下,编辑50行以上的代码决定将另一位添加到配置寄存器中。关于软件设计,这个代码的维护成本相当高。 – JHBonarius

2

请注意,您的代码无效:汇总记号7 | 0代表索引组,而不是向量组。它应该与std_logic值相关联,而不是std_logic_vector。此外,在现有2008 VHDL的版本中,聚集符号3 downto 2也应关联std_logic值:

-- set initial configuration... 
CONFIG_REG <= (
    6   => '1',  
    3 downto 2 => '1', 
    7 | 0  => '0', 
    others  => '0' 
); 

在2008 VHDL是离散范围和聚集体的类型的表达的选择之间的关联现在支持。因此,VHDL 2008中的3 downto 2 => "01"是OK的。但是由于许多合成器尚未完全支持VHDL 2008,所以您应该小心,除非此代码不应当被合成。

无论如何,使用记录而不是向量可能是您的问题的一个选项。如果您还需要矢量版本的数据,则可以非常轻松地在矢量和记录类型之间编写转换函数。例如:

package foo is 
    type config_type is record 
    ready: std_ulogic; 
    enable: std_ulogic; 
    foobar: std_ulogic_vector(1 downto 0); 
    mode:  std_ulogic_vector(1 downto 0); 
    reserved: std_ulogic; 
    done:  std_ulogic; 
    end record; 

    function rec2vec(v: config_type) return std_ulogic_vector; 
    function vec2rec(v: std_ulogic_vector) return config_type; 
end package foo; 

package body foo is 
    function rec2vec(v: config_type) return std_ulogic_vector is 
    begin 
    return v.ready & v.enable & v.foobar & v.mode & v.reserved & v.done; 
    end function rec2vec; 

    function vec2rec(v: std_ulogic_vector) return config_type is 
    constant vv: std_ulogic_vector(7 downto 0) := v; 
    begin 
    return (ready => vv(7), enable => vv(6), foobar => vv(5 downto 4), 
      mode => vv(3 downto 2), reserved => vv(1), done => vv(0)); 
    end function vec2rec; 
end package body foo; 

然后,您可以使用聚集符号分配记录:

signal config_reg: config_type; 
... 
config_reg <= (
    ready => '1', 
    enable => '1', 
    foobar => "--", 
    mode => "01", 
    others => '0' 
); 

,并转换到载体:

signal config_reg_v: std_ulogic_vector(7 downto 0); 
... 
config_reg_v <= rec2vec(config_reg); 
... 
config_reg <= vec2rec(config_reg_v); 
... 
config_reg <= vec2rec(X"ff"); 

注:我用std_ulogicstd_ulogic_vector代替解决std_logicstd_logic_vector。这有很好的理由,但这是另一个问题。

+0

感谢您的详细回复。我搞砸了'7 | 0'这是真的。我认为可以说'3 downto 2 =>“01”虽然不是吗?我没有使用记录,因为这似乎是一个复杂的方式来在我的注册表中找到一个名字,但我相对VHDL来说是新手/中级,因此我不确定其他开发人员如何执行此操作。 – bgarisn

+0

对不起,但是'3 downto 2 =>“01”'在这种情况下,**不是**有效。任何VHDL编译器/模拟器都会引发错误。记录并不复杂,它们只是大多数体面编程语言的一个非常有用的功能。帮你一个忙:在他们有意义的地方使用它们。主要归功于他们将避免的愚蠢错误的数量,这将大大提高您的生产力。 –

+0

不要后悔。我只是想了解为什么它是无效的,因为Modelsim 10.5c(我用来运行我的测试平台的模拟器)似乎认为它很好 - 也就是说,在模拟中将值更改为“01”如预期。我感谢你指点我的记录。我会确保检查出来并学习如何以更高效的方式使用它们。 – bgarisn