I'm _damn_ confused.

Discussion in 'VHDL' started by randomdude@gmail.com, Jul 5, 2006.

  1. 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
     
    , Jul 5, 2006
    #1
    1. Advertising

  2. KJ Guest

    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
     
    KJ, Jul 5, 2006
    #2
    1. Advertising

  3. 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
     
    Ralf Hildebrandt, Jul 5, 2006
    #3
  4. Guest

    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 :)
     
    , Jul 5, 2006
    #4
  5. KJ Guest


    > 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, Jul 5, 2006
    #5
  6. Guest

    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
     
    , Jul 5, 2006
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. DJ Miller

    Confused and bewildered.

    DJ Miller, Jul 31, 2003, in forum: ASP .Net
    Replies:
    4
    Views:
    1,103
    DJ Miller
    Sep 4, 2003
  2. RichGK
    Replies:
    1
    Views:
    408
    SStory
    Jul 31, 2004
  3. Cobra Pilot

    Confused. Need Help!

    Cobra Pilot, Jul 22, 2003, in forum: Perl
    Replies:
    1
    Views:
    989
    Shawn Corey
    Jul 22, 2003
  4. Sean Berry

    Confused on using basename...

    Sean Berry, Apr 14, 2004, in forum: Perl
    Replies:
    1
    Views:
    530
    Joe Smith
    Apr 14, 2004
  5. John
    Replies:
    0
    Views:
    287
Loading...

Share This Page