Questions related to adding VHDL add-ons: converting std_logic to integer

Essentially, my question is: "Is it easier to do this?"; and that 'this' follows below (code too):

I wanted to have the add-on counter function implemented in VHDL, which basically inverted / supplemented / not the value of the counter at each step, providing somewhat richer bit samples for testing. Of course, I wanted this to be synthesized (so that the counter value can be assigned to contacts) and portable code (i.e. only IEEE libraries, no STD_LOGIC_ARITH ). I also do not want to treat everything as unsigned by default (so I would like to avoid STD_LOGIC_UNSIGNED ).

In short, this counter can be described as follows: a given initial value C [0], then the values ​​on each measure will be:

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

... or if C is 16 bits wide (which will result in unsigned Cmax = 65535 and Cmax / 2 = 32768), it can also be written as:

 C[i+1] = 65535 - C[i] + ( ( C[i]<32768 ) ? 0 : 1 ) 

The trick here is that the counter should only increase once - if it increases for both additional and “normal” ranges, then no changes will occur (the equation will “fluctuate” between the two values).

So, given that checking C [i] <(Cmax / 2) is basically the same as checking the most significant (15th) bit of C, I thought I could easily implement something like this in VHDL using something- how:

 Y <= not(Y) + Y(15); 

Boy, I was wrong about "easy" :)

The first problem is that it is possible that the above equation can end at 65535 + 1, in which case the result will require 17 bits (i.e., overflow); in my case, I would just like to truncate / ignore any "carry bits".

This leads to a usage problem:

  • std_logic_vector has a not() complement defined; but it does not have + (complement) defined
  • natural / integer can internally accept 32 bits, and since such a bit width is not necessarily specified for them; they support arithmetic + , but do not complement not()
  • I tried unsigned too, had some problems as well (can't remember which one)

The 15th bit (MSB) can be extracted only when Y is std_logic_vector , in which case Y (15) is a single std_logic - but then it must be converted to integer type, because otherwise the addition of + not defined: |

So my current solution (below) first has two counter copies; one is SIGNAL wCntReg : STD_LOGIC_VECTOR(15 DOWNTO 0) ; the other is SIGNAL tmp_na : natural . Then:

  • There are two clock cycles: one “main” with a frequency of 50 MHz, the other - “counter”: the main 16-fold frequency is divided (3.125 MHz).
  • The counter clock must activate the calculation of the counter value from the falling edge
  • The calculation is performed using the variable natural (which copies with std_logic_vector )
  • Apparently std_logic can only be converted to integer if it is first converted to std_logic_vector (I was lucky enough to find the vectorize function on the network).

The most unpleasant part here was how to return the value of the variable natural , back to std_logic_vector ; the only working team that I could build is:

 wCntReg <= std_logic_vector(to_unsigned(natural'pos(tmp_na), wCntReg'length)); 

...; however, note that this command basically “sets” the value that will be “implemented” the next time the same command is executed. Thus, it cannot work in the "counter" mode - in the code below, I have this in a faster "hourly" process.

Finally, the code below works (goes through behavioral modeling in ISE WebPack), but I would still like to know if there is an easier way to solve this problem.

Thanks in advance for any answers, Hooray!

Code:

 ---------------------------------------------------------------------------------- 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 ----------------------------- 
+4
source share
1 answer

First, full marks for avoiding using std_logic_arith !

If you define your vectors as unsigned , then (outside the process) all that is required is the following:

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

and you can assign cn_plus_1 to std_logic_vector this way:

 wCntReg <= std_logic_vector(cn_plus_1); 

Here are some complete examples of the idiomatic ways of 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; 

or in a synchronous process:

 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; 

Whenever you often convert between std_logic_vector and integer (or similar), you usually work with actual numbers. Work with unsigned / signed vectors or with integers. If you need a vector at the end of everything, convert it one and all at the end. I don’t like to watch. But first ask if the thing you are sending the value to should use some kind of numeric type on its interface. Only if it is truly a bag-by-bit, is std_logic_vector best type. The name wCntReg sounds like a count value to me, so it should have a numeric type.

You have this code:

 wCntReg <= std_logic_vector(to_unsigned(natural'pos(tmp_na), wCntReg'length)); 

slightly worse than necessary:

 wCntReg <= std_logic_vector(to_unsigned(tmp_na, wCntReg'length)); 

should work fine.

Finally, you will comment that this only takes effect at the next clock cycle, how VHDL works - signals are updated only after some time (often this is only at the end of the process). If you want to use the new value before this, use the variable - they are updated immediately.

So, if your tempna was a variable, you can do the wCntReg assignment right after.

For completeness: another way around this (usually a kludge IME) is wait for 0 ns; after signal assignment. This causes some time for the transition in terms of updates, so all other delta cycles will be executed during the current time (including the purpose of the signal you want to program), the time will move (by 0ns!), And a new delta cycle may start .

+6
source

All Articles