Relative Addressing and Position Independence (Microcontrollers)

3.3
The microcomputer is very much like any other computer; however, the use of ROMs in microcomputers raises an interesting problem that is met by the last mode of addressing that we discuss. The problem is that a program may be put in a ROM such that the
Simplified Control Hardware for Relative Addressing
Figure 3.8. Simplified Control Hardware for Relative Addressing
program starts at location $1000 and ends at $2000. Suppose that someone buys this ROM, but his/her microcomputer has another program in a ROM that starts at location $1000 and ends at $2000. We would like to be able to use this new ROM so thai the new program would start at location $4000 and end at location $5000, for instance, or wherever there is room in the address space of the microcomputer. However, because the program is in a ROM, it cannot be changed by the buyer. Similarly, a compiler or assembler that downloads a particular program into different parts of memory won’t have to change addresses if the program is position independent. A program that works the same way, wherever it is loaded in memory, is said to be position independent. Position independent programs can be written by an assembler or compiler to run anywhere in memory without modification. Programs we have seen so far are position independent when the location of the data is fixed, and, in fact, most program segments that do not use JMP or JSR instructions using direct addressing are position independent.
Program counter relative addressing, or simply relative addressing, adds a two’s-complement number, called a relative offset, to the value of the program counter to get the effective address of the operand. Figure 3.8 illustrates a simplified implementation of a controller. The top switch can add “1,” or the sign-extended data bus, to the program counter. The former is used to increment the program counter each time an instruction byte is fetched, and the latter is used for relative branches. The bottom switch permits the adder’s output or the data bus value to be put into the program counter. The bottom switch selects the latter when a jmp , jsr, rts, or rti instruction or interrupt loads the program counter. The adder’s output can also be used as an effective address.
The relative addressing mode is used to implement position independence. If the program segment at $1000 to $2000 was in a ROM and that ROM was installed so that the instruction following the bke was at $4000, the bne instruction would still have the relative offset $20. If Z is 0 when the instruction is executed, the program counter would be changed to $4020. That would be the address of the instruction that had the label L. The program would execute the same way whether it was stored at location $1000 or $4000. This makes the program position independent.
Branching instructions all use relative addressing. For example, the instruction bra l for “branch always” to location L will cause the program counter to be loaded with the address L, An example of a branch is illustrated in Figure 3.9. Observe that label L is two bytes below the end of the bra l instruction. The program counter PC has the address $834 of the next instruction, ldaa #4, when it is executing the bra l instruction. The second byte of the bra l instruction, the offset, 2, is added to the program counter, to make it $836, and then the next byte is fetched.
Program Segment Using BRA, Illustrating Position Independence
Figure 3.9. Program Segment Using BRA, Illustrating Position Independence
The example in Figure 3.10 constantly flips bits in location 1. It might be used in topic 12; location 1 is an output port, and this program segment outputs a square wave on all the bits. The two’s-complement offset is negative because the branch is backwards. Observe that, after BRA L is fetched, the program counter is on location $816; the offset $FB is -5, so the program counter becomes $811 after it is executed.
Many programmers have difficulty with relative branch instructions that branch backwards. We recommend using sixteen’s complement arithmetic to determine the negative branch instruction displacement. The sixteen’s complement is to hexadecimal numbers as the two’s complement is to binary numbers. To illustrate this technique, the displacement used in the branch instruction, the last instruction in the program in Figure 3.10, can be determined as follows. When the branch is executed, the program counter has the value $816, and we want to jump back to location $811. The difference. $816-S8I1, is $05, so the displacement should be -$05. A safe way to calculate the displacement is to convert to binary, negate, then convert to hexadecimal. Because $5 is 00000101, the two’s complement negative is 11111011. In hexadecimal, this is $FB. That is not hard to see, but binary arithmetic gets rather tedious. A faster way takes the sixteen’s complement of the hexadecimal number. Just subtract each digit from $F (15), digit by digit, then add 1 to the whole thing. Then -$05 is ($F – 0),($F – 5) + \ or SFA + 1, which is $FB. That’s pretty easy, isn’t it!
If the relative offset is outside the 8-bit range, one uses the long branch equivalent. lbra l, which uses a 16-bit two’s-complement relative offset.
Program counter relative addressing can be used to read (constant) data that should be stored with the program. Relative addressing can be implemented using a 5-bit, 9-bit, or 16-bit signed relative offset. Nine-bit offset relative addressing is denoted by the “<” before and “, PCR” after the offset and 16-bit offset by “>”‘ symbol before and “, PCR” after the offset. (This mode’s machine code uses a post byte as it is an index option.)
Program Segment to Put a Square Wave on an Output Port
Figure 3.10. Program Segment to Put a Square Wave on an Output Port
For example,
tmp33-75_thumb
can load any word into A that can be reached by adding an 8-bit signed number to the program counter. (Recall that the PC is pointing to the next instruction just below the LDAA instruction when the effective address L is calculated.) The instruction
tmp33-76_thumb
can be used to access words that are farther away than -128 to + 127 locations from the address of the next instruction; it adds a 16-bit offset to the current value of the program counter to get the effective address. Although the machine coding of relative addressed instructions is the same as that of index addressed instructions, do not dwell too much on that similarity because the offset put in the machine code is determined differently.
Program counter relative indirect addressing can be used to access locations such as I/O ports as in
tmp33-77_thumb
Assuming that L is 18 bytes below this instruction, the machine code is given by
tmp33-78_thumb
where $A6 is the opcode byte for any LDAA index mode; the post byte $FB indicates indirect index addressing with 16-bit offset, but using the program counter as the “index register”, and the last two bytes are added to the program counter. The indirect address ($12 in the example above) is in a location relative to the program. If the program is loaded into a different location, the offset $12 is still used to get the indirect address. Such use of relative and indirect relative addressing lets the program have one location and only one location where a value is stored, so that a downloaded file can insert the value in one place to run the program anywhere it is stored.
Branch and long branch instructions do not need the “,PCR” symbol in the instruction because they only use relative addressing with 16-bit relative offsets. However, the BSR L, having an 8-bit offset, doesn’t have a corresponding long branch to subroutine. But JSR L,PCR is a 16-bit position independent subroutine call that has the same effect as the missing LBSR L.
A 16-bit position independent indirect subroutine call, JSR [ L, PCR ], can jump to a subroutine whose address is in a “jump table,” as discussed in a problem at the end of this topic. Such jump tables make it possible to write parts of a long program in pieces called sections and compile and write each section in EEPROM at different times. Jumps to subroutine in a different section can be made to go through a jump table rather than going directly to the subroutine. Then when a section is rewritten and its subroutines appear in different places, only that section’s jump table needs to be rewritten, not all the code that jumps to subroutines in that section. The jump table can be in EEPROM at the beginning of the section, or in RAM, to be loaded at run time.
A program is not position independent if any instruction in it causes it to do something different when the program is moved, intact, to a different location. The only real test for a program’s position independence is to show that it can be moved without changing its operation. One necessary condition, however, is that all changes to the program counter be position independent, and using branch instructions in place of jump instructions, or JMP and JSR instructions with program counter relative addressing, will generally make that possible. The relative addressing mode is generally used with data that move with the program, such as constants that are on the same ROM as the program, and with instructions that compute the address to jump to in a manner to be introduced later. Listed with other instructions, then, the relative mode allows programs to be position independent, and that may be very important in a microcomputer that uses a lot of ROMs.


Next post:

Previous post: