I'm _damn_ confused.

Guest
Sorry about the non-descriptive title, I couldn't think of much more
specific.

Anyway, I'm building an IDE device, and I have the following code :

signal REG_DRV_ADDY: std_logic_vector(0 to 7);
constant REG_DRV_HEAD_DRV: integer:=4;
....
begin
debug<=REG_DRV_HEAD(REG_DRV_HEAD_DRV);

-- convienece
csda(0 to 1) <= not(CS);
csda(2 to 4) <= DA;

-- main logic
process(RD, WR, RST
,DATA, csda, REG_STATUS_DATA, sectorbuf_data )
begin

if (RST='0') then
-- reset condition
REG_DRV_HEAD(REG_DRV_HEAD_DRV) <='0';
DATA<=(others=>'Z');
elsif (rd='0') then
-- read strobe
if REG_DRV_HEAD(REG_DRV_HEAD_DRV)='0' then -- are we selected?
if csda=IDE_REG_R_DATA then
sectorbuf_nextbuf<='0';
data(0 to 15)<=sectorbuf_data;
else
sectorbuf_nextbuf<='1';
end if;
else
DATA<=(others=>'Z');
end if;
elsif wr='0' then
-- write strobe
DATA<=(others=>'Z');
if IDE_REG_DRV_HEAD=csda then
REG_DRV_HEAD<=DATA(0 to 7);
end if;
else
-- bus idle
DATA<=(others=>'Z');
end if;
end process;

The effect I'm trying to acheve is that the drive will store writes to
the DRV_HEAD register, and will only respond to reads if the
REG_DRV_HEAD_REG bit of DRV_HEAD register is set to 0. The way I see
this it should work, but in a simulation I get a 'z' on the 'debug'
port (in behavioural) or an X in post-synthesis. The way I read it, the
debug pin should go low when the relevant data bit goes low and the
write strobe is low..
Can anyone help me out, or give me a few pointers? I've uploaded a
screengrab of the simulation - http://i6.tinypic.com/1z22lg5.png .
Thanks.

-Alan
 
The process to compute signal 'REG_DRV_HEAD' should be all by itself
and in no way a function of RD, strip out the assignment to everything
other than 'REG_DRV_HEAD' and move them to a separate process.
Something like...

if (RST='0') then
Do the reset stuff here
elsif wr='0' then
Assign the signal from the appropriate data bits here
end if;

The assignment to drive 'DATA' should be in either a separate process.

Now for the reason for what you see. The process does indeed get
triggered by WR going to '0' which then causes the following statements
to get executed
DATA<=(others=>'Z');
if IDE_REG_DRV_HEAD=csda then
REG_DRV_HEAD<=DATA(0 to 7);
end if;
Besides assigning to 'REG_DRV_HEAD' you're also assigning all data bits
of 'DATA' to 'Z'. Now take a look at the sensitivity list and you'll
see that 'DATA' is in the list (as it should be given the way you've
written the process). From the waveforms it would appear that your
testbench does not actively drive the 'DATA' I/O signals (forced I'm
assuming??) so the 'Z' does not get overridden as it would be if
anything else was actually assigning to it. So now the process gets
triggered again this time with 'DATA' equal to 'Z' which then causes
'REG_DRV_HEAD' to be assigned a 'Z'.

As a totally separate aside, if this is intended for synthesis in an
actual device you should probably consider using a synchronous process
(either free running clock or use 'WR' if the edge quality on that
signal is adequate) for computing ''REG_DRV_HEAD' otherwise you'll
probably find yourself fighting issues with latches that work great in
simulation but generally not so hot in real hardware in many
CPLD/FPGAs.

KJ
 
randomdude@gmail.com wrote:

process(RD, WR, RST
,DATA, csda, REG_STATUS_DATA, sectorbuf_data )
begin

if (RST='0') then
-- reset condition
REG_DRV_HEAD(REG_DRV_HEAD_DRV) <='0';
DATA<=(others=>'Z');
elsif (rd='0') then
-- read strobe
if REG_DRV_HEAD(REG_DRV_HEAD_DRV)='0' then -- are we selected?
if csda=IDE_REG_R_DATA then
sectorbuf_nextbuf<='0';
data(0 to 15)<=sectorbuf_data;
else
sectorbuf_nextbuf<='1';
end if;
else
DATA<=(others=>'Z');
end if;
elsif wr='0' then
-- write strobe
DATA<=(others=>'Z');
if IDE_REG_DRV_HEAD=csda then
REG_DRV_HEAD<=DATA(0 to 7);
end if;
else
-- bus idle
DATA<=(others=>'Z');
end if;
end process;
Hmm .. do you really want to model latches? I like latches very much,
but one has to be very careful using them. Your latches here most likely
lead to the muxed latch problem.

What is the muxed latch problem? If you have a latch and a mux, that
selects the input of the latch you have to take care, that the
enable-signal for the latch must not control the mux too. If you violate
this rule then while deactivating the enable-signal the mux may change
too and the latch may see a new value at its inputs before it is really
closed. This is similar to violating the data-to-clock hold-time of a
flipflop.

-> Model combinational logic (assign a value in every possible to your
signals) or make it synchronous (build flipflops). If you really want to
have latches, think about uncoupling the latch-enable and the mux-selector.

Ralf
 
KJ wrote:
The process to compute signal 'REG_DRV_HEAD' should be all by itself
and in no way a function of RD, strip out the assignment to everything
other than 'REG_DRV_HEAD' and move them to a separate process.
Something like...

if (RST='0') then
Do the reset stuff here
elsif wr='0' then
Assign the signal from the appropriate data bits here
end if;

The assignment to drive 'DATA' should be in either a separate process.
This is what I tried first (if I understand you right?) It did seem
like a much cleaner approach but I couldn't get it to work. The thing
is, I have some registers that need to be modified both in write and
read (eg. I need to write a register and them inc it on reads). Before
I had something along the lines of

process(wr)
begin
if rising_edge(wr)
(assign to appropiate place)
end if
end process

process(rd)
begin
if falling_edge(rd)
if ( reg_drv_head checks ) then
(assign to appropiate place)
end if;
end if
end process

which I *belive* is the 'standard' way of doing it? I just had some
(major) problems with accessing registers from both. :/

From the waveforms it would appear that your
testbench does not actively drive the 'DATA' I/O signals
It does.. just not till the rising edge of WR. So an X should get
written then data should..?

Thanks, both of you :)
 
This is what I tried first (if I understand you right?)
It sounds like you understood right.

The thing
is, I have some registers that need to be modified both in write and
read (eg. I need to write a register and them inc it on reads).
And you can't use two processes to do this since this would mean that
the register would be an output of two processes which from your
description I think would mean that no matter what you did you couldn't
get those registers to be initialized via the WR signal or
increment...assuming that both processes used RST to initialize them
then that's probably all that you could do.

You have to get all the assignments for a particular read/write port
down into a single process so you have two choices off the top of my
head then:

1. Use some free running clock signal that is faster than the pulse
width of RD or WR (typically the clock would need to be at least twice
as fast...i.e. if WR and RD are active for 100 ns minimum then you
would need to have a 50 ns clock in order to catch that pulse. Sync up
the WR and RD signals and then feed the synced up signals into a
process. On the data path the simplest approach is probably to have a
temporary holding register that simply clocks DATA on the falling edge
of WR (totally independent of addressing or anything) and then feed
that into your process. That will insure that the data fed into the
process to actually initialize your registers does not start changing
at the tail end of WR even if the external DATA signals do since your
register update is occurring whenever the synced up WR signal is
active. If you know that DATA won't be changing after WR goes away
then you might not need this additional holding register. Another
common approach is to generate a little one clock cycle wide signal by
delaying WR by 3 clocks and look for the leading edge of WR by looking
for when the 'delayed by 2' is active but 'delayed by 3' isn't. The
output of the first flop isn't used (other than to feed into flop #2)
since it is potentially metastable.

2. Or together the WR and RD signals somewhere to create a signal that
can be used as a clock to your process. Depending on what your target
technology is for all of this this might not be feasible if a reliable
clock signal can not be generated internally to the device.

It does.. just not till the rising edge of WR. So an X should get
written then data should..?
Yes.

KJ
 
KJ wrote:
This is what I tried first (if I understand you right?)

It sounds like you understood right.

The thing
is, I have some registers that need to be modified both in write and
read (eg. I need to write a register and them inc it on reads).

And you can't use two processes to do this since this would mean that
the register would be an output of two processes which from your
description I think would mean that no matter what you did you couldn't
get those registers to be initialized via the WR signal or
increment...assuming that both processes used RST to initialize them
then that's probably all that you could do.

You have to get all the assignments for a particular read/write port
down into a single process so you have two choices off the top of my
head then:

1. Use some free running clock signal that is faster than the pulse
width of RD or WR (typically the clock would need to be at least twice
as fast...i.e. if WR and RD are active for 100 ns minimum then you
would need to have a 50 ns clock in order to catch that pulse. Sync up
the WR and RD signals and then feed the synced up signals into a
process. On the data path the simplest approach is probably to have a
temporary holding register that simply clocks DATA on the falling edge
of WR (totally independent of addressing or anything) and then feed
that into your process. That will insure that the data fed into the
process to actually initialize your registers does not start changing
at the tail end of WR even if the external DATA signals do since your
register update is occurring whenever the synced up WR signal is
active. If you know that DATA won't be changing after WR goes away
then you might not need this additional holding register. Another
common approach is to generate a little one clock cycle wide signal by
delaying WR by 3 clocks and look for the leading edge of WR by looking
for when the 'delayed by 2' is active but 'delayed by 3' isn't. The
output of the first flop isn't used (other than to feed into flop #2)
since it is potentially metastable.

2. Or together the WR and RD signals somewhere to create a signal that
can be used as a clock to your process. Depending on what your target
technology is for all of this this might not be feasible if a reliable
clock signal can not be generated internally to the device.

It does.. just not till the rising edge of WR. So an X should get
written then data should..?
Yes.

KJ
OK, cool. Thanks a lot, I'll mull this over and play with the options.
Thanks for your advice :)

-Alan
 

Welcome to EDABoard.com

Sponsor

Back
Top