23

The question "Which endian was the Intel 4004?" generated some discussion about the distinction between the endianness of instructions versus data. In the case of the 4004, the code space had 12 bit addresses, and addresses which were encoded inside instructions were packed in big endian format. However, the data size was only 4 bits, making the question of data endianness supported by the hardware moot (although software was free to use whichever representation they desired).

Recognizing that instructions and data can theoretically have opposite endianness, did any processor have big endian instructions and little endian data, or vice versa? By "instructions" I mean opcodes and operands, and "data" means all other memory accesses.

Note that many processors are now "bi-endian", meaning that they are capable of loading and storing data in both big and little endian. That's not what is being discussed here, so please do not include that as an answer.

7
  • 2
    Another interesting scenario is a big endian computer with little endian bit numbering: the 68000. This makes operations on bit fields and bit vectors super "interesting"!
    – Erik Eidt
    Mar 8 at 15:24
  • 4
    @ErikEidt most architectures number the bits from the least significant bit like that. However PowerPC counts bits from the most significant position
    – phuclv
    Mar 8 at 15:28
  • 1
    @ErikEidt: If you want to ask that as a separate question, go for it!
    – DrSheldon
    Mar 8 at 15:43
  • 1
    @phuclv, so does PA-RISC like PowerPC. MIPS docs tend to use the little endian bit order, but that doesn't really matter b/c they don't have any instructions that take bit number (68k's BCLR/BTST/BSET, for example, can take a bit # in a register and the numbering is backwards from endian-ness).
    – Erik Eidt
    Mar 8 at 19:30
  • @ErikEidt PowerPC has instructions such as rlwinm which take the bit number and that makes it a little bit awkward to deal with
    – phuclv
    Mar 9 at 1:25
27

First that comes to mind would be Nationals NS16xxx/32xxx series. For data in memory it's little-endian, but displacements and immediate values within instructions are big-endian.

[Official End Of Answer]


[Later AddOn I Couldn't Stop Myself From Doing]

I know, the question does explicit exclude for bi-endian CPUs, but spending some time about the issue, I think there is more to it to be able to simply put it away as a single issue. So please pardon me for going there.


In reality, what often is called bi-endianess isn't a single feature, but a spectrum.

  • At one end there are CPUs (*1) like MIPS, which offers separate load and store for either endianess. Here byte order is really arbitrary and most definitely nothing to be considered in context of this question.

  • On the other end we have ARM. The CPU was originally designed as little-endian but a bi-endian mode was added regarding data. Being a RISC CPU it matters only for load and store (*2, *3), but unlike MIPS, it's not done per-instruction but switched via a global flag. Control register 1 holds a bit for endianness. When cleared (like after reset) access is little-endian, otherwise big-endian. Writing that register (CPRT) is a privileged instruction, making switching anything but casual.

    As a result, an ARM CPU with the big-endian bit set fits the question for all operations. Data read from memory are big-endian, while values in instructions (*4) are little-endian. A user-mode programmer has no chance to change this.

    So in hindsight, I would place ARM on the list of 'dual endianness ' CPUs. (*5)

  • To add more confusion, SUN gave us not only SPARC, but increased pressure with UltraSPARC (64 bit), which introduced per (load/store) instruction endianness, much like MIPS. In addition, the MMU got a memory attribute defining endianness for a memory region. Here programs do not have a say about endianness, instead it's done automatically depending on the address which is accessed.

    So again, as with ARM, the decision is not in hands of ordinary programmers but defined by the OS. I guess SPARC V9 should also go on the 'dual endianness' list.


P.S.: Interesting question :))


*1 - I use a generic plural here to avoid any discussion how many are there.

*2 - Plus SWP (Swap).

*3 - Always doing aligned word access; using a non-word address also reorders bytes/words, but that's a different issue.

*4 - Another unusual case for ARM, as by default it knows only an 8-bit immediate value, which can be shifted after loading. In addition there are 12-bit offsets for relative addressing and 24-bit offsets for branching.

*5 - An attempt to use a different word than "bi-endian" to describe a CPU with different code and data endianness.

7
  • 14
    So it begs the question, "Why on earth?"
    – OmarL
    Mar 8 at 13:23
  • 3
    @OmarL: Consider an architecture which can use two bytes to encode effective-address forms including "Rn+v" for a 12-bit displacement, or "Rn+Rm+d" for an 8-bit displacement. Having the first byte encode the kind of effective address would allow the processor to start the work of fetching Rn while it fetches the second byte, but having the second byte always represent bit 0-7 of the displacement would be more practical than having it represent bits 0-7 of an 8-bit displacement, but 4-11 of a 12-bit one.
    – supercat
    Mar 8 at 17:14
  • 4
    @DrSheldon Sorry, I though I had another, but when checking the databook I realized my memory was wrong. So far couldn't find any other - at least no clear ones. There are a few border cases, but they might only open up endless discussions how to interpret this. Bi-Endian processors are explicit excluded, although one might make a case of ARM as it's memory endianess can be switched globally, not per instruction like on MIPS (Sparc again is an even more wired case as its neither global nor instrution as here the MMU can declare endianess per memory region).
    – Raffzahn
    Mar 8 at 19:03
  • 3
    Even having the NS32k come to mind is an achievement!
    – TEMLIB
    Mar 8 at 21:29
  • Thank you for the updated answer. It gets the checkmark!
    – DrSheldon
    Mar 9 at 5:28
7

The PDP-11 used little endian for most data, and for its instructions. So a normal 16-bit integer, or an instruction like 0xABCD in hex would be stored in two bytes in memory, in ascending address order: CD, AB.

The in-memory representation for the 32-bit double-width integers, and for the floating point numbers, was different. Two 16-bit little endian numbers, combined in big endian format themselves. So a 32-bit number represented by hex 1234ABCD would be stored as: 34, 12, CD, AB.

Various other mixed forms are of course possible. And some have been used. This particular arrangement got the name PDP-endian, and that term, and software support for it in the UNIX world at least, persisted long past the PDP-11 platform itself.

3
  • 2
    I had heard that 32 bit integers on the PDP-11 had the same endian as the floating point.
    – Joshua
    Mar 9 at 0:37
  • @Joshua: Yes, when I've seen discussion of "pdp-endianness", it's been about integers. en.wikipedia.org/wiki/PDP-11_architecture#Data_formats confirms that 2 separate ISA extensions (FPU instructions, and "double-words in the Extended Instruction Set") use that PDP / middle-endianness. (Good and unsurprising that they chose to use the same endianness for FP and integer.) PDP-11's integer registers are only 16-bit, but apparently there is some direct HW support for double-words, so the integer side of it isn't just a software convention. Mar 9 at 1:05
  • Thanks, forgot all about double-words! Edited.
    – RETRAC
    Mar 9 at 4:09
-3

In considering whether to design a processor to be big-endian, little-endian, or some form of mixed-endian, the question one should ask is whether the processor will benefit from processing things in any particular order. Consider the 6502 and its (zp),y addressing mode. Given an instruction "lda ($12),y", if locations $12 and $34 hold $AB and $CD, the processor will perform the following sequence of steps:

  1. Read the opcode
  2. Read the operand $12
  3. Fetch a byte ($AB) from an address formed by outputting 0 on the upper address bus and forwarding the received value to the lower address bus, while computing ($12 + 1).
  4. Fetch a byte ($CD) from an address formed by outputting 0 on the upper address bus and the newly-computed value on the lower address bus, while computing ($AB + Y).
  5. Fetch a byte from an address formed by outputting the newly computed value on the lower address bus and the newly fetched value on the upper address, bus while computing ($BC + 1).
  6. If ($AB + Y) had generated a carry, fetch a byte from the address formed by keeping the value on the lower address bus and outputting the newly computed value on the upper address bus.

If computation of ($AB + Y) generates a carry, the instruction will take six cycles. If it does not, however, step 5 will have been able to start outputting the correct address as soon as the upper byte was received, without having to perform any computation on it. If the lower byte had been accessed second, the processor would have to add Y to it before being able to use it as an address, thus requiring six cycles in every case.

In cases where all operand bits are fetched separately from from instruction bits, there's seldom if ever any advantage to using big-endian format, and there are sometimes advantages to little-endian. In cases where operand and instruction bits are combined, however, a processor might need to know what the instruction bits are before it can do anything useful with the operand. In those cases, it may be advantageous (if not downright essential) to fetch the instruction bits before the operand bits. If some operand bits are included with those instruction bits, putting upper bits there may be more convenient than putting lower bits there.

12
  • 5
    While this is a notable rant, it does not answer the question in any way. If you want to keep it relevant, you may want to open a new question, like "why would someone use mixed endianes for code and data", and add this as an answer.
    – Raffzahn
    Mar 8 at 17:35
  • @Raffzahn: Processors which combine part of a displacement or other numerical operand with other instruction bits will likely put the upper bits of the numerical operand there. The processors I know of that combine things in such fashion happen to be big-endian, but there's no reason that a processor which combines numerical operands with mode-control bits couldn't be little-endian in most respects, but I would expect that even if such a processor were little-endian it would put the upper bits of the operand before the lower portion.
    – supercat
    Mar 8 at 17:45
  • 2
    Erm, the question asks CPUs/Architectures named that do use both directions. Neither that your answer nor your comment provides either. So please, if you want to keep this relevant, think about the option suggested.
    – Raffzahn
    Mar 8 at 18:05
  • @Raffzahn, "rant: speak or shout at length in an angry, impassioned way". That's hostile language you're using there, on a friendly Q&A site. In what way exactly was this calm answer a 'rant'?
    – TonyM
    Mar 13 at 14:43
  • @TonyM I guess rant is a quite flexible word with spectrum of meaning, including "The extensively talk about a given topic longer than needed whether anyone cares or not". Not at least the addition of the positiv conotation of 'notable', but as well as the supportive suggestion to turn it into a dedicated Q&A, should have given away that the intended usage is not negative one. So what made you assuming the worst possible meaning and trying to put my friendly and supportive reminder as hostile and unfriendly?
    – Raffzahn
    Mar 13 at 15:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.