From: harold@harvax.UUCP (Harold Rabbie)
Subject: Memory-mapped I/O
Date: 16 Jan 90 17:58:51 GMT [thread overview]
Message-ID: <9001161758.AA17503@monolith.> (raw)
It seems that there is a misconception about the use of data representation
specifications to do memory mapped I/O in embedded systems. A lot of people
write code like:
type DEVICE_TYPE is range 0 .. 255;
for DEVICE_TYPE'SIZE use 8; -- some 8-bit hardware register
DEVICE_REGISTER : DEVICE_TYPE;
for DEVICE_REGISTER use at 16#1234#; -- memory mapped address
and then use Ada assignment statements with the object DEVICE_REGISTER to
do memory-mapped I/O. For example, on a bare Motorola 680X0 you do I/O by
accessing locations in the memory space. The object DEVICE_REGISTER is of
course a special piece of hardware inside the I/O device, and not a RAM
location at all.
The problem is that most compilers assume that data objects are stored in
RAM memory, and so they may do things that work fine in RAM, but are
inappropriate for device registers.
Many devices are sensitive to the size of access, whether 8, 16 or 32 bits
wide. Just because I give a SIZE representation clause to an object doesn't
guarantee that the compiler will emit a MOVE instruction of the specified
width when accessing that object. It's perfectly entitled to use whatever
instructions it deems appropriate, as long as it gets the right result in
normal RAM memory.
For example, if the device is located at an odd address, the generated code
might read the next lower even address and mask out the unnecessary bits.
That is a valid sequence for a RAM location, but probably wouldn't work on
an I/O device register.
Another behavior that works just fine for RAM is to initialize all of
memory to zero before the program starts. This could easily screw up many
devices.
I believe the right way to do physical I/O is through the LOW_LEVEL_IO
package defined in LRM 14.6. For example, you could define the package to
do memory-mapped I/O of different widths as follows:
package LOW_LEVEL_IO is
subtype DEVICE_TYPE is new SYSTEM.ADDRESS; -- for memory-mapped I/O
procedure SEND_CONTROL ( DEVICE : DEVICE_TYPE; DATA : in ....
procedure RECEIVE_CONTROL( DEVICE : DEVICE_TYPE; DATA : out ....
end LOW_LEVEL_IO;
The procedures SEND_CONTROL would do memory-mapped output and the
procedures RECEIVE_CONTROL would do memory-mapped input. You specify the
width (8, 16 or 32 bits) by the type of the DATA parameter.
Then you write the body of LOW_LEVEL_IO with machine-code insertion or
pragma INTERFACE( ASSEMBLER) to get the right instruction sequence. This
also has the benefit of portability to embedded architectures that do not
use memory-mapped I/O, for example, the Intel 80X86 family. And if your
compiler can inline assembly code, you're in fat city.
I'd be interested in hearing the opinions of the Ada community on this. If
people really want to do memory-mapped I/O with Ada assignment statements,
then somehow we'll have to tighten up the requirements on the code
generated by the compilers.
--------------------------+--------------------------------------------
Harold Rabbie, Ready Systems "when REAL_TIME => accept READY_SYSTEMS;"
UUNET: {sun!pyramid,hplabs}!harvax!harold ARPA: rabbieh@ajpo.sei.cmu.edu
--------------------------+--------------------------------------------
next reply other threads:[~1990-01-16 17:58 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
1990-01-16 17:58 Harold Rabbie [this message]
-- strict thread matches above, loose matches on Subject: below --
1990-01-18 14:19 Memory-mapped I/O "Norman H. Cohen"
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox