Hi Ben,
> > So my question is: Is it more efficient to merge the two *_DIRTY states
> > into one and reserve an additional state_next register to hold the
> > state to transition to, or just duplicate the states?
> > Did I miss something here? What's the "right" way to do this?
> Really, it is more a question of style. Keeping the "dirty" bit separate
> from the state machine is basically keeping state implicitly, which can
> often lead to confusion. In particular: is the contents of the "dirty" bit
> meaningful when you're not in the READ_MISS or WRITE_MISS state? If not,
> then the existing state machine is probably a better expression of the
> logical behaviour of your circuit than the merged version.
I'm not sure if I got that right. The dirty-bit is stored together with
the cache line in block ram. It's actually state information for the
cacheline, not for the state machine that's controlling the reading and
writing from/to the cache. So it has a meaning even when I'm in some
other state; it marks the corresponding cache line as dirty.
I'll try giving some simplified VHDL'ish example to clarify what I
meant:
-- First with separate states
process(clk)
[...]
case state is
when IDLE =>
[...]
when READ_FROM_RAM =>
[...]
when WRITE_TO_RAM =>
[...]
when READ_MISS =>
if dirty = '1' then -- if cacheline is dirty
state <= READ_MISS_DIRTY; -- write it back
else
state <= READ_FROM_RAM; -- otherwise read the new one
end if;
[...]
when WRITE_MISS =>
if dirty = '1' then
state <= WRITE_MISS_DIRTY; -- see above
else
state <= WRITE_TO_RAM;
end if;
[...]
when READ_MISS_DIRTY; -- almost equals WRITE_MISS_DIRTY
write_back <= '1';
-- do something else
state <= READ_FROM_RAM; -- except for this
end if;
[...]
when WRITE_MISS_DIRTY; -- almost equals READ_MISS_DIRTY
write_back <= '1';
-- do something else
state <= WRITE_TO_RAM; -- except for this
end if;
[...]
-- Or with a merged _DIRTY state
process(clk)
[...]
case state is
when IDLE =>
[...]
when READ_FROM_RAM =>
[...]
when WRITE_TO_RAM =>
[...]
when READ_MISS =>
if dirty = '1' then
state <= MISS_DIRTY;
state_next <= READ_FROM_RAM; -- set next state
else
state <= READ_FROM_RAM;
end if;
[...]
when WRITE_MISS =>
if dirty = '1' then
state <= MISS_DIRTY;
state_next <= WRITE_TO_RAM; -- set next state
else
state <= WRITE_TO_RAM;
end if;
[...]
when MISS_DIRTY; -- merged
write_back <= '1';
-- do something else
state <= state_next; -- "jump"
end if;
[...]
This is somehow like pushing the return address of a function onto the
stack in C programs; and for some reason I don't feel comfortable with
that. On the other hand, it allows me to change the write_back
behaviour on one place (MISS_DIRTY) instead of two (READ_MISS_DIRTY and
WRITE_MISS_DIRTY).
The more I think about it, the more it appears to be a purely academic
questions - both versions do work.
By the way, thanks for the quick response.
Best regards,
Enno