Undocumented 8086 processor operating codes
- Transfer
Nope, not IMUL. A comment in the code states that it is a “direct jump”:
cmp byte ptr cs: [DiskSector], 069H; Is it a direct jump? je Check_Signature; don't need to find a NOP cmp byte ptr cs: [DiskSector], 0E9H; DOS 2.0 jump? je Check_Signature; no need for NOP cmp byte ptr cs: [DiskSector], 0EBH; How about a short jump. jne baddisk
Well, that's just about 69h, the 8086 documentation says nothing! Yes, in 8186 onwards it is the IMUL opcode, but it is highly unlikely that the 8086 can IMUL. Moreover, the comment clearly indicates that this is a leap.
Maybe on processors 8086 69h behaves like a jump? The question is good, but there is almost no information on this subject. I thought that someone from the old PC hacker party of early PCs would surely find out exactly what undocumented instructions do, but I was mistaken - a fairly thorough search on the Internet did not yield any intelligible results, and even Frank van Gilluwe’s book “Undocumented PC ”, Which says a lot about operating codes not described in the documentation, helped little. Surely, sometime, somewhere, someone published something ...
First, it would be nice to note that starting from 80186, unlike 8086/8088, an attempt to execute an incorrect (undocumented) opcode will raise a corresponding exception (now denoted as #UD). That is, now the opcode is either standard and executed, or #UD is triggered, and, accordingly, there is no sense in trying to execute anything other than the instructions described in the documentation. Well, of course, there are exceptions: D6h and F1h - Intel made it clear that the standards do not bother him ... but back to 8086.
For 8086, it was not described how it should behave if it tries to execute the wrong instruction on it. Undefined behavior means that every, even an unwritten instruction, definitely does something, and this is something that might very well hang the processor. At least this is not prohibited.
There are several 8086 opcodes that are not described in Intel documentation, but whose behavior has long been established :
- POP CS (0Fh). It's pretty easy to guess what he is doing. See: 06h (push es) - 07h (pop es), 16h (push ss) - 17h (pop ss), 1Eh (push ds) - 1Fh (pop ds), 0Eh (push cs) - and, accordingly, 0Fh ( pop cs). This manual, although it works, is almost useless. That's why it was never documented, and, starting from 80286, the opcode 0Fh corresponds to another instruction.
- MOV CS (8Eh). The same as with POP CS is pretty easy to guess, and again, it's useless.
- SETALC / SALC (D6h). It does the same as SBB AL, AL, but does not touch the flags, that is, AL will have either FFh, or 0 - depending on CF. This instruction is present in modern Intel CPUs, but it is still undocumented.
Three instructions are fine, but for 8086, 60h - 6Fh (including our 69h), C0h - C1h, C8h - C9h, and F1h are also undefined. There are also several spaces in opcode extensions (this is when the instruction is described not only by the first byte, but also by the bit part in the byte following it), especially the GRP4 group, here .
To clarify this, Raúl Gutiérrez Sanz took his Siemens 8086-2 (produced in 1990) and figured out what exactly happens when executing opcodes not described in official documentation.

This processor is manufactured under the Intel license, and, without any suspicion, it is functionally no different from the original Intel processors.
Clue
Unfortunately, the behavior of most undocumented opcodes is very prosaic. No magical secret instructions - these instructions are just aliases to other documented ones. In other words, the 8086 processor, when decoding such instructions, simply ignores some bits of the word, and that's it :(
The undocumented opcodes 60h - 6Fh follow the same instructions as the documented 70h - 7Fh - the processor ignores the fourth bit of the opcode, i.e. 60h corresponds to 70h, 61h - 71h, ..., 6Eh - 7Eh, 6Fh - 7Fh, and they do exactly same. Quite reasonable, especially - for a slow 8086 - no potentially dangerous behavior, and you don’t need to write too much microcode. On the other hand, these initially undocumented opcodes can then be assigned to other instructions in new generation processors, while maintaining backward compatibility (after all, it is assumed that no one will use undescribed opcodes in the code).
So, in the range C0h - CFh, the CPU ignores the first bit of the word: C0h means C2h, C1h means C3h, C8h means CAh, and C9h means CBh.
The behavior of the F1h opcode remains a mystery at the moment. On new F1h processors, the undocumented instruction ICEBP, or INT1. In the documentation of Intel, it is not described, although AMD is present.
On 8088, F1h is more likely not even an instruction, but a prefix. We determined this by going through the sequence step by step, consisting of repeating opcodes F1h and some other documented one. The microprocessor steps over the entire sequence, which actually proves that F1h is a kind of prefix.
It seems that F1h is an alias to F0h - the LOCK prefix. We did not succeed in somehow proving or disproving it, because some piece of hardware is required that can track the LOCK # signal on the bus.
Back to the boot sector. Could the boot sector start with 69h? On 8088, this would probably work. If opcode 69h is an alias to the JNS instruction, then if the sign flag is not set, a short jump will be executed. At least on an IBM PC, the state of the flags at the start of the boot sector execution is predictable, so 69h might work.
But what is the point of putting the 69h boot sector at the beginning and who would need it? Good question. At the moment, I don’t know if there were any DOS boot sectors starting with opcode 69h. Why someone needed to use undocumented instructions is completely incomprehensible. Maybe the implementation of the copy protection system is incorrect ... but the fact is that DOS separately checks the start of the boot sector for the presence of the 69h opcode, and this definitely proves that such boot sectors definitely existed. Ideas?
PS There are some more undocumented opcodes in the range of extended codes! More on this next time ...