16. The Sparrowhawk Subset
Part of
the Hawk Manual
|
16.1. The Subset
16.2. Code Conversion
16.2.1. Converting LIL
16.2.2. Converting Memory Reference Instructions
Strictly speaking, many of the instructions in the Hawk instruction set are unnecessary. Omitting some of these instructions can greatly simplify the hardware.
The Sparrowhawk subset of the Hawk instruction set omits all 32-bit instruciton formats. Specifically, there are no long memory reference instructions (see Chapter 3), no long immediate instructions (see Chapter 4), and no coprocessor instructions (see Section 11.4).
Use of the opcodes assigned to these instructions on a Sparrowhawk processor results in an instruction trap (see Section 13.1. Operating systems on the Sparrowhawk may virtualize the missing instructions using an appropriate trap service routine, allowing Sparrowhawk processors to run aribtrary code written for the Hawk.
Most Hawk code can be converted to the Sparrowhawk subset by making local substitutions that replace single Hawk instrucitons with sequences of Sparrowhawk instructions that do the same thing. In some cases, this requires use of at most one temporary register; in these cases, if no register is available, additional changes to the original code are required.
Macro assemblers supporting the Sparrowhawk should provide macros for all of the Hawk instructions in the header file sparrowhawk.h. This provides a second avenue to virtualize the Hawk instruciton set on the Sparrowhawk.
Note that many of the substitutions needed to convert Hawk code to Sparrowhawk code occupy more memory. As a result, code that assembles correctly on the Hawk will not always assemble correctly with these substitutions. The reason is that the expanded code may push some PC-relative addresses out of bounds.
For LIL (see Chapter 4), replace:
LIL R5,CONST
With LIS followed by an zero or more ORIS instructions (see Section 5.2). In the general case, this gives:
LIS R5,(CONST>>16) ORIS R5,(CONST>> 8)&#FF ORIS R5,(CONST )&#FF
If the constant can be represented in 16 bits, this code suffices:
LIS R5,(CONST>>8) ORIS R5,(CONST )&#FF
Note that the above substitutions may be problematic when the constant being loaded is a value that will be modified by the linker when combining separately processed object files. For example, when the constant is used in one object file but defined in another. In this case, the best workable substitution involves replacing LIL R5,const with something like the following:
LOAD R5,WCONST ... WCONST: W CONST
In the above, note the following:
For memory reference instructions, a register must be used for effective address computation. Here, we will use r[1] as a temporary because this register is commonly used for subroutine linkage and therefore routinely unsafe to use for long-term operand storage.
Taking STORE as the prototypical memory reference instruction (see Chapter 3), we can replace:
STORE R5,R2,DISP
With an appropriate load immediate sequence (see Chapter 5) followed by an add (see Section 11.3) prior to storing the operand. In the general case, this gives:
LIS R1,(DISP>>8) ORIS R1,(DISP )&#FF PLUS R1,R2 ; compute the effective address STORES R5,R1 ; store in the effective address
Note the use of PLUS to compute the effective address instead of ADD (see Section 8.2). This is needed here because STORE does not change the condition codes.
Note that if the 16-bit displacement DISP is modified by the linker, the above substitution will not work. The solution to the same problem given for LIL in the previous section also works here.
The above substitution can be made for most memory reference instructions, but many optimizations are possible. When the displacement is short, the ORIS instruction may be omitted. In the case of LOAD and LEA, the destination register may be used for effective address computation. So, we can replace:
LOAD R5,R2,100
With the optimized sequence:
LIS R5,100 PLUS R5,R2 LOADS R5,R5
PC relative addressing requires only small changes. We can replace:
LOAD R5,LOC
With an a similar instruction sequence:
LIS R5,((LOC-ALOADS)>>8) ORIS R5,((LOC-ALOADS) )&#FF PLUS R5,PC ALOADS: LOADS R5,R5The tricky detail in the above is the placemet of the label ALOADS. Note that the program counter is incremented immediately upon instruction fetch, before the instruction is executed. Therefore, the value used by PLUS will be the address of the immediately following LOADS. As a result, the computed address (LOC-ALOADS)+PC will be (LOC-ALOADS)+ which is LOC.