Skip to content
Snippets Groups Projects
Commit fda98c6a authored by Eric Kooistra's avatar Eric Kooistra
Browse files

Made the template more general and clarified more where to define the component function code.

parent 88e7e6eb
No related branches found
No related tags found
No related merge requests found
......@@ -33,7 +33,8 @@
-- <---|snk_out src_in |<---
-- --->|snk_in src_out |--->
-- |____________________|
--
--
-- B) Flow control
--
-- RL=1 RL=1 RL=1
......@@ -43,7 +44,7 @@
-- . | /------\ nxt_r | | r |
-- . \-->| |---*-------*----->|p_reg|-----*---> src_out
-- . | | | | |_____|
-- snk_in -------->|p_comb|<--|-------|--------------*-------- src_in
-- snk_in -------->|p_func|<--|-------|--------------*-------- src_in
-- | | | | |
-- | | | v |
-- | | | /-------\ |
......@@ -59,18 +60,31 @@
-- \|
--
-- Description:
-- . p_comb = functionality:
-- The functionality of the DP component is defined in the p_comb process.
-- The example DUT provides a VHDL template for implementing a streaming
-- function with snk_in.valid and snk_out / src_in flow control. The
-- VHDL template uses the Gaisler two-process coding style. this style
-- has a combinatorial process that describes the function and a clocked
-- process that contains all registers. The register nicely fits the
-- requirement that the streaming component should introduce 1 pipeline
-- latency. In this way it becomes easier to maintain the ready latency
-- of RL=1 from input snk to output src.
-- The example function in the dp_example_dut is a streaming pipeline
-- stage. Hence the dp_example_dut.vhd is equivalent to dp_pipeline.vhd.
--
-- . p_func = functionality:
-- The functionality of the DP component is defined in the p_func process.
-- The p_func process is purely cominatorial, ie it has no clock input.
-- The rest of the block diagram is needed to fit support input valid and
-- output ready flow control and to pipeline the processing such that
-- the function can be implementend within 1 clock cycle.
--
-- . p_reg = local storage and pipelining:
-- The storage is done in a register r and this r contains local storage
-- and the src_out. The r.src_out can directly be wired to src_out. The
-- latency from snk_in to src_out must be 1 clock cycle. If more pipelining
-- is needed then the functionality should be split over separate components
-- that can each again have a latency of 1.
-- and the src_out. The p_reg contains all registers, so it is the only
-- process that has a clock input. The r.src_out can directly be wired to
-- src_out. The latency from snk_in to src_out must be 1 clock cycle. If
-- more pipelining is needed then the functionality should be split over
-- separate components that can each again have a latency of 1.
--
-- . p_flow = local flow control:
-- If the functionality does not add or remove valid data from the snk_in
......@@ -83,14 +97,14 @@
-- Note that the function yields nxt_r that gets pipeline stored in r. The
-- nxt_r is combinatorially related to snk_in so it does not change the RL.
-- The p_flow also works combinatorially because it uses nxt_r and via
-- p_comb also src_in. Hence in total the flow control logic does not change
-- p_func also src_in. Hence in total the flow control logic does not change
-- the RL because snk_out relaies combinatorially on snk_in.valid, nxt_r
-- and src_in.ready.
--
-- . nxt_r.hold_out.valid = combine local and remote flow control:
-- When the functionality in p_comb is about to yield new valid output then
-- When the functionality in p_func is about to yield new valid output then
-- nxt_r.hold_out.valid='1' and then the remote src-in is passed on to
-- snk_out. If p_comb is not yet about to yield new valid output then
-- snk_out. If p_func is not yet about to yield new valid output then
-- nxt_r.hold_out.valid='0' and then the local r_snk_out is passed on to
-- snk_out.
--
......@@ -120,6 +134,17 @@
-- items, until the whole functinality has been covered. This step by step
-- approach makes that the bugs appear one by one instead of all together.
-- Without a step by step approach the bugs are too big to solve.
-- . It is important to keep the function implementation as clean as possible.
-- This can be achieved by only manipulating what is needed and using
-- default options where possible. In practise this implies eg avoiding
-- nested if-then-else statements, don't force assign a value if holding the
-- current value is fine too, etc.
-- . It is important to also verify the DUT for the corner cases of the
-- stimuli. For example block sizeof 1, 2, more, and max. If a certain value
-- is use then verify also what happens if <, = or >. If a design works for
-- the corner cases then this ensures that it works for all values. If a
-- design works for the typical cases then that is no garantuee that it
-- will workfor all situations.
-- . The development steps can becovered in a single testbench or they may also
-- be covered by representing them as tb instances in a multi tb testbench.
-- During the development the multi tb ensures that bug fixes do not
......@@ -169,7 +194,7 @@ ARCHITECTURE rtl OF dp_example_dut IS
BEGIN
p_comb : PROCESS(rst, r, snk_in, src_in)
p_func : PROCESS(rst, r, snk_in, src_in)
VARIABLE v : t_reg;
BEGIN
------------------------------------------------------------------------
......@@ -184,9 +209,13 @@ BEGIN
-- Function
IF r.hold_out.valid='0' THEN
-- Clear hold_out for new output valid (= new subsection)
IF r.src_out.valid='1' THEN
v.hold_out := c_dp_sosi_rst;
-- Clear hold_out for new output valid
IF r.src_out.sop='1' THEN
v.hold_out.sync := '0';
v.hold_out.sop := '0';
END IF;
IF r.src_out.eop='1' THEN
v.hold_out.eop := '0';
END IF;
-- Capture the snk_in block info that is valid at sop and eop
......@@ -203,23 +232,27 @@ BEGIN
END IF;
IF snk_in.valid='1' THEN
-- < main section of component function >
--< start of component function >
v.src_out.data := snk_in.data; -- pipeline function as example
v.hold_out.valid := '1'; -- the function has new data to output
--< end of component function >
END IF;
-- output input stage into output stage when ready, else hold_out.valid to signal pending output
IF v.hold_out.valid='1' THEN
IF src_in.ready='1' THEN
v.src_out.valid := '1';
v.src_out.sync := v.hold_out.sync;
v.src_out.sop := v.hold_out.sop;
v.src_out.eop := v.hold_out.eop;
ELSE
v.hold_out.valid := '1';
v.hold_out.valid := '0';
END IF;
END IF;
ELSE
-- pending output
-- pending output waiting for src_in (could use v, but using r is equivalent and may ease timing closure)
IF src_in.ready='1' THEN
v.src_out.valid := '1';
v.src_out.sync := r.hold_out.sync;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment