簡體   English   中英

VHDL 補碼計數器問題:將 std_logic 轉換為 integer

[英]VHDL complement counter issues: converting std_logic to integer

本質上,我的問題是:“這不是更容易嗎? ”; 什么是'this',如下(代碼也是):

我想要一種用 VHDL 實現的“補碼”計數器 function,它基本上會在每一步中反轉/補碼/不反轉計數器值,從而為測試提供稍微豐富的位模式。 當然,我希望它是可綜合的(因此計數器值可以分配給引腳)和可移植代碼(即僅實現 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 ,也有一些問題(不記得是哪個)

第 15(MSB)位只能在 Y 為std_logic_vector時提取,在這種情況下,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的function)。

這里最討厭的部分是如何將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 -----------------------------

首先,避免不使用 std_logic_arith的滿分!

如果您將向量定義為unsigned ,那么(在進程之外)所需要的就是:

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

您可以將cn_plus_1分配給std_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_vectorinteger (或類似的)之間進行大量轉換時,您通常會使用實際數字。 使用unsigned /有signed向量或整數。 如果您需要一個向量,請在最后將其一勞永逸地轉換。 看着不一定是令人愉快的。 但首先要詢問您發送值的對象是否應該在其接口上使用某種數字類型。 只有當它真的是一個“比特袋”時, 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)並且新的增量周期可以開始。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM