FPGARelated.com
Forums

UART RS232 "hello world" program trial and terror.

Started by jleslie48 January 28, 2009
Ok,

continuing with the RS232 and Ricks pseudo code for sending out a 16
character message:
--------------------------------------------------------------------------------
constant TstData : string(0 to 15) := "Testing 1, 2, 3!";
signal TxCntr : integer range 0 to 16;

TxNxtData <= TstData (TxCntr);

-- Data source control, provide string data to the UART, repeat every
16 chars
process SelectCntr ( clk, reset ) is
begin
  if (reset = '1') then
    TxCntr <= 0;
  elsif ( rising_edge (clk) ) then
    if ( TxRdy = '0' ) then
      TxWrite <= '0';
    else
      if ( TxWrite = '0' and TxCntr <> 16 ) then
        TxWrite <= '1';
        TxCntr <= TxCntr + 1;
      end if;
    end if;
  end if;
end process;

---------------------------------------------------------------------------------


I cleaned this up a bit, used my variable names,  to get a synth to
work:
----------------------------------------------------------------------


  function to_slv(c: character) return std_logic_vector  is
  begin
    return std_logic_vector(to_unsigned(character'pos(c), 8));
  end;



  SIGNAL system_startup  : STD_LOGIC  := '1';
  SIGNAL txwrite         : STD_LOGIC  := '1';
  SIGNAL txrdy           : STD_LOGIC  := '0';
  SIGNAL TxNxtData       : STD_LOGIC_VECTOR( 7 downto 0 );
  SIGNAL init_done       : STD_LOGIC  := '0';
  signal TxCntr          : integer range 0 to 17;

  constant TstData : string(1 to 16) := "Testing 1, 2, 3!";


    TxNxtData <= to_slv(TstData(TxCntr));



-- Initialize01
--
-- Lets put out a hello world message once when the system first
starts up,
--
-- system_startup, init_done are flags to start the run and signal th
end.
-- txrdy and txwrite, do some ping_pong thing to get the chars out I
think.
-- lets see.
--
initialize01: process ( CLK_16_6MHZ, system_startup )
begin
  if (system_startup = '1') then --1{
    TxCntr         <= 1;
    system_startup <= '0';
    init_done      <= '0';
    TxRdy          <= '0';
  elsif ( rising_edge (CLK_16_6MHZ) ) then    --1
    if ( TxRdy = '0' ) then   --5{
      TxWrite <= '0';
    else
      if ( TxWrite = '0' and TxCntr /= 17 ) then --4{
        TxWrite <= '1';
        TxRdy <= '0';
        TxCntr <= TxCntr + 1;
        if (init_done = '0') then  --3{
          TX_DATA_IN <= TxNxtData  ;
          end if;  --3}
      elsif (TxCntr = 17) then  --4
         init_done <= '1';
      end if; --4}
    end if;   --5}
  end if; --1}
end process initialize01 ;
----------------------------------------------------------------------

the act of getting through the syntax errors was very useful,
particularly since
when I added the >>>TX_DATA_IN <= TxNxtData  ;<<< line
I got 8 errors relating to "multiple line drive" or something to that
effect.

Well you guys beat it into my head enough times, and instantly
realized that and I had
two wires hooked up to TX_DATA_IN that could both send in signals at
the same time, and
that would be a no-no.  That is when I added the "init_done" boolean
both here and in the
regular transmission producer, process p7 which I renamed to the more
appropriate, uart_echo:
________________________

--p7
uart_echo:  PROCESS ( CLK_16_6MHZ, UART_RESET_BUFFER,
RX_READ_BUFFER_STB, RX_DATA_OUT( 7 DOWNTO 0 )  )
BEGIN
     IF ( CLK_16_6MHZ = '1' AND CLK_16_6MHZ'EVENT ) THEN
          IF ( UART_RESET_BUFFER = '0' ) THEN
               IF ( RX_READ_BUFFER_STB  = '1' ) THEN
                    if ( init_done = '1') then
                         TX_DATA_IN  <= RX_DATA_OUT;
                         end if;
               END IF;
          END IF;
     END IF;
END PROCESS uart_echo;
__________________________

note the TX_DATA_IN line is now dependent on the init_done flag.

well then after being all proud of my synth coming up clean (well no
errors, and 23 warnings, I didn't say spotless...) I actually took the
plunge and loaded up my board and ran it.

Yuck.

no hello world message, and even the uart_echo is now broken.

So, taking the advise I was given here, its time to testbench this
puppy and see what all my system_startup, init_done, etc are doing.
Lets see if I can make up a good testbench to this thing,

On Wed, 28 Jan 2009 11:56:48 -0800 (PST), jleslie48
<jon@jonathanleslie.com> wrote:

>Ok, > >continuing with the RS232 and Ricks pseudo code for sending out a 16 >character message:
[better code...]
>Well you guys beat it into my head enough times, and instantly >realized that and I had >two wires hooked up to TX_DATA_IN that could both send in signals at >the same time, and >that would be a no-no. That is when I added the "init_done" boolean >both here and in the >regular transmission producer,
Didn't you still have similar messages? Both processes still have drivers connected to TX_DATA_IN... You have started to arbitrate between them, but they are both still driving... unless you turn them off
> if ( init_done = '1') then > TX_DATA_IN <= RX_DATA_OUT;
else TX_DATA_IN <= (others -> 'Z');
> end if;
(and likewise in the other process. If you don't know what 'Z' means, look up "Tristate logic") or bring them both out on DIFFERENT signals TX_DATA_1 <= RX_DATA_OUT; and switch between them in a third process (can be purely combinational, as here - it's just a multiplexer) TX_DATA_IN <= TX_DATA_1 when init_done = '1' else -- other data source when other condition else TX_DATA_2; or combine both processes into one... NOTE - the first approach isn't actually supported in modern FPGAs. But you can safely use it - the tools do a good job of transforming it into the equivalent second approach.
>So, taking the advise I was given here, its time to testbench this >puppy and see what all my system_startup, init_done, etc are doing. >Lets see if I can make up a good testbench to this thing
Testbench is well worth doing... also consider bringing out "init_done< to an external pin - preferably with a LED on it... - Brian
On 2009-01-29, Brian Drummond <brian_drummond@btconnect.com> wrote:
> NOTE - the first approach isn't actually supported in modern FPGAs. > But you can safely use it - the tools do a good job of transforming it > into the equivalent second approach.
A word of warning regarding tristates (If you already know about how tristates can cause simulation/synthesis mismatch you can stop reading now.) Consider the following VHDL code: library ieee; use ieee.std_logic_1164.all; entity foo is port ( foo1 : in std_logic; foo2 : in std_logic; sel1 : in std_logic; sel2 : in std_logic; o1 : out std_logic; o2 : out std_logic ); end foo; architecture test of foo is signal o1_int : std_logic; signal o2_int : std_logic; begin -- test o1 <= o1_int; o2 <= o2_int; o1_int <= foo1 when sel1 = '1' else 'Z'; o1_int <= foo2 when sel2 = '1' else 'Z'; process (o1_int) begin -- process o2_int <= '1'; if o1_int = '1' then o2_int <= '0'; end if; end process; end test; When you simulate this o2_int will be set to 1 if o1_int is '0' or 'Z'. (or 'X' for that matter). But when you synthesize this things are different: ========================================================================= * Low Level Synthesis * ========================================================================= WARNING:Xst:2041 - Unit foo: 1 internal tristate is replaced by logic (pull-up yes): N5. WARNING:Xst:2039 - Unit foo: 1 multi-source signal is replaced by logic (pull-up yes): o1_MLTSRCEDGE. This means that 'Z' will correspond to a '1' in the FPGA. Which means that you will not get the same behavior in simulation as in hardware. (But don't depend on 'Z' being 1 either, depending on the synthesis tool it could be 0 as well, or don't care for that matter I guess.) If you use tristates correctly it is not a problem, but you need to be aware about this situation. Therefore, we don't recommend our students to use tristates internally. /Andreas
I have to say that I find your learning process to be very
interesting.  It has been so long for me that I have forgotten exactly
what it was that I had to learn or unlearn to switch from software to
HDL.  I am getting a feel for that again.


On Jan 28, 2:56 pm, jleslie48 <j...@jonathanleslie.com> wrote:
> Ok, > > continuing with the RS232 and Ricks pseudo code for sending out a 16 > character message: > -------------------------------------------------------------------------------- > constant TstData : string(0 to 15) := "Testing 1, 2, 3!"; > signal TxCntr : integer range 0 to 16; > > TxNxtData <= TstData (TxCntr); > > -- Data source control, provide string data to the UART, repeat every > 16 chars > process SelectCntr ( clk, reset ) is > begin > if (reset = '1') then > TxCntr <= 0; > elsif ( rising_edge (clk) ) then > if ( TxRdy = '0' ) then > TxWrite <= '0'; > else > if ( TxWrite = '0' and TxCntr <> 16 ) then > TxWrite <= '1'; > TxCntr <= TxCntr + 1; > end if; > end if; > end if; > end process; > > --------------------------------------------------------------------------------- > > I cleaned this up a bit, used my variable names, to get a synth to > work: > ---------------------------------------------------------------------- > > function to_slv(c: character) return std_logic_vector is > begin > return std_logic_vector(to_unsigned(character'pos(c), 8)); > end; > > SIGNAL system_startup : STD_LOGIC := '1'; > SIGNAL txwrite : STD_LOGIC := '1'; > SIGNAL txrdy : STD_LOGIC := '0'; > SIGNAL TxNxtData : STD_LOGIC_VECTOR( 7 downto 0 ); > SIGNAL init_done : STD_LOGIC := '0'; > signal TxCntr : integer range 0 to 17; > > constant TstData : string(1 to 16) := "Testing 1, 2, 3!"; > > TxNxtData <= to_slv(TstData(TxCntr)); > > -- Initialize01 > -- > -- Lets put out a hello world message once when the system first > starts up, > -- > -- system_startup, init_done are flags to start the run and signal th > end. > -- txrdy and txwrite, do some ping_pong thing to get the chars out I > think. > -- lets see. > -- > initialize01: process ( CLK_16_6MHZ, system_startup ) > begin > if (system_startup = '1') then --1{ > TxCntr <= 1; > system_startup <= '0'; > init_done <= '0'; > TxRdy <= '0'; > elsif ( rising_edge (CLK_16_6MHZ) ) then --1 > if ( TxRdy = '0' ) then --5{ > TxWrite <= '0'; > else > if ( TxWrite = '0' and TxCntr /= 17 ) then --4{ > TxWrite <= '1'; > TxRdy <= '0'; > TxCntr <= TxCntr + 1; > if (init_done = '0') then --3{ > TX_DATA_IN <= TxNxtData ; > end if; --3} > elsif (TxCntr = 17) then --4 > init_done <= '1'; > end if; --4} > end if; --5} > end if; --1} > end process initialize01 ; > ---------------------------------------------------------------------- > > the act of getting through the syntax errors was very useful, > particularly since > when I added the >>>TX_DATA_IN <= TxNxtData ;<<< line > I got 8 errors relating to "multiple line drive" or something to that > effect. > > Well you guys beat it into my head enough times, and instantly > realized that and I had > two wires hooked up to TX_DATA_IN that could both send in signals at > the same time, and > that would be a no-no. That is when I added the "init_done" boolean > both here and in the > regular transmission producer, process p7 which I renamed to the more > appropriate, uart_echo: > ________________________ > > --p7 > uart_echo: PROCESS ( CLK_16_6MHZ, UART_RESET_BUFFER, > RX_READ_BUFFER_STB, RX_DATA_OUT( 7 DOWNTO 0 ) ) > BEGIN > IF ( CLK_16_6MHZ = '1' AND CLK_16_6MHZ'EVENT ) THEN > IF ( UART_RESET_BUFFER = '0' ) THEN > IF ( RX_READ_BUFFER_STB = '1' ) THEN > if ( init_done = '1') then > TX_DATA_IN <= RX_DATA_OUT; > end if; > END IF; > END IF; > END IF; > END PROCESS uart_echo; > __________________________ > > note the TX_DATA_IN line is now dependent on the init_done flag. > > well then after being all proud of my synth coming up clean (well no > errors, and 23 warnings, I didn't say spotless...) I actually took the > plunge and loaded up my board and ran it. > > Yuck. > > no hello world message, and even the uart_echo is now broken. > > So, taking the advise I was given here, its time to testbench this > puppy and see what all my system_startup, init_done, etc are doing. > Lets see if I can make up a good testbench to this thing,
Yeah, I have no idea why the change you made to add init_done would have gotten rid of the "multiple line drive" error. If you make an assignment to a signal within a process, that is defining some sort of driver on that signal. If you make assignments to the same signal from two different processes, that puts two drivers on the same signal and creates a problem. This is another error of thinking like software rather than hardware. The fact that the two assignment statements are not made under the same conditions does not make this work any better. It is "describing" two registers with their outputs tied together and that will not work. You need a multiplexer to select either the test data or the receiver data register. Try replacing the uart_echo process with a concurrent statement... TX_DATA_IN <= TxNxtData when (init_done = '0') else RX_DATA_OUT ; Notice that I also removed the assignment to TX_DATA_IN from the initialize01 process. That was adding a register to the data path that is not needed. The character counter, TxCntr, provides a select value to control a mux on the character array. Actually, this logic is combined and optimized to produce the TxNxtData without actually having an array of chars and a mux, but that is not important. The output of this mux is appropriately timed by the changes in TxCntr so that it can directly drive the UART Tx input, TX_DATA_IN. Just as a matter of style, init_done also does not need to be in the clocked process. Any signal assigned in a clocked process produces a register. init_done only needs to be the decode of the state of TxCntr = 17. Or even simpler is to use 0 to 15 on the string constant and to use 16 as the terminal state which brings me to the use of integers. Again this is an issue of preference, but you can use signed or unsigned from the ieee.numeric_std package. These types are related to slv so that they can convert without a conversion function. They are arrays, so you can pick out individual bits. I have all but done away with integers myself. Then picking out the msb of TxCntr would be init_done <= TxCntr (4); as a concurrent assignment. A final thought. The dual assignment to TX_DATA_IN should be producing an error. It will cause an 'X' to be displayed on that signal in the simulator... or at least it should. It may be a 'U', I'm not certain. But it won't work correctly until you change the code. If you had to draw a diagram of the registers in this design, would you be able to do that? If you can do that, you can then use templates to produce the code to match the register descriptions with very few errors. Rick
On 2009-01-29, rickman <gnuarm@gmail.com> wrote:
> On Jan 28, 10:13&#4294967295;pm, Andreas Ehliar <ehliar-nos...@isy.liu.se> wrote: >> On 2009-01-29, Brian Drummond <brian_drumm...@btconnect.com> wrote: >> >> > NOTE - the first approach isn't actually supported in modern FPGAs. >> > But you can safely use it - the tools do a good job of transforming it >> > into the equivalent second approach. >> >> A word of warning regarding tristates (If you already know about how >> tristates can cause simulation/synthesis mismatch you can stop reading >> now.) &#4294967295;Consider the following VHDL code:
<snip>
> The only time I can think of using a tristate internally in an FPGA is > when very old code is being reused. In that case I would expect the > code to be rewritten to replace the tristate buffers with > multiplexers. Has this come up in your career?
Some students I supervised did this and had a very hard time debugging it. They had probably read somewhere that the tools could convert tri-states to regular logic automatically and thought that was pretty neat. But the text that told them that the synthesis tool could do this probably never warned them about simulation/synthesis mismatch. (I could also rant about the FPGA book they had borrowed from the library which had a UART example that had more than one clock IIRC... *GRR*) This is one of the reasons why I always try to warn people about this kind of issue whenever I see someone suggesting that it is ok to use tri-states inside an ASIC or FPGA because the tools can convert it to regular logic. The other reason is the same as the one you just described. It is probably much better to model what you really want rather than modelling something you believe that the synthesis tool will probably be able to translate into the thing you want. /Andreas
On 2009-01-29, glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote:
> There used to by systems with different transmit/receive speed > (modems with 75 baud one direction, 1200 the other). That would > need separate send/receive clocks.
I should perhaps acknowledge that it is non-trivial to write a UART if you don't have a clock which is significantly faster than the baud-rate. But in the case you quote you shouldn't have any problems since 1200 is an even multiple of 75. And if I remember correctly this example created an internal clock which was 16 times faster than the baud rate and then used that clock instead of using only one clock.
> >> This is one of the reasons why I always try to warn people about this >> kind of issue whenever I see someone suggesting that it is ok to use >> tri-states inside an ASIC or FPGA because the tools can convert it to >> regular logic. > > or use verilog.
You will have the same problem in Verilog: if (testsignal == 1) begin do_something; end do_something will not be run in simulation if testsignal is x or z, but in the hardware it may be activated depending on the synthesis tool. /Andreas
On Jan 28, 10:13=A0pm, Andreas Ehliar <ehliar-nos...@isy.liu.se> wrote:
> On 2009-01-29, Brian Drummond <brian_drumm...@btconnect.com> wrote: > > > NOTE - the first approach isn't actually supported in modern FPGAs. > > But you can safely use it - the tools do a good job of transforming it > > into the equivalent second approach. > > A word of warning regarding tristates (If you already know about how > tristates can cause simulation/synthesis mismatch you can stop reading > now.) =A0Consider the following VHDL code: > > library ieee; > use ieee.std_logic_1164.all; > entity foo is > > =A0 port ( > =A0 =A0 foo1 : in =A0std_logic; > =A0 =A0 foo2 : in =A0std_logic; > =A0 =A0 sel1 : in =A0std_logic; > =A0 =A0 sel2 : in =A0std_logic; > =A0 =A0 o1 =A0 : out std_logic; > =A0 =A0 o2 =A0 : out std_logic > =A0 =A0 ); > > end foo; > > architecture test of foo is > =A0 signal o1_int : std_logic; > =A0 signal o2_int : std_logic; > begin =A0-- test > > =A0 o1 <=3D o1_int; > =A0 o2 <=3D o2_int; > > =A0 o1_int <=3D foo1 when sel1 =3D '1' else 'Z'; > =A0 o1_int <=3D foo2 when sel2 =3D '1' else 'Z'; > > =A0 process (o1_int) > =A0 begin =A0-- process > =A0 =A0 o2_int <=3D '1'; > =A0 =A0 if o1_int =3D '1' then > =A0 =A0 =A0 o2_int <=3D '0'; > =A0 =A0 end if; > =A0 end process; > > end test; > > When you simulate this o2_int will be set to 1 if o1_int is '0' or 'Z'. > (or 'X' for that matter). > > But when you synthesize this things are different: > > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> * =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Low Level Synthesis =A0=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> WARNING:Xst:2041 - Unit foo: 1 internal tristate is replaced by logic (pu=
ll-up yes): N5.
> WARNING:Xst:2039 - Unit foo: 1 multi-source signal is replaced by logic (=
pull-up yes): o1_MLTSRCEDGE.
> > This means that 'Z' will correspond to a '1' in the FPGA. Which means tha=
t
> you will not get the same behavior in simulation as in hardware. (But don=
't
> depend on 'Z' being 1 either, depending on the synthesis tool it could be=
0
> as well, or don't care for that matter I guess.) > > If you use tristates correctly it is not a problem, but you need to be aw=
are
> about this situation. Therefore, we don't recommend our students to use > tristates internally.
Maybe I don't understand the significance of this. Tristates are *not* supported internally in FPGAs. You can use a tristate on an I/O pin, but I don't know of any modern FPGA families that use tristate drivers inside the FPGA. Why would anyone concern themselves with how the simulation and synthesis mismatch when you really shouldn't be using an internal tristate at all??? The only time I can think of using a tristate internally in an FPGA is when very old code is being reused. In that case I would expect the code to be rewritten to replace the tristate buffers with multiplexers. Has this come up in your career? Rick
On Wed, 28 Jan 2009 11:56:48 -0800 (PST), jleslie48 wrote:

>constant TstData : string(0 to 15) := "Testing 1, 2, 3!";
A VHDL language-lawyer thing that will probably hit you as soon as you try to use a professional-grade simulator: The built-in data type "string" is defined as type string is array (positive range <>) of character; and "positive" is subtype positive is integer range 1 to INTEGER'HIGH; So a string indexed from 0 is technically illegal. I'm a little surprised that the tools you've already tried allowed you to get away with it, but there's no doubt that synthesis tools (and particularly FPGA vendor tools) are a tad sloppy about things like that. You can write constant TstData: string (1 to 16) := ... or even (eccentrically) ... string (16 downto 1) ... but you must not include 0 in the subscript range. Note, too, that you don't need to specify the subscript range for an array constant: constant TstData: string := "Testing"; will automatically give TstData the range (1 to 7). You can then make your counter track the size of the constant automatically like this: signal StrPtr: integer range TstData'range; ... if reset = '1' then StrPtr <= TstData'low; elsif rising_edge(clock) then if (it's time to increment the pointer) then if StrPtr = TstData'high then StrPtr <= TstData'low; else StrPtr <= StrPtr + 1; end if; ... -- Jonathan Bromley, Consultant DOULOS - Developing Design Know-how VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK jonathan.bromley@MYCOMPANY.com http://www.MYCOMPANY.com The contents of this message may contain personal views which are not the views of Doulos Ltd., unless specifically stated.
Andreas Ehliar <ehliar-nospam@isy.liu.se> wrote:
 
> This means that 'Z' will correspond to a '1' in the FPGA. Which means that > you will not get the same behavior in simulation as in hardware. (But don't > depend on 'Z' being 1 either, depending on the synthesis tool it could be 0 > as well, or don't care for that matter I guess.)
Early FPGAs had internal tristate buffers. I believe with keepers on them such that they stay at the last level. Those don't scale well, though, so now the synthesis tools generate something else. If it is AND/OR logic then Z will come out as 0. FPGA tools like to move inverters around, so 1 is probably about as likely.
> If you use tristates correctly it is not a problem, but you need to > be aware about this situation. Therefore, we don't recommend > our students to use tristates internally.
You might as well generate AND/OR logic yourself. Though in converting an existing design (say a box full of 7400 series logic) it might be more consistent to keep them. -- glen
Andreas Ehliar <ehliar-nospam@isy.liu.se> wrote:
(snip)
>>> A word of warning regarding tristates (If you already know about how >>> tristates can cause simulation/synthesis mismatch you can stop reading >>> now.) ?Consider the following VHDL code:
(previous snip of verilog code) I believe verilog doesn't have this problem. You will get X if you use Z with most operators. && and || will not give X if the other operand is 0 or 1 respectively, but that should also synthesize correctly.
> <snip>
>> The only time I can think of using a tristate internally in an FPGA is >> when very old code is being reused. In that case I would expect the >> code to be rewritten to replace the tristate buffers with >> multiplexers. Has this come up in your career?
Multiplexers, or AND/OR logic. But if the logic is easier to describe in tristate form, that should be fine.
> Some students I supervised did this and had a very hard time debugging it. > They had probably read somewhere that the tools could convert tri-states > to regular logic automatically and thought that was pretty neat. But the > text that told them that the synthesis tool could do this probably never > warned them about simulation/synthesis mismatch. (I could also rant about > the FPGA book they had borrowed from the library which had a UART example > that had more than one clock IIRC... *GRR*)
There used to by systems with different transmit/receive speed (modems with 75 baud one direction, 1200 the other). That would need separate send/receive clocks.
> This is one of the reasons why I always try to warn people about this > kind of issue whenever I see someone suggesting that it is ok to use > tri-states inside an ASIC or FPGA because the tools can convert it to > regular logic.
or use verilog.
> The other reason is the same as the one you just described. It is > probably much better to model what you really want rather than modelling > something you believe that the synthesis tool will probably be able to > translate into the thing you want.
-- glen