Hello. I normally have the control description (normally a fsm)
separate from the datapath.
That's a religious thing, not a design requirement or anything that
necessarily improves anything...but OK.
Supposing I need a counter to time the
duration of some of the control outputs, for example, enable this mux
for 1000 cycles before doing anything else, would you declare the
counter inside or outside of the fsm architecture?
Depends on what you mean by 'fsm architecture'. For the sake of
discussion, I'll assume that you mean a VHDL 'process'. Next, I
wouldn't get philosophical about it but instead focus on the
readability and maintainability of the design. A VHDL process that
requires paging back and forth in order to be understood likely does
not rank very high on the readability and maintainability score (which
is subjective). Given no other information about what function is to
be accomplished in the entity I would most likely start like the code
I've shown below.
If either the counter logic or the FSM logic (or other logic in the
architecture) grew to the point where the process gets to be too long,
I would likely break it up into separate clocked processes just to try
to keep related things together and try to make it a bit easier to
understand.
Long processes can spawn use of numerous variables. While variables
are a good thing, assignments to variables create a line in the sand.
Prior to the assignment, the variable means one thing, after the
assignment it means something else. Since code generally tends to
grow over time and not shrink it can cause problems if the code starts
to look a bit unwieldy since you can't easily move things around
without destroying the function. In my example, I didn't use
variables so the logic implementing the FSM and the logic implementing
the counter could be rearranged as separate block for readability
however I see fit...it's all happening in parallel.
You having the take that control logic must be separated from control
logic you've put up some artificial barriers that are philosophical
but do not contribute to making a design more robust or maintainable.
As I wrote it, the counter is separated from the control logic but not
because of any philosophy. The two functions are loosely coupled (the
FSM tells the counter to start, the counter tells the FSM when it's
done) so the logic to implement each tends to not want to live inside
the other.
A more pragmatic approach that will lead to better design is to view
sub-functions to see if they fit the model of 'request/acknowledge' or
'start/complete' 'command/wait' (whichever works for you). You'll
find that in many cases they do. In this case, the FSM commands the
counter to start (via being in a particular state...or could've been
as a separate signal if you prefer) and the counter then signals back
when it completes (via the 'Done_Counting' signal). Once you take
that viewpoint, you'll probably see that the logic for sub-functions
naturally separates into more readable, maintainable code.
Kevin Jennings
----
architecture RTL of Something is
type t_STATES is (Idle, Start_Count, Done);
signal Current_State: t_STATES;
constant MAX_COUNT: natural := 999;
signal Counter: natural range 0 to MAX_COUNT;
signal Done_Counting: std_ulogic;
begin
process(Clock)
begin
if rising_edge(Clock) then
------------
-- FSM logic
------------
if (Reset = '1') then
Current_State <= Idle;
else
case Current_State is
when Idle =>
-- Code to wait for event to start timing
when Start_Count =>
if (Done_Counting = '1') then
Current_State <= Done;
end if;
when Done =>
-- Code to take us back to idle presumably
end case;
end if;
------------------------
-- Output signal counter
------------------------
if ((Current_State /= Start_Count)
or (Counter = MAX_COUNT) then
Counter <= 0;
else
Counter <= Counter + 1;
end if;
end process;
Done_Counting <= '1' when (Counter = MAX_COUNT) else '0';