3. Hawk Memory Reference Instructions
Part of
the Hawk Manual
|
3.1. Memory Reference Format
3.2. Load Effective Address
3.3. Load
3.4. Jump and Call
3.5. Store
07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | |
1 1 1 1 | dst | 0 - - - | x |
15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
disp |
Long-format memory reference instructions occupy 32 bits and are not supported on the Sparrowhawk; the extra 16 bits come from the next successive instruction halfword. The second halfword holds disp, the displacement. The effective memory address (ea) is computed by sign-extending the displacement to 32 bits and adding it to index register x, unless x is zero, in which case the program counter is used:
Because the program counter is incremented as a side effect of instruction fetch, indexed addressing using the program counter is relative to the address of the immediately following instruction.
The LOAD instruction for loading a value from memory into a register is the prototypical memory reference instruction. All of these instructions share the same assembly language formats:
LOAD dst,x,disp LOAD dst,label
The three argument form is used for indexed addressing, where x is one of R1 through R15. The second form is used for PC relative addressing, where x is implicitly R0 (pc), and the assembler automatically computes disp as the difference between the current location and the given label. Thus, the following two lines of assembly code are exactly equivalent in that they generate identical machine code.
LOAD R5,R0,label-(.+2) LOAD R5,label
The documentation that follows gives the format of the first halfword of each instruction. The second halfword is always as documented above.
07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | ||||||
1 1 1 1 | dst (nz) | 0 1 1 1 | x (pc) | LEA | dst,x,disp | r[dst] = ea | |||||||||||||||
1 1 1 1 | dst (x) | 0 1 1 0 | x (pc) | LEACC | dst,x,disp | r[dst] = ea |
LEA | NZVC unchanged | |||
LEACC | N = r[dst]:31 | — result is negative | ||
Z = (r[dst] = 0) | — result is zero | |||
V = ( r[dst]:31 ⊕ ( r[x]:31 ≡ disp:15 )) | ||||
C = carry out of computation of ea | ||||
The LEA and LEACC (load effective address setting condition codes) instructions load the effective address, ea, into the destination register, r[dst]. In the case of the LEACC instruction, the N, Z, V and C condition codes are set to indicate the result of the add used in effective address computation. If some word of memory is to be repeatedly referenced, it can be more efficient to load the address of that word into a register once and then use short memory reference instructions for the repeated references.
LEACC can serve to add a constant to a register. Assemblers should support this with the alternative mnemonic ADDI (add immediate). Programmers should use LEACC when the purpose is to manipulate a memory address, and ADDI when the purpose is numerical computation. If dst is zero, the result is discarded. As a result, LEACC can also be used to compare a register and a constant by adding the negated constant. Assemblers should support this with the CMPI (compare immediate) mnemonic. Assembly of CMPI should negate the displacement.
07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | ||||||
1 1 1 1 | dst (x) | 0 1 1 0 | x (pc) | ADDI | dst,x,disp | r[dst] = ea | |||||||||||||||
1 1 1 1 | 0 0 0 0 | 0 1 1 0 | x (pc) | CMPI | x,-disp |
LEACC R1,R1,16 and ADDI R1,R1,16 should produce identical machine code adding the constant 16 to R1:
LEACC R0,R1,-5 and CMPI R1,5 should produce identical machine code to compare R1 with the constant 5:
07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | ||||||
1 1 1 1 | dst (pc) | 0 1 0 1 | x (pc) | LOAD | dst,x,disp | r[dst] = m[ea] | |||||||||||||||
1 1 1 1 | dst (x) | 0 1 0 0 | x (pc) | LOADCC | dst,x,disp | r[dst] = m[ea] |
LOAD | NZVC unchanged | |||
LOADCC | N = r[dst]:31 | — result is negative | ||
Z = (r[dst] = 0) | — result is zero | |||
V = 0 | ||||
C = (r[dst]:31:24 = 0) ∨ (r[dst]:23:16 = 0) ∨ (r[dst]:15:8 = 0) ∨ (r[dst]:7:0 = 0) | ||||
The LOAD and LOADCC (load setting condition codes) instructions load the contents of the designated word of memory, m[ea], into the destination register, r[dst]. In the case of the LOADCC instruction, the N and Z condition codes are set to indicate whether the indicated word is negative or zero, the V condition code is cleared, and the C condition code is set if any byte in the loaded value is zero. This feature allows for fast string operatons working with 4 bytes at a time.
If dst is zero, LOAD sets pc to the value loaded. In the case of LOADCC, the loaded value is discarded when dst is zero; this allows the operand in memory to be tested without changing the contents of any register. Hawk assemblers should provide the mnemonic TEST for this purpose.
07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | ||||||
1 1 1 1 | 0 0 0 0 | 0 1 0 0 | x (pc) | TEST | x,disp |
The following instructions are equivalent:
LOADCC R0,R0,label-(.+2) LOADCC R0,label TEST R0,label-(.+2) TEST labelAll 4 instructions listed above should generate exactly the same machine code, producing a LOADCC instruction that uses the program counter as an index register to address the memory location with the given label, and then discards the result after setting the condition codes appropriately.
The Hawk architecture does not allow direct loading or storing of bytes or halfwords. See the EXTB and EXTH instructions for efficient support of byte and halfword addressing.
07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | ||||||
1 1 1 1 | dst (x) | 0 0 1 1 | x (pc) | JSR | dst,x,disp | r[dst] = pc; pc = ea |
JSR | NZVC unchanged | ||
The JSR (jump to subroutine) instruction stores the old value of the program counter, pc, in the destination register as a return address, and then sets the program counter to the effective address. The condition codes are not changed.
If dst is zero, the value is discarded. In the case of the JSR instruction, this is useful because it allows for a simple jump to the effective address.
07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | ||||||
1 1 1 1 | 0 0 0 0 | 0 0 1 1 | x (pc) | JUMP | x,disp | pc = ea |
Assembly of the following instructions should produce exactly the same machine instructions:
JUMP label JUMP R0,label-(.+2) JSR R0,label JSR R0,R0,label-(.+2)All 4 lines generate a JSR instruction that discards the return address and uses PC-relative addressing to transfer control to the indicated label.
07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | ||||||
1 1 1 1 | srcx (0) | 0 0 1 0 | x (pc) | STORE | srcx,x,disp | m[ea] = r[srcx] |
JSR | NZVC unchanged | ||
The STORE instruction stores the contents of the designated designated register, r[srcx] into the indicated word of memory m[ea]. The condition codes are not changed. Note that the mnemonic srcx used here refers to the register field usually known as dst, but here it is the source of the operand, not the destination.
Note that PC-relative STORE instructions should never be used when code is executed from read-only memory or from a read-only segment of the address space. Since one or the other of these will usually be the case, the PC-relative form of STORE should rarely be of any use!
The Hawk architecture does not allow direct loading or storing of bytes or halfwords. See the STUFFB and STUFFH instructions for efficient support of byte and halfword addressing.