По сути, мой вопрос таков: " Разве это не легче сделать? "; и что «это», следует ниже (код тоже):
Я хотел иметь своего рода функцию счетчика «дополнения», реализованную в 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) в основном такая же, как проверка самого старшего (15-го) бита C, я подумал, что мог бы легко реализовать что-то подобное в VHDL, используя что-то вроде : </p>
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 МГц, другой - «счетчик»: 16-кратная частота основного делителя (3.125 МГц).
- Часы «счетчика» должны активировать расчет значений счетчика по падающему фронту
- Расчет выполняется с помощью переменной
natural
(которая копирует из STD_LOGIC_VECTOR
one)
- Очевидно,
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 -----------------------------