Q: |
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:
while (*(unsigned char *)0x600017 != 255);
But, the calculator freezes. I tried to use peek macro, as in
while (peek (0x600017) != 255);
No fortune again (I know that this is, in fact, the same as above). What is wrong?
|
A: |
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 volatile 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
while (*(volatile unsigned char *)0x600017 != 255);
Starting from TIGCCLIB 2.3, a new macro peekIO is introduced,
to make life easier. You can do
while (peekIO (0x600017) != 255);
Basically, peekIO works exactly like peek, but prevents any unwanted optimizations
generated by the compiler. Always use peekIO
(or peekIO_w) for reading memory-mapped I/O ports, else you may have
troubles. The _rowread function in TIGCCLIB releases prior to 2.3 also
caused similar troubles, now this is corrected too.
peekIO may be used even for reading bytes into the memory, but peek
will generate better code when working with memory. However, use peekIO 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).
Note: For sending bytes to I/O ports, the macros pokeIO and
pokeIO_w are also introduced, which are more reliable for
this purpose than poke and poke_w.
|