[Main]
Title=I'm having troubles while reading I/O ports!

[Top]
<TABLE CELLPADDING="4"><TR><TD VALIGN="TOP"><B>Q:</B></TD><TD>
I have a lot of troubles while reading I/O ports. I need a loop which will wait until the
programable timer on the TI-89 reaches value 255. I know that I can read the value of the
programable timer counter using address 0x600017, so I made the following loop:
<PRE>while (*(unsigned char *)0x600017 != 255);
</PRE>
But, the calculator freezes. I tried to use <A HREF="$$LINK(peekpoke.h/peek)">peek</A> macro, as in
<PRE>while (peek (0x600017) != 255);
</PRE>
No fortune again (I know that this is, in fact, the same as above). What is wrong?
</TD></TR><TR><TD VALIGN="TOP"><B>A:</B></TD><TD>
See, there is a problem when reading I/O ports in small loops. Look at the above loop for
example. The compiler will notice that the same value is read again and again in the loop. As
normal memory location can not be changed without explicitly writing to it, and there is nothing
in the loop which changes the address 0x600017, the optimizer will move memory reading out of the
loop to make the code more efficient. Such behavior is correct for ordinary memory locations.
But, in our case, it will cause an infinity loop. The compiler does not know anything about the
fact that 0x600017 is not an ordinary memory location but an I/O port, which may be
changed unpredictably (purely by the hardware, without any program control). To prevent
such behaviour, you should use the <CODE>volatile</CODE> keyword to make the address 'volatile',
i.e. to say to the compiler that this address may be changed unpredictably. So, the correct
code is
<PRE>while (*(volatile unsigned char *)0x600017 != 255);
</PRE>
Starting from TIGCCLIB 2.3, a new macro <A HREF="$$LINK(peekpoke.h/peekIO)">peekIO</A> is introduced,
to make life easier. You can do
<PRE>while (peekIO (0x600017) != 255);
</PRE>
Basically, peekIO works exactly like <A HREF="$$LINK(peekpoke.h/peek)">peek</A>, but prevents any unwanted optimizations
generated by the compiler. Always use <A HREF="$$LINK(peekpoke.h/peekIO)">peekIO</A>
(or <A HREF="$$LINK(peekpoke.h/peekIO_w)">peekIO_w</A>) for reading memory-mapped I/O ports, else you may have
troubles. The <A HREF="$$LINK(kbd.h/_rowread)">_rowread</A> function in TIGCCLIB releases prior to 2.3 also
caused similar troubles, now this is corrected too.
<BR><BR>
<A HREF="$$LINK(peekpoke.h/peekIO)">peekIO</A> may be used even for reading bytes into the memory, but <A HREF="$$LINK(peekpoke.h/peek)">peek</A>
will generate better code when working with memory. However, use <A HREF="$$LINK(peekpoke.h/peekIO)">peekIO</A> to read any memory
location which may change in a way which is unpredictable from the aspect of a normal program
flow (for example, a memory location which is changed in the body of the interrupt handler).
<BR><BR>
<B>Note:</B> For sending bytes to I/O ports, the macros <A HREF="$$LINK(peekpoke.h/pokeIO)">pokeIO</A> and
<A HREF="$$LINK(peekpoke.h/pokeIO_w)">pokeIO_w</A> are also introduced, which are more reliable for
this purpose than <A HREF="$$LINK(peekpoke.h/poke)">poke</A> and <A HREF="$$LINK(peekpoke.h/poke_w)">poke_w</A>.
</TD></TR></TABLE>
