2. IMPLEMENTATION
2.1 Description
2.2 VHDL Source Code Listing
and Description
delay1
delay2
shared components
3. SIMULATION RESULTS
delay1.ps
delay2.ps
Design a Glushkov Machine with a control unit and datapath. The controller has to be implemented with a state machine. Memory, if any, is considered as a part of the datapath. Optimize the control unit and datapath separately, and discuss timing and cost of the design.
The design we have chosen to implement is the waveform delay generator. It has a 4-bit programmable delay, takes an input, A, and outputs B after the predefined delay expires. The two waveforms, A and B, should look identical, except B is delayed. For simplicity of the design, A cannot be asserted again until B is cleared, i.e. the interval between two pulses on A cannot be less than the delay; the length of the pulse on A cannot equal to the delay; and the length of the pulse on A is 15 clock cycles.
There are two possible scenarios that can happen : 1) the length of the pulse on A is longer than delay; 2) the length of the pulse on A is shorter than delay. The scenarios are illustrated in Figure 1. Care should be taken when implementing the controller so both cases are covered.
The top level of the sorter consists of a reset, a system clock, a pulse input, A, a 4-bit programmable input delay_in, and an output pulse, B. The top-level block diagram is illustrated in Figure 2.
Two different controllers -- delay1 and delay2 -- are implemented for the waveform delay generator with cost/area optimization in mind, since speed is not a real concern in this case (not too much logic is involved.)
delay1 is actually implemented with two separate state machines. One state machine keeps track of where signals A and B are with an internal 4-bit counter, and the other one generates the output B. The state machine on the top detects A and B and starts/stops the internal counter (counting UP) accordingly. The internal counter does not start counting DOWN until A = '0' AND B = '1'. In scenario #1 in Figure 1, the counter would stop when the counter value reaches the delay value; and in scenario #2, the counter value would basically represent the length of the pulse on A when the counter stops counting up. The state machine diagrams are illustrated in Figure 3. The default value of cntr is 0.
delay2 is a much simpler design. It only requires one counter,
but the tradeoff is that an adder is required. The state machine is optimized
to use only two states, which requires only one flip-flop. The basic idea
is that the counter starts when A goes high. When A goes back low, the
counter value is copied to a temporary buffer (requiring a few more flip
flops). The buffer stores the length of the A pulse. When the counter value
equals the delay input, B is asserted to 1. This can happen before or after
A goes back to 0, accounting for both cases of A going low after or before
A goes high. When the counter value equals the temporary value plus the
delay, B will return to 0, which effectively waits a delay value since
A went low, delaying the pulse. As can be seen from the state machine below,
there are multiple state transitions that end up in the same state, but
incur different outputs. This might not be a safe way to design a state
machine, but it allows the use of just one flip flop to store this state
machine. Refer to vhdl code for the state machine description.
gate count:
state machine: 1 flip flops, 9 gates
counter: 4 flip flops, 0 gates
temp storage: 4 flip flops, 0 gates
adder: 4 flip flops, 20 gates
total: 13 flip flops, 29 gates
back to top
2.2 VHDL Source Code Listing
and Description
-----------------------------------------------------------
-- This is the top level
of the waveform delay generator --
-----------------------------------------------------------
LIBRARY ieee;
USE
ieee.std_logic_1164.ALL;
USE
ieee.std_logic_arith.ALL;
USE
ieee.std_logic_unsigned.ALL;
ENTITY delay_top IS
PORT
(
reset : IN STD_LOGIC;
-- global async reset
sys_clk : IN STD_LOGIC;
-- system clock
a : IN STD_LOGIC;
-- input a
delay_in : IN STD_LOGIC_VECTOR (3 DOWNTO 0);
-- programmable delay input
b : BUFFER STD_LOGIC
-- output b
);
END ENTITY delay_top;
ARCHITECTURE comp_list
OF delay_top IS
SIGNAL
cnt_dir : STD_LOGIC;
-- up/down counter direction
SIGNAL
cntr_en : STD_LOGIC;
-- up/down counter enable
SIGNAL
up_cnt_reset : STD_LOGIC;
-- up counter reset
SIGNAL
up_cntr_en : STD_LOGIC;
-- up counter enable
SIGNAL
cntr : STD_LOGIC_VECTOR
(3 DOWNTO 0); -- 4-bit up/down counter
SIGNAL
up_cntr : STD_LOGIC_VECTOR (3 DOWNTO 0);
-- 4-bit up counter
-- control unit
COMPONENT wave_delay
IS
PORT
(
reset : IN STD_LOGIC;
-- global async reset
sys_clk : IN STD_LOGIC;
-- system clock
a_in : IN STD_LOGIC;
-- input a
b_in : IN STD_LOGIC;
-- output b
cntr : IN STD_LOGIC_VECTOR (3 DOWNTO 0);
-- up/down counter
cnt_dir : OUT STD_LOGIC;
-- up/down counter direction
cntr_en : OUT STD_LOGIC
-- up/down counter enable
);
END COMPONENT wave_delay;
COMPONENT output_logic
IS
PORT
(
reset : IN STD_LOGIC;
-- async global reset
sys_clk : IN STD_LOGIC;
-- system clock
a_in : IN STD_LOGIC;
-- input a
cntr : IN STD_LOGIC_VECTOR
(3 DOWNTO 0); -- 4-bit up/down counter
up_cntr : IN STD_LOGIC_VECTOR (3 DOWNTO 0);
-- 4-bit up counter
delay_in : IN STD_LOGIC_VECTOR (3 DOWNTO 0);
-- programmable delay input
up_cntr_en : OUT STD_LOGIC;
-- down counter enable
up_cnt_reset : OUT STD_LOGIC;
-- async up counter reset
b_out : BUFFER STD_LOGIC
-- output b
);
END COMPONENT output_logic;
-- datapath
COMPONENT up_ctr IS
PORT
(
up_cnt_reset : IN STD_LOGIC;
-- up counter reset
sys_clk : IN STD_LOGIC;
-- system clock
cntr_en : IN STD_LOGIC;
-- up counter enable
cntr : BUFFER STD_LOGIC_VECTOR
(3 DOWNTO 0)
-- 4-bit up counter
);
END COMPONENT up_ctr;
COMPONENT updown_cntr
IS
PORT
(
reset : IN STD_LOGIC;
-- global async reset
sys_clk : IN STD_LOGIC;
-- system clock
cnt_dir : IN STD_LOGIC;
-- direction of count : 1 -> count up
--
0 -> count down
cntr_en : IN STD_LOGIC;
-- up/down counter enable
cntr : BUFFER STD_LOGIC_VECTOR (3 DOWNTO 0)
-- 4-bit up/down counter
);
END COMPONENT updown_cntr;
BEGIN
wd:wave_delay
PORT MAP (reset, sys_clk,
a, b, cntr, cnt_dir, cntr_en);
ol:output_logic
PORT MAP (reset, sys_clk,
a, cntr, up_cntr, delay_in, up_cntr_en, up_cnt_reset, b);
cntr1:up_ctr
PORT MAP (up_cnt_reset,
sys_clk, up_cntr_en, up_cntr);
cntr2:updown_cntr
PORT MAP (reset, sys_clk,
cnt_dir, cntr_en, cntr);
END ARCHITECTURE comp_list;
----------------------------------------------------------------------------
-- This module contains
a state machine that keeps track of the waveforms --
----------------------------------------------------------------------------
LIBRARY ieee;
USE
ieee.std_logic_1164.ALL;
USE
ieee.std_logic_arith.ALL;
USE
ieee.std_logic_unsigned.ALL;
ENTITY wave_delay IS
PORT
(
reset : IN STD_LOGIC;
-- global async reset
sys_clk : IN STD_LOGIC;
-- system clock
a_in : IN STD_LOGIC;
-- input a
b_in : IN STD_LOGIC;
-- output b
cntr : IN STD_LOGIC_VECTOR (3 DOWNTO 0);
-- up/down counter
cnt_dir : OUT STD_LOGIC;
-- up/down counter direction
cntr_en : OUT STD_LOGIC
-- up/down counter enable
);
END ENTITY wave_delay;
ARCHITECTURE delay OF
wave_delay IS
TYPE
delay_typ IS (idle, count_up, a_stop, b_start, count_down);
SIGNAL
delay_ps : delay_typ;
SIGNAL
delay_ns : delay_typ;
BEGIN
delay_sm:
PROCESS
(delay_ps, a_in, b_in, cntr)
BEGIN
CASE delay_ps IS
-- wait until a to be asserted to start counting up; up/down counter direction
is '1' (= up),
-- which is the default
WHEN idle =>
IF (a_in = '1') THEN
delay_ns <= count_up;
cntr_en <= '1' after 1 ns;
ELSE
delay_ns <= idle;
cntr_en <= '0' after 1 ns;
END IF;
cnt_dir <= '1' after 1 ns;
-- if a is cleared or b is asserted when in this state, then stop the up/down
counter by
-- clearing cntr_en and set counter direction to '0' (= down); otherwise,
keep the counter
-- running (counting up)
WHEN count_up =>
IF (a_in = '0') THEN
delay_ns <= a_stop;
cntr_en <= '0' after 1 ns;
cnt_dir <= '0' after 1 ns;
ELSIF (b_in = '1') THEN
delay_ns <= b_start;
cntr_en <= '0' after 1 ns;
cnt_dir <= '0' after 1 ns;
ELSE
delay_ns <= count_up;
cntr_en <= '1' after 1 ns;
cnt_dir <= '1' after 1 ns;
END IF;
-- the state machine enters this state if a is cleared before b is asserted,
so wait for b to be
-- asserted to start the up/down counter again; this time, the up/down
counter will be counting
-- down (cnt_dir = '0')
WHEN a_stop =>
IF (b_in = '1') THEN
delay_ns <= count_down;
cntr_en <= '1' after 1 ns;
ELSE
delay_ns <= a_stop;
cntr_en <= '0' after 1 ns;
END IF;
cnt_dir <= '0' after 1 ns;
-- the state machine enters this state if b is asserted before a is cleared,
so wait until a is
-- cleared to start the up/down counter again (counting down)
WHEN b_start =>
IF (a_in = '0') THEN
delay_ns <= count_down;
cntr_en <= '1' after 1 ns;
ELSE
delay_ns <= b_start;
cntr_en <= '0' after 1 ns;
END IF;
cnt_dir <= '0' after 1 ns;
-- wait until up/down counter reaches 0 to clear b; disable the up/down
counter and change the
-- direction of the counter to up (cnt_dir = '1')
WHEN count_down =>
IF (cntr = 0) THEN
delay_ns <= idle;
cntr_en <= '0' after 1 ns;
cnt_dir <= '1' after 1 ns;
ELSE
delay_ns <= count_down;
cntr_en <= '1' after 1 ns;
cnt_dir <= '0' after 1 ns;
END IF;
END CASE;
END
PROCESS delay_sm;
delay_sm_proc:
PROCESS
(reset, sys_clk)
BEGIN
IF (reset = '1') THEN
delay_ps <= idle after 1 ns;
ELSIF (rising_edge (sys_clk)) THEN
delay_ps <= delay_ns after 1 ns;
END IF;
END
PROCESS delay_sm_proc;
END ARCHITECTURE delay;
---------------------------------------------------------------------
-- This module contains
a state machine that controls the output B --
---------------------------------------------------------------------
LIBRARY ieee;
USE
ieee.std_logic_1164.ALL;
USE
ieee.std_logic_arith.ALL;
USE
ieee.std_logic_unsigned.ALL;
ENTITY output_logic IS
PORT
(
reset : IN STD_LOGIC;
-- async global reset
sys_clk : IN STD_LOGIC;
-- system clock
a_in : IN STD_LOGIC;
-- input a
cntr : IN STD_LOGIC_VECTOR
(3 DOWNTO 0); -- up/down counter
up_cntr : IN STD_LOGIC_VECTOR (3 DOWNTO 0);
-- down counter
delay_in : IN STD_LOGIC_VECTOR (3 DOWNTO 0);
-- delay input
up_cntr_en : OUT STD_LOGIC;
-- up counter enable
up_cnt_reset : OUT STD_LOGIC;
-- up counter reset
b_out : BUFFER STD_LOGIC
-- output b
);
END ENTITY output_logic;
ARCHITECTURE output OF
output_logic IS
TYPE
output_typ IS (idle, delay, end_delay);
SIGNAL
output_ps : output_typ;
SIGNAL
output_ns : output_typ;
BEGIN
output_sm:
PROCESS
(output_ps, a_in, cntr, up_cntr, delay_in)
BEGIN
up_cnt_reset <= '0';
-- default up counter reset
-- is always '0'
CASE output_ps IS
-- wait for a to be asserted to start delay i.e. start the up counter;
b = '0' in this state
WHEN idle =>
IF (a_in = '1') THEN
output_ns <= delay;
up_cntr_en <= '1' after 1 ns;
ELSE
output_ns <= idle;
up_cntr_en <= '0' after 1 ns;
up_cnt_reset <= '1';
END IF;
b_out <= '0' after 1 ns;
-- wait until delay is over, i.e. the value of the up counter = programmable
delay, to assert b
-- and clear up counter enable
WHEN delay =>
IF (up_cntr = delay_in) THEN
output_ns <= end_delay;
up_cntr_en <= '0' after 1 ns;
b_out <= '1' after 1 ns;
ELSE
output_ns <= delay;
up_cntr_en <= '1' after 1 ns;
b_out <= '0' after 1 ns;
END IF;
-- wait until up/down counter reaches 0 to clear b
WHEN end_delay =>
IF (cntr = 0) THEN
output_ns <= idle;
b_out <= '0' after 1 ns;
ELSE
output_ns <= end_delay;
b_out <= '1' after 1 ns;
END IF;
up_cntr_en <= '0' after 1 ns;
END CASE;
END
PROCESS output_sm;
--
output state machine process
output_sm_proc:
PROCESS
(reset, sys_clk)
BEGIN
IF (reset = '1') THEN
output_ps <= idle after 1 ns;
ELSIF (rising_edge (sys_clk)) THEN
output_ps <= output_ns after 1 ns;
END IF;
END
PROCESS output_sm_proc;
END ARCHITECTURE output;
----------------------------------------------------------------------------
-- This module contains
an optimized waveform delay generator
--
----------------------------------------------------------------------------
LIBRARY ieee;
USE
ieee.std_logic_1164.ALL;
USE
ieee.std_logic_arith.ALL;
USE
ieee.std_logic_unsigned.ALL;
ENTITY delay2 IS
PORT
(
reset : IN STD_LOGIC;
-- global async reset
clk : IN STD_LOGIC;
-- system clock
a : IN STD_LOGIC;
-- input a
delay : IN STD_LOGIC_VECTOR(3 downto 0);
-- user defined delay
b : INOUT STD_LOGIC
-- output b
);
END ENTITY delay2;
ARCHITECTURE behav OF
delay2 IS
TYPE
state_type IS (idle, run);
SIGNAL
delay_ps : state_type;
SIGNAL
delay_ns : state_type;
SIGNAL
temp : STD_LOGIC_VECTOR(3
downto 0);
SIGNAL
up_cnt_reset : STD_LOGIC;
SIGNAL
cntr : STD_LOGIC_VECTOR(3
downto 0);
COMPONENT up_ctr IS
PORT
(
up_cnt_reset : IN STD_LOGIC;
-- up counter reset
sys_clk : IN STD_LOGIC;
-- system clock
cntr : BUFFER STD_LOGIC_VECTOR
(3 DOWNTO 0)
-- 4-bit up counter
);
END COMPONENT up_ctr;
BEGIN
cntr1:up_ctr
PORT MAP (up_cnt_reset,
clk, cntr);
delay_sm:
PROCESS
(delay_ps, a, reset, delay, temp, up_cnt_reset, cntr)
BEGIN
CASE delay_ps IS
WHEN idle =>
temp <= "ZZZZ";
up_cnt_reset <= '1';
b <= '0';
IF (a = '1') THEN
delay_ns <= run;
ELSE
delay_ns <= idle;
END IF;
WHEN run =>
up_cnt_reset <= '0';
IF (a'event AND a = '0' AND delay = cntr) THEN
delay_ns <= run;
temp <= cntr;
b <= '1';
ELSIF (delay = cntr) THEN
delay_ns <= run;
b <= '1';
ELSIF (a'event AND a = '0') THEN
delay_ns <= run;
temp <= cntr;
ELSIF (cntr = temp + delay) THEN
delay_ns <= idle;
ELSE
delay_ns <= run;
END IF;
END CASE;
END
PROCESS delay_sm;
delay_sm_proc:
PROCESS
(reset, clk)
BEGIN
IF (reset = '1') THEN
delay_ps <= idle after 1 ns;
ELSIF (clk'event and clk = '1') THEN
delay_ps <= delay_ns after 1 ns;
END IF;
END
PROCESS delay_sm_proc;
END ARCHITECTURE behav;
----------------------------
-- 2 to 1 mux description
--
-- gate count : 4
--
----------------------------
LIBRARY ieee;
USE
ieee.std_logic_1164.ALL;
USE
ieee.std_logic_arith.ALL;
ENTITY mux IS
PORT
(
in0 : IN STD_LOGIC;
-- mux input 0
in1 : IN STD_LOGIC;
-- mux input 1
sel : IN STD_LOGIC;
-- input select :
-- if bit = '0', muxout <= in0
-- if bit = '1', muxout <= in1
muxout : OUT STD_LOGIC
-- mux output
);
END mux;
ARCHITECTURE behav OF
mux IS
BEGIN
process
(sel, in0, in1)
begin
-- select mux output
muxout <= (in0 AND Not sel) OR (in1 AND sel);
end
process;
END behav;
-----------------------------
-- t flip-flop description
--
-----------------------------
LIBRARY ieee;
USE
ieee.std_logic_1164.ALL;
USE
ieee.std_logic_arith.ALL;
ENTITY tflipflop IS
PORT
(
reset : IN STD_LOGIC;
-- reset of T flip-flop
T : IN STD_LOGIC;
-- T input
Q : BUFFER STD_LOGIC;
-- Q output
Qnot : OUT STD_LOGIC;
-- Qnot outupt
clk : IN STD_LOGIC
-- clock
);
END tflipflop;
ARCHITECTURE behav OF
tflipflop IS
BEGIN
PROCESS
(clk, reset, T, Q)
BEGIN
Qnot <= NOT Q;
-- Qnot always gets NOT Q
if (reset = '1') then
Q <= '0';
-- clear Q at reset
elsif (clk'event and clk = '1') then
if (T = '1') then
Q <= NOT Q;
-- toggle Q if T = '1'
else
Q <= Q;
end if;
end if;
END
PROCESS;
END behav;
------------------------------
-- binary ripple up
counter --
------------------------------
LIBRARY ieee;
USE
ieee.std_logic_1164.ALL;
USE
ieee.std_logic_arith.ALL;
ENTITY up_ctr IS
PORT
(
up_cnt_reset : IN STD_LOGIC;
sys_clk : IN STD_LOGIC;
-- clock
cntr_en : IN STD_LOGIC;
-- count enable
cntr : BUFFER STD_LOGIC_VECTOR
(3 DOWNTO 0)
);
END up_ctr;
ARCHITECTURE behav OF up_ctr IS
COMPONENT tflipflop IS
PORT
(
reset : IN STD_LOGIC;
T : IN STD_LOGIC;
Q : BUFFER STD_LOGIC;
Qnot : OUT STD_LOGIC;
clk : IN STD_LOGIC
);
END COMPONENT;
signal Qnot0 :
std_logic;
signal Qnot1 :
std_logic;
signal Qnot2 :
std_logic;
signal Qnot3 :
std_logic;
BEGIN
t0 : tflipflop
PORT
MAP(
reset => up_cnt_reset,
T => cntr_en,
Q => cntr(0),
Qnot => Qnot0,
clk => sys_clk
);
t1 : tflipflop
PORT
MAP(
reset => up_cnt_reset,
T => cntr_en,
Q => cntr(1),
Qnot => Qnot1,
clk => Qnot0
);
t2 : tflipflop
PORT
MAP(
reset => up_cnt_reset,
T => cntr_en,
Q => cntr(2),
Qnot => Qnot2,
clk => Qnot1
);
t3 : tflipflop
PORT
MAP(
reset => up_cnt_reset,
T => cntr_en,
Q => cntr(3),
Qnot => Qnot3,
clk => Qnot2
);
END behav;
---------------------------------------------------------------------------
-- This is a binary
ripple up/down counter implemented with T flip-flops --
-- and 2-input multiplexers
--
---------------------------------------------------------------------------
LIBRARY ieee;
USE
ieee.std_logic_1164.ALL;
USE
ieee.std_logic_arith.ALL;
USE
ieee.std_logic_unsigned.ALL;
ENTITY updown_cntr IS
PORT
(
reset : IN STD_LOGIC;
-- global async reset
sys_clk : IN STD_LOGIC;
-- system clock
cnt_dir : IN STD_LOGIC;
-- up/down counter direction
cntr_en : IN STD_LOGIC;
-- up/down counter enable
cntr : BUFFER STD_LOGIC_VECTOR (3 DOWNTO 0)
-- 4-bit up/down counter
);
END updown_cntr;
ARCHITECTURE bidir_cntr OF updown_cntr IS
COMPONENT tflipflop IS
PORT
(
reset : IN STD_LOGIC;
-- async T flip-flop reset
T : IN STD_LOGIC;
-- T input
Q : BUFFER STD_LOGIC;
-- Q output
Qnot : OUT STD_LOGIC;
-- Qnot output
clk : IN STD_LOGIC
-- clock
);
END COMPONENT;
COMPONENT mux IS
PORT
(
in0 : IN STD_LOGIC;
-- mux input in0
in1 : IN STD_LOGIC;
-- mux input in1
sel : IN STD_LOGIC;
-- mux input select
muxout : OUT STD_LOGIC
-- mux output :
-- if sel = '0', muxout = in0
-- if sel = '1', muxout = in1
);
END COMPONENT;
SIGNAL
Qnot0 : STD_LOGIC;
SIGNAL
Qnot1 : STD_LOGIC;
SIGNAL
Qnot2 : STD_LOGIC;
SIGNAL
Qnot3 : STD_LOGIC;
SIGNAL
clk1 : STD_LOGIC;
SIGNAL
clk2 : STD_LOGIC;
SIGNAL
clk3 : STD_LOGIC;
BEGIN
-- instatiate T flip-flops
and muxes
t0:tflipflop
PORT
MAP (
reset =>reset,
T => cntr_en,
Q => cntr(0),
Qnot => Qnot0,
clk => sys_clk
);
t1:tflipflop
PORT
MAP (
reset => reset,
T => cntr_en,
Q => cntr(1),
Qnot => Qnot1,
clk => clk1
);
t2:tflipflop
PORT
MAP (
reset => reset,
T => cntr_en,
Q => cntr(2),
Qnot => Qnot2,
clk => clk2
);
t3:tflipflop
PORT
MAP (
reset => reset,
T => cntr_en,
Q => cntr(3),
Qnot => Qnot3,
clk => clk3
);
mux1:mux
PORT
MAP(
in0 => cntr(0),
in1 => Qnot0,
sel => cnt_dir,
muxout => clk1
);
mux2:mux
PORT
MAP(
in0 => cntr(1),
in1 => Qnot1,
sel => cnt_dir,
muxout => clk2
);
mux3:mux
PORT
MAP(
in0 => cntr(2),
in1 => Qnot2,
sel => cnt_dir,
muxout => clk3
);
END ARCHITECTURE bidir_cntr;