gpt4 book ai didi

integer - VHDL 补码计数器问题 : converting std_logic to integer

转载 作者:行者123 更新时间:2023-12-05 00:37:34 25 4
gpt4 key购买 nike

本质上,我的问题是:“这不能更容易吗?”;什么是'this',如下(代码也是):

我想有一种“补码”计数器功能,用 VHDL 实现,它基本上会在每一步中反转/补码/不是计数器值,为测试提供稍微丰富的位模式。当然,我希望它是可综合的(因此计数器值可以分配给引脚)和可移植代码(即仅实现 IEEE 库,没有 STD_LOGIC_ARITH )。我也不想默认将所有都视为无符号(所以我想避免 STD_LOGIC_UNSIGNED )。

简而言之,这个计数器可以描述为:给定初始值 C[0],那么每个时钟滴答的值将是:

C[i+1] = not(C[i]) + ( ( C[i]<(Cmax/2) ) ? 0 : 1 )

...或者给定 C 是 16 位宽(这将导致无符号 Cmax = 65535 和 Cmax/2 = 32768),它也可以写成:
C[i+1] = 65535 - C[i] + ( ( C[i]<32768 ) ? 0 : 1 )

这里的技巧是计数器应该只增加一次 - 如果它在互补和“正常”范围内增加,那么不会发生任何变化(方程将在两个值之间“振荡”)。

因此,鉴于检查 C[i]<(Cmax/2) 与检查 C 的最高有效位(第 15 位)基本相同,我认为我可以使用以下方法在 VHDL 中轻松实现类似的东西:
Y <= not(Y) + Y(15);

男孩,我对“容易”的看法是不是错了:)

第一个问题是,上面的等式有可能最终为 65535+1,在这种情况下,结果需要 17 位(即溢出);就我而言,我只想截断/忽略任何“进位”。

这导致了使用什么的问题:
  • std_logic_vector有补码 not()定义;但它没有 + (附加)定义
  • natural/integer可能在内部占用 32 位,因此不必指定它们的位宽;他们支持算术+ , 但没有补充 not()
  • 我试过unsigned也有一些问题(不记得)

  • 只有当 Y 为 std_logic_vector 时才能提取第 15 位 (MSB) ,在这种情况下,Y(15) 是单个 std_logic - 但是,它需要转换为 integer类型,否则添加 +未定义:|

    所以,我目前的解决方案(如下)首先有两个计数器寄存器的副本;一个是 SIGNAL wCntReg : STD_LOGIC_VECTOR(15 DOWNTO 0) ;另一个是 SIGNAL tmp_na : natural .然后:
  • 有两个时钟:一个“主”@ 50 MHz,另一个是“计数器”时钟:主时钟 16 倍分频(3.125 MHz)。
  • “计数器”时钟应在下降沿激活计数器值的计算
  • 通过 natural 执行计算变量(从 STD_LOGIC_VECTOR 复制)
  • 显然,std_logic只能转换为 integer如果它转换为 std_logic_vector首先(我很幸运在网上找到了vectorize 函数)。

  • 这里最讨厌的部分是如何反馈 natural变量值,返回 STD_LOGIC_VECTOR一;我可以构建的唯一有效命令是:
    wCntReg <= std_logic_vector(to_unsigned(natural'pos(tmp_na), wCntReg'length));

    ...;但是,请注意,此命令基本上是“设置”该值,下次运行同一命令时该值将“生效”。因此,它不能在“计数器”时钟进程中运行——在下面的代码中,我将它放在更快的“主”时钟进程中。

    最后,下面的代码确实有效(通过 ISE WebPack 中的行为模拟) - 但是,我仍然想知道是否有更直接的方法来解决这个问题。

    提前感谢您的任何答案,
    干杯!

    编码:
    ----------------------------------------------------------------------------------

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    -- use IEEE.STD_LOGIC_ARITH.ALL;
    -- use IEEE.STD_LOGIC_UNSIGNED.ALL;
    use IEEE.NUMERIC_STD.ALL;


    ENTITY complement_count_test_tbw IS
    END complement_count_test_tbw;

    ARCHITECTURE testbench_arch OF complement_count_test_tbw IS

    -- http://www.ingenieurbuero-eschemann.de/downloads/ipicregs/example/vhdl/test/timer_regs_tb.vhd
    -- convert std_logic to std_logic_vector(0 downto 0)
    function vectorize(s: std_logic) return std_logic_vector is
    variable v: std_logic_vector(0 downto 0);
    begin
    v(0) := s;
    return v;
    end;


    -- DECLARE REGISTERS ==========================

    -- 'wires'
    SIGNAL wtCLK : std_logic := '0';

    -- counter register: 16 bit
    SIGNAL wCntReg : STD_LOGIC_VECTOR(15 DOWNTO 0) := (others => 'Z');

    -- temporary 'natural' copy of counter register
    -- http://www.velocityreviews.com/forums/t21700-std_logic_vector-to-unsigned-type-casting.html
    SIGNAL tmp_na : natural;


    -- clock parameters
    constant PERIODN : natural := 20; -- can be real := 20.0;
    constant PERIOD : time := PERIODN * 1 ns;
    constant DUTY_CYCLE : real := 0.5;
    constant OFFSET : time := 100 ns;

    -- freq divisor; with initial values
    constant fdiv : natural := 16;
    SIGNAL fdiv_cnt : natural := 1;
    SIGNAL wfdiv_CLK : std_logic := '0';

    BEGIN

    -- initializations of connections:

    -- instances of components, and their wiring (port maps)...
    -- END instances of components, and their wiring (port maps)...


    -- PROCESSES (STATE MACHINES) CODE =========

    -- clock process for generating CLK
    PROCESS
    BEGIN

    WAIT for OFFSET;

    CLOCK_LOOP : LOOP
    wtCLK <= '0';
    -- MUST refresh counter reg here with value of tmp_na
    wCntReg <= std_logic_vector(to_unsigned(natural'pos(tmp_na), wCntReg'length));
    WAIT FOR (PERIOD - (PERIOD * DUTY_CYCLE));
    wtCLK <= '1';
    WAIT FOR (PERIOD * DUTY_CYCLE);
    END LOOP CLOCK_LOOP;
    END PROCESS;

    -- freq divided clock
    freq_divisor: PROCESS(wtCLK)
    BEGIN
    IF rising_edge(wtCLK) THEN -- posedge
    IF fdiv_cnt = fdiv THEN
    -- reset
    fdiv_cnt <= 1 ;
    wfdiv_CLK <= not(wfdiv_CLK);
    ELSE
    fdiv_cnt <= fdiv_cnt + 1;
    END IF;
    END IF;
    END PROCESS freq_divisor;



    -- sim: count
    PROCESS
    BEGIN

    WAIT for 10 ns;

    tmp_na <= 125;

    WAIT for 10 ns;


    TESTCOUNT_LOOP: LOOP

    -- change counter on negedge of freq. divided clock
    WAIT until falling_edge(wfdiv_CLK);

    tmp_na <= to_integer(unsigned(not(wCntReg))) + to_integer(unsigned(vectorize(wCntReg(15))));

    WAIT for 10 ns;

    END LOOP TESTCOUNT_LOOP;

    END PROCESS;

    -- END PROCESSES (STATE MACHINES) CODE =====

    -- END IMPLEMENT ENGINE of 'CORE' ===============
    END testbench_arch;
    -- END ARCHITECTURE -----------------------------

    最佳答案

    首先,avoiding not use std_logic_arith 满分!

    如果您将向量定义为 unsigned那么(在流程之外)所需要的就是:

      cn_plus_1 <= not cn when cn < halfc else (not cn) + 1;

    你可以分配 cn_plus_1std_logic_vector因此:
    wCntReg <= std_logic_vector(cn_plus_1);

    以下是 VHDL 惯用方式的几个完整示例:
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    entity funny_counter1 is
    port (
    cn: IN unsigned(15 downto 0);
    cn_plus_1 : out unsigned(15 downto 0));
    end entity funny_counter1;

    architecture a1 of funny_counter1 is
    constant halfc : unsigned(cn'range) := (cn'high => '1', others => '0');
    begin -- architecture a1
    cn_plus_1 <= not cn when cn < halfc else (not cn) + 1;
    end architecture a1;

    或在同步过程中:
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;

    entity funny_counter is
    port (
    clk : in std_logic;
    reset : in std_logic;
    cout : out unsigned(15 downto 0));
    end entity funny_counter;

    architecture a1 of funny_counter is
    constant halfc : unsigned(cout'range) := (cout'high => '1', others => '0');
    begin
    process (clk) is
    variable c : unsigned(15 downto 0);
    variable add : integer range 0 to 1;
    begin -- process
    if rising_edge(clk) then -- rising clock edge
    if reset = '1' then
    c := (others => '0');
    else
    add := 0;
    if c < halfc then
    add := 1;
    end if;
    c := (not c) + add;
    end if;
    cout <= c;
    end if;
    end process;
    end architecture a1;

    每当您发现自己在 std_logic_vector 之间进行了很多转换时s 和 integer s(或类似的),您通常使用实际数字。使用 unsigned/ signed向量或整数。如果您需要一个向量,请在最后将其一劳永逸地转换。看着不一定是令人愉快的。但首先要询问您发送值的对象是否应该在其接口(interface)上使用某种数字类型。只有当它真的是一个“比特袋”时,它才是 std_logic_vector最好的类型。姓名 wCntReg对我来说听起来像是一个计数值,所以我认为它应该有一个数字类型。

    你有这个代码:
    wCntReg <= std_logic_vector(to_unsigned(natural'pos(tmp_na), wCntReg'length));

    比它需要的稍差:
    wCntReg <= std_logic_vector(to_unsigned(tmp_na, wCntReg'length));

    应该可以正常工作。

    最后,您评论这仅在下一个时钟滴答时生效是 VHDL 的工作方式 - 仅在经过一段时间后才更新信号(通常仅在进程结束时)。如果您想在此之前使用新值,请使用变量 - 它们会立即更新。

    因此,如果您的 tempna是一个变量,你可以在之后立即进行 wCntReg 赋值。

    为了完整起见:解决此问题的另一种方法(通常是 kludge IME)是 wait for 0 ns;信号分配后。从更新的角度来看,这会导致一些时间过去,因此所有其他增量周期将在当前时间执行(包括您想要传播的信号分配)时间将继续(0ns!)并且新的增量周期可以开始。

    关于integer - VHDL 补码计数器问题 : converting std_logic to integer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6701075/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com