琉球大学情報工学科 和田 知久
CLKがHighの時に、入力Dは出力Qへインバータ2段で接続され、
CLKがLowの時に、インバータ2段がリング接続になり、値を保持する。
シンボル | 名称 | 意味 |
tC | サイクルタイム | 動作する周期、スペックでは最小値が規定される。 |
tS | セットアップタイム | クロックエッジに対するデータを用意する時間、スペックでは最小値が規定される。 |
tH | ホールドタイム | クロックエッジに対してデータを保持する時間、スペックでは最小値が規定される。 |
tKQ | アクセスタイム | クロックエッジからデータ出力までの時間、スペックでは最大値が規定される。 |
OUT <=[ { (IN + 1) *2 + 1 } *2 + 1 ] *2
=>1組の加算器と乗算器を繰り返し使用すればよい。さてどのように?
サイクルNo. | 動作 |
1 | X <= (IN + 1) * 2 |
2 | Y <= (X + 1) * 2 |
3 | OUT <= (Y + 1) * 2 |
入力IN=2の場合の動作波形を示す。
GetInput=1で入力IN=2をAに取りこむ。
D <= (IN + 1) *2 = 6 でサイクル2に Q <= 6となる。
サイクル2ではGetInput=0であるので、A <= 6となる。
後は繰り返して、サイクル4で30が出力される。
ということで、フリップフロップで順序回路が構成できる。
library IEEE;
use IEEE.STD_LOGIC_1164.all, IEEE.NUMERIC_STD.all;
entity ADDMUL is
port (Input : in unsigned (7 downto 0);
GetInput : in std_logic;
Clk : in std_logic;
Output : out unsigned (7 downto 0) );
end entity ADDMUL;
architecture RTL of ADDMUL
is
signal Q : unsigned (7 downto 0);
begin
process(Clk)
variable A : unsigned (7 downto 0);
begin
if rising_edge(Clk) then
----------
-- MUX
----------
MUX: if (GetInput = '1') then
A := Input;
else A := Q;
end if MUX;
----------
-- ADD1 & MUL2
----------
Q <= Shift_left((A + 1),1);
end if;
end process;
Output <= Q;
end architecture RTL;
process文の中で、wait文やif文でエッジを検出する記述を行えば、FFが生成される。
エッジ検出記述
Clock'event and Clock= '1' | 'eventアトリビュートを用いた立ち上りエッジの検出 |
Clock'event and Clock= '0' | 'eventアトリビュートを用いた立ち下りエッジの検出 |
not Clock'stable and Clock = '1' | 'stableアトリビュートを用いた立ち上りエッジの検出 |
not Clock'stable and Clock = '0' | 'stableアトリビュートを用いた立ち下りエッジの検出 |
rising_edge(Clock) | ファンクションコールを用いた立ち上りエッジの検出 |
falling_edge(Clock) | ファンクションコールを用いた立ち下がりエッジの検出 |
関数rising_edge, falling_edgeは'X'から'1'への変化を検知しない。
P1: process (Clock)
begin
if ( Clock'event and Clock= '1') then
Y1 <= A1;
end if;
if ( Clock'event and Clock=
'1') then
Y2 <= A2;
end if;
end process P1;
立ち上りエッジのDFF、if文は繰り返し書けるで複数のFFを生成できる。
P2: process
begin
wait until (Clock'event and Clock= '1');
Y3 <= A3;
end process P2;
wait文はそこでブロックして止まるので、複数のwait文を一つのprocess文に書けない。
P3: process (Clock)
begin
if rising_edge(Clock) then
Y4 <= A4;
end if;
end process P3;
if文中でrising_edge関数を用いた場合。記述がコンパクトでGOOD!
P4: process
begin
wait until rising_edge(Clock);
Y5 <= A5;
end process P4:
wait文に関数rising_edgeを用いた記述。
以下のように3つ(もしくは3人)の計算機があったとする。
3人はそれぞれ計算の仕事を同時に行う。例えば、計算1は加算、計算2は掛算、計算3は割算である。
この3人が計算結果をグルグル回すことで、1つの大きな仕事ができるとする。
この場合以下のようなことがおきる
1) 計算1は5nsごとに計算結果を計算2に渡そうとするが、計算2は10nsごとにしか仕事もらえない。
2) 計算1は計算2が空いたことを教えてもらってから、計算2へ仕事を渡す。
3) 同様に計算2も計算3が空いたことを知らされて、計算3へ結果を渡し、その後計算1へ自分が空いたことを伝える。
4) 要するに、隣接ユニット間で知らせ合い(ユニット間の通信)を行う必要がある。
同期回路では、このユニットごとの通信を不要にするために、ユニット間にフリップフロップを入れて、同一のクロック信号で同期させる。
1) クロックの立ち上がりエッジで、セイノで、(同時に)各ユニットへ入力データが入力される。
2) その後、計算1は7ns (CLK立ち上がりエッジからFFの出力までの遅延を2nsとする)で計算が終わるが
3) 次の入力を得るまで、20nsぐらいの間そのまま待たされる。
4) 一番遅い計算3も22ns
後には計算を終える。
5) そして、25ns
後のクロックの立ち上がりエッジで各FFは前のユニットの結果を次のユニットへ伝える。
FFの働きは、各ユニットばらばらの計算時間をクロックにより遅らせて、計算時間をそろえている。
理想的には、最も低速な計算3の計算時間20nsのサイクル時間が使えそうであるが、実際にはFFのセットアップタイムとアクセスタイムの分だけサイクル時間を延ばす必要がある。
一見、同期回路は効率が悪そうであるが、最大のメリットは非同期回路のユニット間の通信が不要になることにある。
非同期の場合でも、計算のスループットは結局最も遅い計算3で決まり、それに、ユニット間通信の遅延が加算される。ユニット間通信の遅延がFFのセットアップ+アクセス時間以上なら、同期の方が性能はよくなる。
1)3人の学生A,B,Cさんはそれぞれ以下の仕事をするとする
A: 紙に書かれた数字を見て、その数字に1を加えたもの計算し、紙に答えを書く
B: 紙に書かれた数字を見て、その数字を2倍したもの計算し、紙に答えを書く
C: 紙に書かれた数字を見て、その数字を5倍し、それから3を引き算したもの計算し、紙に答えを書く
最初、Aさん、Bさん、Cさんにそれぞれ、「1」、「2」、「3」と書かれた紙を渡す。
そして、A,B,Cさんはすぐに自分の仕事をする。
先生の「ハイ!」という合図で、AさんはBさんに紙を渡し、BさんはCさんに紙を渡し、CさんはAさんに紙を渡すとする。
先生が「ハイ!」と5回言った後に、Aさん、Bさん、Cさんの紙の数字はそれぞれ幾らか?
2) 以下の波形をそれぞれ、DラッチとDフリップフロップに入力した時の波形を描け
以上