* E000:0000h 128K EPROM
*
**********************************************************************/
#define SRAM_BASE (void *) 0x00000000
#define SCC_BASE (void *) 0x70000000
#define SCC_INTACK (void *) 0x70001000
#define FLASH_BASE (void *) 0xC0000000
#define EPROM_BASE (void *) 0xE0000000
Pointers Versus AddressesIn both C and C++, the value of a pointer is an address. So when we say that we have a pointer to some data, we really mean that we have the address at which the data is stored. But programmers don't usually set or examine these addresses directly. The exception to this rule are the developers of operating systems, device drivers, and embedded software, who sometimes need to set the value of a pointer explicitly in their code.Unfortunately, the exact representation of an address can change from processor to processor or can even be compiler dependent. This means that a physical address like 12345h might not be stored in exactly that form, or might even be stored differently by different compilers. The issue that then arises is how a programmer can set the value of a pointer explicitly so that it points to the desired location in the memory map.
Most C/C++ compilers for 80x86 processors use 32-bit pointers. However, the older processors don't have a simple linear 32-bit address space. For example, Intel's 80188EB processor has only a 20-bit address space. And, in addition, none of its internal registers can hold more than 16 bits. So on this processor, two 16-bit registers-a segment register and an offset register are combined to create the 20-bit physical address. (The physical address computation involves left-shifting the contents of the segment register by four bits and adding the contents of the offset register to the result. Any overflow into the 21st bit is ignored.)
To declare and initialize a pointer to a register located at physical address 12345h we therefore write:
int * pRegister = (int *) 0x10002345;
where the leftmost 16 bits contain the segment value and the rightmost 16 bits contain the offset value.
For convenience, 80x86 programmers sometimes write addresses as segment:offset pairs. Using this notation, the physical address 12345h would be written as 0x1000:2345 . This is precisely the value sans colon that we used to initialize the pointer above. However, for each possible physical address there are 4096 distinct segment:offset pairs that point to a given physical address. For example, the pairs 0x1200:0345 and 0x1234:0005 (and 4093 others) also refer to physical address 12345h.
5.2.2 I/O Map
The I/O map for the arcom board is shown in Figure 5-3. It includes three devices: the peripheral control block (PCB), parallel port, and debugger port. The PCB is a set of registers within the 80188EB that are used to control the on-chip peripherals. The chips that control the parallel port and debugger port reside outside of the processor. These ports are used to communicate with the printer and a host-based debugger, respectively.
Figure 5-3. I/O map for the Arcom board
The I/O map is also useful when creating the header file for your board. each region of the I/O space maps directly to a constant, called the base address. The translation of the above I/O map into a set of constants can be found in the following listing:
/**********************************************************************
*
* I/O Map
*
* Base Address Description
* --------------- ----------------------------------------
* 0000h Unused
* FC00h SourceVIEW Debugger Port (SVIEW)
* FD00h Parallel I/O Port (PIO)
* FE00h Unused
* FF00h Peripheral Control Block (PCB)
*
**********************************************************************/
#define SVIEW_BASE 0xFC00
#define PIO_BASE 0xFD00
#define PCB_BASE 0xFF00
5.3 Learn How to Communicate
If polling is used, then the processor repeatedly checks to see if the task has been completed. This is analogous to the small child who repeatedly asks "are we there yet?" throughout a long trip. Like the child, the processor spends a large amount of otherwise useful time asking the question and getting a negative response. To implement polling in software, you need only create a loop that reads the status register of the device in question. Here is an example:
do {
// Play games, read, listen to music, etc.
// Poll to see if we're there yet.