ARM instruction set
Almost certainly more for my benefit that anyone else’s, but if I am about to take on
the ludicrously difficult task of porting Phix to the Raspberry Pi (specifically that is on
RaspbianOS running on an ARM mfpu=vfpv2+ chip, as opposed to bare-metal LED blinking stuff)
then I need a decent lookup to be one (F1) keystroke away, rather than wade though all
1,949+ pages of the official references, or sixteen shorter ones that each miss something,
every single time!
Should you want to learn (the Phix subset of) ARM assembly, you are probably better off searching builtins\ for "[ARM]", most of what follows is likely and in fact deliberately intended to make much more sense within such a context, specifically when faced with (say) "ermah du,da,de", pressing F1 with the cursor on that should give you some kind of hint (when a real/known instruction).
These pages are naturally biased towards binary [dis]assembly of instructions, rather than usage, and deliberately omit the 75% or more of instructions that Phix does not [yet] make any use of.
You may recognise that as a somewhat cut-down "rE Ejected" table, however I am only interested in documenting opcodes that are actually used and supported/properly tested, and deliberately omitting distractions (via a prefix of '-'): for instance there are four different types of stack, garnished with pre- and post- increment, so for my own sanity I’m just sticking with push and pop [erm... I think I spoke too soon on that, but I think you get the idea]. The full/original "rE Ejected" was used to write the dissassembler, and therefore should perhaps be trusted slightly more (but lacks any fpu stuff), the above was/will be used to write the inline assembler (ie extensions to pilasm.e/ilasm() and friends).
For my own sanity I have hidden the dataprocessing opcodes EOR..BIC in the main table as they are very similar to and, ditto mvn/ldr/ldm, mov/str/stm, and all fpu.
Likewise I don’t support the adr pseudo-instruction, and have replaced overloaded ldr pseudo-forms with lea.
It is probably fair to describe my (Phix-specific) opcodes as "pre-UAL", I’ve certainly avoided any jack-of-all-trades such as vmov, since they may be nice for a coder but a royal pain to de/encode and test. The (P/L)U(I/D/N/B)W (etc) bits may/are not really properly documented and unlikely to ever be.
I will of course happily put things back in, once my 310+ immediate needs are done, but if Euphoria 4.0 has taught me anything, the one thing you should never do is just dump in 500 untested things and leave it to someone else to (never) come along and fix them all later.
These are (most of) the internal mask constants, as used in filedump.exw and similar:
Should you want to learn (the Phix subset of) ARM assembly, you are probably better off searching builtins\ for "[ARM]", most of what follows is likely and in fact deliberately intended to make much more sense within such a context, specifically when faced with (say) "ermah du,da,de", pressing F1 with the cursor on that should give you some kind of hint (when a real/known instruction).
These pages are naturally biased towards binary [dis]assembly of instructions, rather than usage, and deliberately omit the 75% or more of instructions that Phix does not [yet] make any use of.
Supported instructions in bitwise-layout-ish order:
| Opcode | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| OPCODE | LIT12 | |||||||||||||||||||||||||||||||
| O7/8 | ROTATE | LIT8 | ||||||||||||||||||||||||||||||
| OOOO | S | R | SHIFTH | |||||||||||||||||||||||||||||
| COND | OOO | P | U | I | W | S | RN | RD | RS | V | SHFT | Z | RM | |||||||||||||||||||
| and[cond][s] Rd, Rn, Rm OP # | cond | 0 | 0 | 0 | 0 | 0 | 0 | 0 | S | Rn | Rd | shift# | shft | 0 | Rm | |||||||||||||||||
| and[cond][s] Rd, Rn, Rm OP Rs | cond | 0 | 0 | 0 | 0 | 0 | 0 | 0 | S | Rn | Rd | Rs | 0 | shft | 1 | Rm | ||||||||||||||||
| and[cond][s] Rd, Rn, # | cond | 0 | 0 | 1 | 0 | 0 | 0 | 0 | S | Rn | Rd | rotate | # | |||||||||||||||||||
| eor, sub, rsb, add, adc, sbc, rsc, tst, teq, cmp, cmn, orr, bic - as and but with OPCODE 0001 to 1100, & 1110 | ||||||||||||||||||||||||||||||||
| mul[cond][s] Rd, Rm, Rs | cond | 0 | 0 | 0 | 0 | 0 | 0 | 0 | S | Rd | SBZ | Rs | 1 | 0 | 0 | 1 | Rm | |||||||||||||||
| mla[cond][s] Rd, Rm, Rs, Rn | cond | 0 | 0 | 0 | 0 | 0 | 0 | 1 | S | Rd | Rn | Rs | 1 | 0 | 0 | 1 | Rm | |||||||||||||||
| smull[cond][s] RdLo, RdHi, Rm, Rs | cond | 0 | 0 | 0 | 0 | 1 | 1 | 0 | S | RdHi | RdLo | Rs | 1 | 0 | 0 | 1 | Rm | |||||||||||||||
| umull, umlal, smlal - as smull but with OPCODE 0100, 0101, 0111 respectively | ||||||||||||||||||||||||||||||||
| mov[cond][s] Rd, Rm OP # | cond | 0 | 0 | 0 | 1 | 1 | N | 1 | S | SBZ | Rd | shift# | shft | 0 | Rm | |||||||||||||||||
| mov[cond][s] Rd, Rm OP Rs | cond | 0 | 0 | 0 | 1 | 1 | N | 1 | S | SBZ | Rd | Rs | 0 | shft | 1 | Rm | ||||||||||||||||
| mov[cond][s] Rd, # | cond | 0 | 0 | 1 | 1 | 1 | N | 1 | S | SBZ | Rd | rotate | # | |||||||||||||||||||
| (ie mov, mvn are the same as 'add' and friends, but with Rn SBZ) | ||||||||||||||||||||||||||||||||
| str[cond]<x> Rd, Rn, # | cond | 0 | 1 | 0 | P | U | B | W | 0 | Rn | Rd | # | ||||||||||||||||||||
| str[cond]<b> Rd, Rn, # | cond | 0 | 1 | 1 | P | U | B | W | 0 | Rn | Rd | shift# | shft | 0 | Rm | |||||||||||||||||
| stm[cond]<addrmode> Rm<!>, reglst | cond | 1 | 0 | 0 | P | U | 0 | W | 0 | Rn | register list | |||||||||||||||||||||
| (ldr/ldm as str/stm but with S set to 1) | ||||||||||||||||||||||||||||||||
| bx[cond] Rm | cond | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | SBO | SBO | SBO | 0 | 0 | 0 | 1 | Rm | |||||||||||||||
| b<l>[cond] <target addr> | cond | 1 | 0 | 1 | L | 24_bit_offset | ||||||||||||||||||||||||||
| fls Rd,CRd,# | cond | 1 | 1 | 0 | P | U | N | W | S | Rn | CRd | cp_num | # | |||||||||||||||||||
| fpu CRd,CRn,CRm | cond | 1 | 1 | 1 | 0 | op1 | CRn | CRd | cp_num | op2 | CRm | |||||||||||||||||||||
| (fls and fpu are pseudo-squared-opcodes for floating point load/store and other instructions) | ||||||||||||||||||||||||||||||||
| swi <swi_number> | cond | 1 | 1 | 1 | 1 | swi_number | ||||||||||||||||||||||||||
You may recognise that as a somewhat cut-down "rE Ejected" table, however I am only interested in documenting opcodes that are actually used and supported/properly tested, and deliberately omitting distractions (via a prefix of '-'): for instance there are four different types of stack, garnished with pre- and post- increment, so for my own sanity I’m just sticking with push and pop [erm... I think I spoke too soon on that, but I think you get the idea]. The full/original "rE Ejected" was used to write the dissassembler, and therefore should perhaps be trusted slightly more (but lacks any fpu stuff), the above was/will be used to write the inline assembler (ie extensions to pilasm.e/ilasm() and friends).
For my own sanity I have hidden the dataprocessing opcodes EOR..BIC in the main table as they are very similar to and, ditto mvn/ldr/ldm, mov/str/stm, and all fpu.
Likewise I don’t support the adr pseudo-instruction, and have replaced overloaded ldr pseudo-forms with lea.
It is probably fair to describe my (Phix-specific) opcodes as "pre-UAL", I’ve certainly avoided any jack-of-all-trades such as vmov, since they may be nice for a coder but a royal pain to de/encode and test. The (P/L)U(I/D/N/B)W (etc) bits may/are not really properly documented and unlikely to ever be.
I will of course happily put things back in, once my 310+ immediate needs are done, but if Euphoria 4.0 has taught me anything, the one thing you should never do is just dump in 500 untested things and leave it to someone else to (never) come along and fix them all later.
These are (most of) the internal mask constants, as used in filedump.exw and similar:
| --- Mask --- | -- Hex -- | ---------------- Binary ---------------- | ---------------- Description ---------------- |
| COND | #F000_0000 | 0b1111_0000_0000_0000_0000_0000_0000_0000 | condition code |
| TA | #0C00_0000 | 0b0000_1100_0000_0000_0000_0000_0000_0000 | zero for all data instructions |
| I | #0200_0000 | 0b0000_0010_0000_0000_0000_0000_0000_0000 | immediate flag |
| OOO | #0E00_0000 | 0b0000_1110_0000_0000_0000_0000_0000_0000 | (as per the rEjected original) |
| OOOO | #0F00_0000 | 0b0000_1111_0000_0000_0000_0000_0000_0000 | (for branches and some ldr/str instructions) |
| OPCODE | #01E0_0000 | 0b0000_0001_1110_0000_0000_0000_0000_0000 | opcode (see here) |
| O7 | #0FE0_0000 | 0b0000_1111_1110_0000_0000_0000_0000_0000 | (as used on multiply instructions) |
| O8 | #0FF0_0000 | 0b0000_1111_1111_0000_0000_0000_0000_0000 | (as used on some unsupported instructions) |
| S | #0010_0000 | 0b0000_0000_0001_0000_0000_0000_0000_0000 | set status bits (s suffix) |
| RN | #000F_0000 | 0b0000_0000_0000_1111_0000_0000_0000_0000 | First operand register |
| RD | #0000_F000 | 0b0000_0000_0000_0000_1111_0000_0000_0000 | Destination register |
| IS | #0000_0F80 | 0b0000_0000_0000_0000_0000_1111_1000_0000 | Immediate shift, second operand is Rm Op IS |
| ROTATE aka IR | #0000_0F00 | 0b0000_0000_0000_0000_0000_1111_0000_0000 | Immediate rotate |
| IN | #0000_00FF | 0b0000_0000_0000_0000_0000_0000_1111_1111 | Immediate, second operand is IN ror 2*IR |
| SHIFTH | #0000_0F80 | 0b0000_0000_0000_0000_0000_1111_1000_0000 | Shift immediate |
| RS | #0000_0F00 | 0b0000_0000_0000_0000_0000_1111_0000_0000 | Shift register, second operand is Rm Op Rs |
| V | #0000_0080 | 0b0000_0000_0000_0000_0000_0000_1000_0000 | (should be 0 when Z is 1) |
| SHIFT | #0000_0060 | 0b0000_0000_0000_0000_0000_0000_0110_0000 | Shift type, 0: lsl, 1: lsr 2: asr, 3: ror |
| Z | #0000_0010 | 0b0000_0000_0000_0000_0000_0000_0001_0000 | Shift-operand flag, 1: IS, 0: Rs |
| RM | #0000_000F | 0b0000_0000_0000_0000_0000_0000_0000_1111 | Second operand register |
| LIT8 | #0000_00FF | 0b0000_0000_0000_0000_0000_0000_1111_1111 | 8 bit immediate |
| LIT12 | #0000_0FFF | 0b0000_0000_0000_0000_0000_1111_1111_1111 | 12 bit immediate |
| OFFSET | #0000_0FFF | 0b0000_0000_1111_1111_1111_1111_1111_1111 | 24 bit immediate offset |