3 ms·
For traditional 32-bit ARM, off the top of my head: - Every instruction being conditional (all instructions have a four-bit condition field, with one of the 16
by cesarb 5y ago
For traditional 32-bit ARM, off the top of my head:
- Every instruction being conditional (all instructions have a four-bit condition field, with one of the 16 possible modes being "always");
- The barrel shifter, which can be used on nearly every data processing instruction;
- The program counter being one of the general-purpose registers (and on the original ARM, the same register also containing the flags), so that any register move can alter the program flow;
- The load-multiple/store-multiple instructions, which can load or store up to 16 registers, plus incrementing or decrementing the base register; and since the program counter is one of these registers, it can restore several registers from the stack, update the stack pointer, change the program counter, and switch to Thumb mode (stored on the least significant bit of the program counter), all in a single instruction.
- Annatar 5y agoLoading and storing multiple registers is by no means weird: the MC68000 family has the movem.(b|w|l) instructions which do exactly that, and it's one of the best things since sliced bread because performance can be gained when used cleverly. Being able to manipulate the program counter in the ARM processors directly is just being honest, simple and straightforward, rather then having it always done implicitly. Seems very intuitive to me now that I think about it.
- brucehoult 5y agoBeing able to manipulate the program counter directly plays hell with a superscalar and especially OoO processor where you want to be able to predict what the program counter does very accurately so the instruction fetch and decode can run far ahead of the execution. There are four kinds of instructions that play hell with pipeline and OoO design: - instructions that might cause traps, dependent on the values processed - instructions that you don't know whether they will change the control flow - instructions that you don't know where the control flow is going to go to - instructions where you don't know how long they will take to execute RISC-V, for example, bans the first category entirely other than load/store, and carefully separates the other three so any one instruction only had at most one of those problems. ARM load multiple has all of those problems. At least you can examine the register mask at instruction decode time and know whether it will change the PC or not and tag the instruction in the pipeline as being a Jump or not. Imagine if there was a version that took the bitmap from a register instead of being hard-coded... Load/store multiple don't increase performance much if at all on a CPU with an instruction cache and/or an instruction prefetch buffer. On an original 68000 or ARM without any cache, sure, a series of load or store instructions requires interleaving reading the opcodes with reading or writing the data, while load/store multiple eliminates the opcode reads. An instruction cache also eliminates them, leaving only the code size benefits. But load/store multiple is a perfect candidate for using a simple runtime function instead, at least if you have lightweight function call/return as RISC designs usually do.
- Annatar 5y ago"An instruction cache also eliminates them, leaving only the code size benefits." The performance of movem.l in the MC68000 comes not from multiple load, but from multiple store, because the main memory access incurred a tremendous, extremely punitive penalty. This has not changed, even decades later, in systems with the fastest memory chips available: any writes to random access memory incur tremendous penalties.
- brucehoult 5y ago"always" is not the weird one -- that's just the same as everyone else. "Never" is weird, immediately spending 1/16th of the opcode space (256 million instructions) on NO-OPs. PC being a general-purpose register was historically not uncommon. PDP-11 and VAX both did it and they were kinda popular at one time. Load/store multiple was also fairly common with, for example, both 68000 and VAX having it. IBM 360 also, though using a register range rather than a bitmap -- a less general solution, but good enough, and much easier to make go fast.
- naniwaduni 5y ago> "always" is not the weird one -- that's just the same as everyone else. "Never" is weird, immediately spending 1/16th of the opcode space (256 million instructions) on NO-OPs. Worse, iirc what looks like it should be the slot for the "never" condition actually does exactly the same thing as "always".
- brucehoult 5y agoHmm. I guess I never actually tried it. The A64 manual says 1111 on a Bcc etc disassembles as NV but does the same as AL. The ARM7TDMI manual says 1111 is reserved and don't use it. I don't know the actual behaviour. Aha. The Welsh&Knaggs "ARM Book" says before ARMv3 NV meant NV. In ARMv3 and ARMv4 NV is unpredictable. And in ARMv5 NV is used to encode "various additional instructions that can only be executed unconditionally".