![]() |
|
|
|
#1 |
|
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 randomdude@gmail.com |
|
|
|
|
#2 |
|
Posts: n/a
|
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 |
|
|
|
#3 |
|
Posts: n/a
|
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 |
|
|
|
#4 |
|
Posts: n/a
|
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 |
|
|
|
#5 |
|
Posts: n/a
|
> 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 |
|
|
|
#6 |
|
Posts: n/a
|
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 |
|