本質的に、私の質問は次のとおりです。「これ」とは何か、以下に続きます(コードも):
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 )
ここでの秘訣は、カウンターが 1 回だけインクリメントする必要があることです。カウンターが補完的な範囲と「通常の」範囲の両方で増加する場合、変更は発生しません (式は 2 つの値の間で「振動」します)。
したがって、チェック 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
+
したがって、私の現在のソリューション (以下) には、最初にカウンター レジスタの 2 つのコピーがあります。一つはSIGNAL wCntReg : STD_LOGIC_VECTOR(15 DOWNTO 0)
; もう一つはSIGNAL tmp_na : natural
。それで:
- 2 つのクロックがあります。1 つは「マスター」@ 50 MHz、もう 1 つは「カウンター」クロックです。マスターは 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 -----------------------------