FPGARelated.com
Forums

UART RS232 "hello world" program trial and terror.

Started by jleslie48 January 28, 2009
On Jan 29, 4:38=A0am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
> On Wed, 28 Jan 2009 11:56:48 -0800 (PST), jleslie48 wrote: > >constant TstData : string(0 to 15) :=3D "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 > =A0 =A0type string is array (positive range <>) of character; > and "positive" is > =A0 =A0subtype positive is integer range 1 to INTEGER'HIGH; > > So a string indexed from 0 is technically illegal. =A0I'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.
No, Jonathan (the other one) did it correctly. I haven't worked with strings since the last time I did a test bench and I forgot about the indexing, or maybe I have never tried to index a string and just didn't know. Come to think of it, I am pretty sure I have never needed to index into a string. It would really bug me to have to use 1 based indexing for strings in synthesized code. But like I was saying elsewhere, optimization really should be left for the cases where it is worth the cost.
> You can write > =A0 constant TstData: string (1 to 16) :=3D ... > or even (eccentrically) =A0 > =A0 ... 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: > =A0 constant TstData: string :=3D "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: > > =A0 signal StrPtr: integer range TstData'range; > =A0 ... > =A0 =A0 =A0if reset =3D '1' then > =A0 =A0 =A0 =A0StrPtr <=3D TstData'low; > =A0 =A0 =A0elsif rising_edge(clock) then > =A0 =A0 =A0 =A0 if (it's time to increment the pointer) then > =A0 =A0 =A0 =A0 =A0 if StrPtr =3D TstData'high then > =A0 =A0 =A0 =A0 =A0 =A0 =A0StrPtr <=3D TstData'low; > =A0 =A0 =A0 =A0 =A0 else > =A0 =A0 =A0 =A0 =A0 =A0 =A0StrPtr <=3D StrPtr + 1; > =A0 =A0 =A0 =A0 =A0 end if;
Do you know how this will synthesize? If my string is 1 to 4, will the counter be two bits or three? I think I know the answer, it will be three. Otherwise the hardware would not match the simulation. Good thing I don't normally use strings in synthesis. Rick
On Jan 29, 5:03=A0am, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
> Andreas Ehliar <ehliar-nos...@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 readin=
g
> >>> now.) ?Consider the following VHDL code: > > (previous snip of verilog code) > > I believe verilog doesn't have this problem. =A0You will get X > if you use Z with most operators. =A0&& and || will not give > X if the other operand is 0 or 1 respectively, but that should > also synthesize correctly.
I believe the same is true for VHDL. But the code above is not using an operator. It is using a conditional assignment based on an IF. o2_int <=3D '1'; if o1_int =3D '1' then o2_int <=3D '0'; end if; The IF evaluates the signal literally. If it is a '1', then o2_int gets '0'. If it is ***any*** other value o2_int retains '1'.
> > <snip> > >> The only time I can think of using a tristate internally in an FPGA is > >> when very old code is being reused. =A0In that case I would expect the > >> code to be rewritten to replace the tristate buffers with > >> multiplexers. =A0Has this come up in your career? > > Multiplexers, or AND/OR logic. =A0But if the logic is easier > to describe in tristate form, that should be fine. =A0
I would not use tristate logic, partly because of the problem Andreas points out, but mainly because it can be confusing and misleading. I think it is much better to change the code to match the current devices than to retain the code in an obsolete form. I don't think there are any issues of "but this code works"! If you are porting it to a new device and most likely new tools, it has to be verified from scratch anyway. So fixing the out of date code would not add significantly to the cost.
> > 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-state=
s
> > to regular logic automatically and thought that was pretty neat. But th=
e
> > text that told them that the synthesis tool could do this probably neve=
r
> > warned them about simulation/synthesis mismatch. (I could also rant abo=
ut
> > the FPGA book they had borrowed from the library which had a UART examp=
le
> > 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). =A0That would > need separate send/receive clocks.
There is no reason why that would require different speed clocks; different speed clock enables maybe, but it can and should run on a single clock unless there is some compelling reason not to.
> > 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 modellin=
g
> > something you believe that the synthesis tool will probably be able to > > translate into the thing you want.
The voice of reason... Rick
On Thu, 29 Jan 2009 03:48:56 -0800 (PST), rickman wrote:

>No, Jonathan (the other one) did it correctly.
Rick, please check your facts. The line of code constant S: string (0 to 3) := "0123"; WILL NOT COMPILE in any standards-compliant tool. I can believe that some synthesis tools bend the rules and permit 0-based indexing of strings, but they should not.
>It would really bug me to have to use >1 based indexing for strings in synthesized code.
It bugs me too, but rules is rules. It is quite unusual to use strings in synthesis, partly because some older synthesis tools didn't handle CHARACTER data, but it works now in all the tools I've seen, so no reason why we shouldn't go ahead - correctly.
>optimization really should be left for the cases >where it is worth the cost.
It's nothing to do with optimization; if the code is illegal, optimization doesn't happen. [snip legal example]
>Do you know how this will synthesize? If my string is 1 to 4, will >the counter be two bits or three? I think I know the answer, it will >be three.
I completely agree with you. If you are so desperate to have a counter that's one bit shorter, you could easily define your own new string type type stringZ is array (natural range <>) of character; and use that - but, of course, you would then lose all the built-in TEXTIO functionality that is so useful in testbenches. -- 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.
On Jan 29, 12:35 am, rickman <gnu...@gmail.com> wrote:
> 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
~ Yeah, I have no idea why the change you made to add init_done would ~ have gotten rid of the "multiple line drive" error. I didn't expect it to work for similar reasons you expected it to fail. It was just my first attempt, It was nothing more than a software persons first thought at a solution, a mutex. Logically correct, but I was doubtful whether it was synthesizable. Your solution is much better: ~ TX_DATA_IN <= TxNxtData when (init_done = '0') else RX_DATA_OUT ; this way TX_DATA_in is driven by a single mechanism. ~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... Again a good idea (both of them) Testbench and ISE is being a stubborn cluck, I'm still fighting with it. I posted another thread on that dragon to slay. I did commandeer another testbench program and got it to start. It actually "crashed" when I launched it on an array out of bounds error. That was quite useful actually. I had txcntr declared wrong: signal TxCntr : integer range 0 to 17; instead of the correct: signal TxCntr : integer range 1 to 17; that 0 value must of made its way to the index of the string which got mad. it's been a long time (since pascal) that a language did that. It was like a welcome friend. Meantime that testbench was designed for Modelsim, and the system_clock didn't even work. I'm still annoyed that the new source wizard is not doing anything. To be continued...
On Thu, 29 Jan 2009 09:38:39 +0000, Jonathan Bromley
<jonathan.bromley@MYCOMPANY.com> wrote:

>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.
XST is indeed surprisingly permissive where it can "understand" in hardware terms, something technically illegal. (Or thinks it can...) I suspect the thinking behind it is "we don't need to run those checks, because the source has obviously already passed simulation". Which is OK if you actually use it that way... - Brian
On Thu, 29 Jan 2009 03:13:16 +0000 (UTC), Andreas Ehliar
<ehliar-nospam@isy.liu.se> wrote:

>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.)
Well worth making the warning; it's difficult to know how much detail to load onto the poor guy! but he seems to take it in his stride... Just to add an alternative take on your warning, which will show why I didn't give it - in your example
> o1_int <= foo1 when sel1 = '1' else 'Z'; > o1_int <= foo2 when sel2 = '1' else 'Z';
the problems really arise because your "sel" conditions may not be complete and mutually exclusive; hence you drive o1_int with 0, 1 or 2 sources... if you arrange complete and mutually exclusive sel conditions (for example, "a" and "not a") you really don't need to worry. - Brian
On Thu, 29 Jan 2009 09:38:39 +0000, Jonathan Bromley
<jonathan.bromley@MYCOMPANY.com> wrote:

Forgot to say...

"jleslie" - watch this bit...

>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; > ...
Nice example of using the type system to do ITS work (not your work!) for you. - Brian
On Jan 29, 9:40 am, Brian Drummond <brian_drumm...@btconnect.com>
wrote:
> On Thu, 29 Jan 2009 09:38:39 +0000, Jonathan Bromley > > <jonathan.brom...@MYCOMPANY.com> wrote: > > Forgot to say... > > "jleslie" - watch this bit... > > > > >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; > > ... > > Nice example of using the type system to do ITS work (not your work!) > for you. > > - Brian
NIce. I know I have a lot of cleaning up to do.
On Jan 29, 4:38 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
> 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.brom...@MYCOMPANY.comhttp://www.MYCOMPANY.com > > The contents of this message may contain personal views which > are not the views of Doulos Ltd., unless specifically stated.
Oh yeah, I just glossed over a lot of the syntax errors when I first implemented Ricks code. there were a bunch (/= instead of <>, eg) and the synth saw the declaration 0 to xxx as bad and flagged it as such. Since wet behind the ears me was able to figure those out, I didn't bother wasting your all time with the syntax stuff. But I do love the compile time derived constants, like TstData'range, TstData'low, high, etc. They will make updates to strings much less cumbersome. Is there a list of all these "common" words/concepts somewhere online? I mean I have a bunch of pdf's that have these very formal lists of "reserved words" but all of them seem to be missing the "reserved" words of the libraries. For example none of the lists show "rising_edge" and "string". I know they are not technically "reserved" words but for all practical purposes, one uses this set of <?????> as reserved words. You have just introduced <variablename>'low, 'high, 'range, I also should of recognized 'event (as in system_clock'event) as a member of this superset of reserved words.
On Jan 29, 12:35 am, rickman <gnu...@gmail.com> wrote:
> 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. >
So glad your enjoying yourself :)))))) Rata-fracken,summana,friken,thing-a-mabob....