7

When an ALU performs a floating point division operation using the non-restoring or the SRT algorithm, it maintains the current value of the "remainder" (in quotes, because it is not a true non-negative remainder) in a scratch register. After the operation, the quotient is presented in a user-visible location, and the contents of the scratch register are of no consequence.

However, if a user-visible register is used as the scratch, specifying its contents in all cases is too bothersome. For example, in the BESM-6, the instruction set manual leaves the contents of the accumulator extension register, normally holding the least significant bits of the mantissa after the FP additions or multiplications, unspecified after a division operation (another source explicitly says that it is undefined). I have not heard of attempts to reverse-engineer the value of that register after a division operation and to use it to speed up computation of the remainder.

A narrow-scope question: Is it possible to use the scratch register of a non-restoring or SRT division to figure out the remainder?

My main question is, has there been another case of an unspecified data register contents after any arithmetic operation in another CPU architecture and were there any attempts to reverse-engineer them for a good use?

  • Assuming you mean "general purpose register" by "data register", this restricts the question to microcoded algorithms that use general purpose registers as scratch registers, and don't specify their contents after whatever operation was implemented is over. There are probably not many cases of that besides division on real old CPUs (maybe some other FP algorithms? Or crypto?), so a more interesting question would be "which CPUs do have such an instruction that uses a general purpose register in that way in the first place". – dirkt Nov 2 '18 at 10:41
  • @dirkt Remember that there were CPUs with split sets of address and data registers. Such CPUs might not have general purpose registers at all. – Leo B. Nov 2 '18 at 18:21
9

There are a lot of instructions on x86 that leave the flag(s) in an indeterminate state, which means the whole FLAGS register is also undefined. Most will have AF undefined, for example

  • TEST

    The OF and CF flags are set to 0. The SF, ZF, and PF flags are set according to the result (see the “Operation” section above). The state of the AF flag is undefined.

but there are also other instructions that leave other undefined flags like

The x87 FPU also has its own flags which may also be left unspecified after many operations

You can open any of the lists in the X86 Opcode and Instruction Reference like this one and look at the undef_f column to have a summary of undefined flags after each instruction


Normal registers can also have an unspecified state, too. Early x86 CPUs will leave the high bit of a mov Reg, Sreg undefined

When executing MOV Reg, Sreg, the processor copies the content of Sreg to the 16 least significant bits of the general-purpose register. The upper bits of the destination register are zero for most IA-32 processors (Pentium Pro processors and later) and all Intel 64 processors, with the exception that bits 31:16 are undefined for Intel Quark X1000 processors, Pentium and earlier processors.

https://www.felixcloutier.com/x86/mov.html (emphasis mine)

And nowadays SHLD/SHRD still have undefined result

If the count operand is CL, the shift count is the logical AND of CL and a count mask. In non-64-bit modes and default 64-bit mode; only bits 0 through 4 of the count are used. This masks the count to a value between 0 and 31. If a count is greater than the operand size, the result is undefined.

https://www.felixcloutier.com/x86/shld

Some other examples on x86

  • LAR: The following fields are returned only if the operand size is greater than 16 bits: Bits 19:16 are undefined
  • SMSW: In non-64-bit modes, when the destination operand is a 32-bit register, the low-order 16 bits of register CR0 are copied into the low-order 16 bits of the register and the high-order 16 bits are undefined
  • BSF, BSR, TZCNT: if source operand is zero, the content of destination operand are undefined
  • SLDT: The high-order 16 bits of the register [...] are undefined for Pentium, Intel486, and Intel386 processors

Not sure whether their intermediate results can be utilize for other purposes or not though


Division and multiplication also often leave unspecified results

For example on PowerPC we have

  • divw

    For the case of -2**31 / -1, and all other cases that cause overflow, the content of GPR RT is undefined.

  • and divd

    If an attempt is made to perform the divisions 0x8000_0000_0000_0000 / -1 or / 0, the contents of RT are undefined

Similarly on MIPS

  • for DIV/MOD/DIVU/MODU/DDIV/DDIVU,

    If the divisor in GPR rt is zero, the arithmetic result value is UNPREDICTABLE

  • In older MIPS ISAs there are also restrictions regarding the HI and LO registers

    In MIPS 1 through MIPS III, if either of the two instructions preceding the divide is an MFHI or MFLO, the result of the MFHI or MFLO is UNPREDICTABLE

On MIPS many floating-point instructions also leave unpredictable result in the registers, like

  • DIV.fmt

    The fields fs, ft, and fd must specify FPRs valid for operands of type fmt. If the fields are not valid, the result is UNPREDICABLE.

    The operands must be values in format fmt; if they are not, the result is UNPREDICTABLE and the value of the operand FPRs becomes UNPREDICTABLE.

  • or FLOOR.L.fmt

    The fields fs and fd must specify valid FPRs: fs for type fmt and fd for long fixed point. If the fields are not valid, the result is UNPREDICTABLE.

    The operand must be a value in format fmt; if it is not, the result is UNPREDICTABLE and the value of the operand FPR becomes UNPREDICTABLE.

    The result of this instruction is UNPREDICTABLE if the processor is executing in the FR=0 32-bit FPU register model; it is predictable if executing on a 64-bit FPU in the FR=1 mode, but not with FR=0, and not on a 32-bit FPU.

http://hades.mech.northwestern.edu/images/1/16/MIPS32_Architecture_Volume_II-A_Instruction_Set.pdf

  • In general, when a hardware specification states that a certain certain bits have an "undefined" value, that means that the bits may arbitrarily read as high or low, but those are the only two possibilities. That concept of "undefined" is very different from the C concept. – supercat Feb 3 at 21:39
  • The question asks about data registers after arithmetic operations. – Leo B. Feb 3 at 21:48
  • @LeoB. SHLD and SHRD can leave the data register undefined – phuclv Feb 4 at 0:14
  • On a RISC CPU without interlocks undefined behavior is par for the course, but the case of overflowing division producing undefined register contents does satisfy the criteria. Unfortunately, there is nothing to gain by analyzing the value. – Leo B. Feb 4 at 7:51
5

One example are the two undocumented 8085 flags that can be found by reverse-engineering the silicon (well, it's part of a register, not a complete register). They have uses for signed overflow in arithmetic operations and signed comparison. There are actually a few undocumented opcodes that make use of at least the K flag.

They were put in deliberately (so it's not a chance effect like in the undocumented opcodes for the 6502 - one could argue that the contents of the BESM-6 scratch register would also be a "chance effect", though a deliberate one that depends on the internal algorithm), but not documented for "political" reasons.

  • That's more about deliberately put undocumented instructions. The fact that only they use particular flags, and therefore the flags are also undocumented, is a second-order effect. I'm asking about documented instructions which leave documented registers (or flags, for that matter) unspecified or undefined. I think that a reason not to document the contents of the acc. extension register was to provide for the possibility to improve/speed-up the division algorithm in future versions of the CPU. – Leo B. Oct 30 '18 at 21:25
  • 1
    The documented arithmetic instructions leave the documented status register in an unspecified state for some of the bits, and reverse engineering figured out that it is actually a specified state, so I think it matches your requirement. That there are additionally undocumented instructions which use the specified state is just icing on the cake. In the same way, leaving the bits unspecified would provide for the possibility of different flags in the future (for the current use seemed to be abandoned for "political" reasons). – dirkt Oct 31 '18 at 7:17
  • I've qualified my question to ask exactly what I've wanted, about data registers. – Leo B. Nov 2 '18 at 2:46
  • 2
    @LeoB. - note that the 8085 PUSH PSW instruction is a documented instruction whose behaviour includes copying undefined bits into memory, whose value is determined from previously executed documented instructions in a way which is not specified in the documentation. This only seems to not match what you're asking because you have to go via memory to get to the undefined values, rather than directly access them in a register, which is a pretty arbitrary distinction... – Jules Nov 4 '18 at 4:50
  • @Jules If it's still unclear that I'm asking about leaving a data register used as scratch in an unspecified state after an arithmetic instruction, please suggest an edit. – Leo B. Nov 6 '18 at 0:30
4

Some arithmetic operations in the Xerox Alto would leave registers in unpredictable states, as the cycle time was shorter than the total propagation time of the ALU:

With a 137ns clock cycle time, the CP pushes the underlying hardware to its limits. As a result, some combinations of input sources requested by a microinstruction will not produce valid results because the data simply cannot all make it to its destination on time. Some combinations will produce garbage in all bits, but some will be correct only in the lower nibble or byte of the result, with the upper bits being undefined. (This is due to the ALU in the CP being comprised of four 4-bit ALUs chained together.)

-- https://engblg.livingcomputers.org/index.php/2019/01/19/introducing-darkstar-a-xerox-star-emulator/

  • That's at the microinstruction level, though. Was this observable at the ISA level? – Leo B. Feb 3 at 21:51
  • The distinction between microcode and "normal" code was rather fuzzy on the Alto -- the control store was writable, and many applications made use of this to add their own instructions. – duskwuff Feb 3 at 21:56
1

And then there are data registers of various FPUs leaving one or more entries in unspecified state after an operation. Well known for example the AMD 9511 series where next to all higher FP functions like SIN or LOG working on a single argument leave at least two entries in undefined states (*1).


*1 - Two operand functions always leave one entry undefined due to their nature.

  • 1
    Unfortunately, I couldn't find an instruction set reference sheet for it. And I don't understand the footnote. What's that "nature" of two operand functions that causes them to leave one register undefined? – Leo B. Feb 3 at 23:11

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.