How does a processor handle invalid opcodes?

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
Hello,

If you have a 64-bit processor (or a 32-bit one), your processor can understand instructions that are 64 (or 32) bits long.

2^64 is a huge number. (2^32 is still pretty big).

There are many, MANY more numbers in a 64 bit array than there are recognizable op-codes.

So, how does the processor handle a bum machine instruction?

Does it just ignore it?

Throw some kind of hardware exception?

Thanks.
 

K7SN

Senior member
Jun 21, 2015
353
0
0
Burn he chip up - well the first 6502 had such an animal but that was 8 bits. I'm sure there is a small subset number of 2^64 that contains all valid op-codes on any modern machine and all other numbers are treated as no-ops. I haven hacked a CPU (In may day that was a god term not nefarious as it is today) in 40 years so someone else will have to answer with actual knowledge.
 

Mark R

Diamond Member
Oct 9, 1999
8,513
16
81
A modern processor will throw an exception in the event of an unrecognizable op code, as well as other errors which occur during execution of specific op codes (e.g. a read to a memory location which either doesn't exist or has been blocked, usually by an OS, by a previous instruction).

When the processor hits an exception it abandons the current instruction, looks at a specified memory location (called a vector) and retrieves the value. It uses that value as an address to jump to.

Normally, during boot up of the OS, the OS will set that memory location (the exception vector) with the location of the OS's exception handler. The job of the exception handler code is to work out what caused the hardware exception and whether it can be recovered.

So, on windows, if an application contains an invalid op code, the processor will fire an exception which will run the windows exception handler. The handler will recognise it as an invalid op code, trace it to a regular app, work out that this isn't fatal to the OS, terminate the application, and put up some sort of error message saying that app.exe has stopped working.
 

Cogman

Lifer
Sep 19, 2000
10,284
138
106
Mark R is correct. In what happens when something goes wrong (especially for an x86 type platform, I'm less familiar with PIC and ARM).

That being said, you can't make any assumption about instruction length based on the word size of the processor. The word size has more to do what the size of the general registers are than anything else.

In RISC style architectures, instructions are a fixed length. In CISC architectures instructions are variable length. The length of an instruction in a CISC architecture could be any number of bytes long. Further, I'm almost certain (but not certain enough to give a definite yes) that some RISC architectures have mixed length instructions, though they tend to be some fixed number of bytes long (Like 8 or 16 but not 9).

The decoding of instructions happens really quickly. So fast that in most intel processors, it isn't just decoded, it is also re-encoded into several smaller opts called "micro-opts". These micro-opts give intel a lot of power and flexibility in what they can do with their CPUs. They also allow intel to fix CPU bugs with software updates (crazy!).
 

Mark R

Diamond Member
Oct 9, 1999
8,513
16
81
Instructions have been decoded into "micro operations" for a long time. Even the old 8-bit 6502 CPU used a variant of micro-ops. In fact, this was responsible for its very odd behavior when encountering an invalid op code.

On the 6502, op codes were 1 byte long and were followed by a variable number of parameters (operands).

The CPU would load the op code byte from RAM, and decode it into several steps. However, instead of breaking it down into a list, it would look it up in a grid, and if it matched a row in the grid, that row would activate a specific circuit at a specific time (immediately, in 1 cycle time, in 2 cycles time, in 3 cycles time, etc.)

Take for example, the command LDA #$20. This would be stored in RAM as A9 20, and would cause the number 0x20 to be loaded into the accumulator register.

The A9 op code would match the rules in 3 rows in the grid - it would match:
1. Immediately load next byte from RAM and strobe onto the CPU internal bus.
2. In 1 cycle time, strobe the contents of the CPU internal bus into the Accumulator register.
3. In 2 cycles time, continue with the next instruction.

The very similar command LDX #$20 would copy the number 0x20 into the X register. It had the op code A2.

As the command was very similar, it would match some of the same rows in the decoder.
1. Immediately load next byte from RAM and strobe onto the CPU internal bus. (shared with LDA)
2. In 1 cycle time, strobe the contents of the CPU internal bus into the X register.
3. In 2 cycles time, continue with the next instruction. (shared with LDA)

Now, the op code AF was, according to the CPU manual, invalid. But due to the way in which the decoder worked, it would match 4 rows.

1. Immediately load next byte from RAM and strobe onto the CPU internal bus.
2. In 1 cycle time, strobe the contents of the CPU internal bus into the Accumulator register.
3. In 1 cycle time, strobe the contents of the CPU internal bus into the X register.
4. In 2 cycles time, continue with the next instruction.

This would cause the CPU to copy the next byte into both the A and X registers simultaneously. It hadn't been intended by the designers, but it just sort of worked - and when it was discovered was used as a sneaky optimisation by programmers.

Some undefined opcodes would do other weird stuff, due to the effects of simultaneously triggering multiple rules in the instruction decoder, and therefore activating multiple different circuits simultaneously. In some cases, there would be conflicts between various internal CPU circuits causing unpredictable effects.

The other effect that could happen was if an op code matched no rows in the decoder table at all. You'll see in the examples above that the last micro-op is always "continue with next instruction". If the op code didn't match a rule which said "continue", then the CPU wouldn't continue, and would just stop until it was power cycled.
 

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
A modern processor will throw an exception in the event of an unrecognizable op code, as well as other errors which occur during execution of specific op codes (e.g. a read to a memory location which either doesn't exist or has been blocked, usually by an OS, by a previous instruction).

When the processor hits an exception it abandons the current instruction, looks at a specified memory location (called a vector) and retrieves the value. It uses that value as an address to jump to.

Normally, during boot up of the OS, the OS will set that memory location (the exception vector) with the location of the OS's exception handler. The job of the exception handler code is to work out what caused the hardware exception and whether it can be recovered.

So, on windows, if an application contains an invalid op code, the processor will fire an exception which will run the windows exception handler. The handler will recognise it as an invalid op code, trace it to a regular app, work out that this isn't fatal to the OS, terminate the application, and put up some sort of error message saying that app.exe has stopped working.

So, the exception handling is done in software, not hardware? That is, there is no exception handling "baked" into the silicon?

If that is so, then when you write your OS, you can decide how the processor handles bad op-codes yourself, yes?
 

Merad

Platinum Member
May 31, 2010
2,586
19
81
So, the exception handling is done in software, not hardware? That is, there is no exception handling "baked" into the silicon?

If that is so, then when you write your OS, you can decide how the processor handles bad op-codes yourself, yes?

No, to the first part, but yes to the second part. Software exceptions and hardware exceptions are very different.

Have you ever used any libraries that dealt with event handlers or callbacks? For example, an OnClick event that calls your function when a button is clicked. Hardware exceptions and interrupts are more analogous to event handlers. One of the first things the OS does when it boots is populate a section of memory called the interrupt vector table. When an exception occurs, the CPU hardware looks in that table for the memory address of a function that it will call to handle the exception.
 

Mark R

Diamond Member
Oct 9, 1999
8,513
16
81
So, the exception handling is done in software, not hardware? That is, there is no exception handling "baked" into the silicon?

If that is so, then when you write your OS, you can decide how the processor handles bad op-codes yourself, yes?

The hardware provides a system for detecting exceptions during processing of instructions, and a method for jumping to a specific software routine.

The software then provides the relevant processing depending on requirements.

For example, on CPUs without specific instruction support (e.g. FPU when it was an option on many CPUs), some OSs provided software emulation support for the instructions. E.g. I had an old ARM based computer, but the standard CPU didn't have an FPU (it was an extra $500 if you wanted the CPU with integrated FPU). If you loaded something like a CAD package, it would crash with an "Illegal operation" exception. However, you could load an optional OS module, which contained an FPU emulator. With that module loaded, the CAD package would run (slow as treacle, but it would run). Essentially, everytime the CPU hit an FPU instruction, it would jump to the OS exception handler, the OS exception handler would check to see if any additional handlers (in this case, the emulator) were installed, and then pass execution onto the emulator.

You could potentially do the same on a modern CPU to provide support for new command sets like AVX, etc. There's not a lot of point in this, because most compilers will produce both AVX and non-AVX code in the same executable, and automatically select the correct version at run-time. Because of the huge overheads of exception handling, the emulated version would be ridiculously slow.
 

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
Have you ever used any libraries that dealt with event handlers or callbacks? For example, an OnClick event that calls your function when a button is clicked.

Yes, 90% of Javascript is centered around that idea.
 

Cogman

Lifer
Sep 19, 2000
10,284
138
106
The hardware provides a system for detecting exceptions during processing of instructions, and a method for jumping to a specific software routine.

The software then provides the relevant processing depending on requirements.

For example, on CPUs without specific instruction support (e.g. FPU when it was an option on many CPUs), some OSs provided software emulation support for the instructions. E.g. I had an old ARM based computer, but the standard CPU didn't have an FPU (it was an extra $500 if you wanted the CPU with integrated FPU). If you loaded something like a CAD package, it would crash with an "Illegal operation" exception. However, you could load an optional OS module, which contained an FPU emulator. With that module loaded, the CAD package would run (slow as treacle, but it would run). Essentially, everytime the CPU hit an FPU instruction, it would jump to the OS exception handler, the OS exception handler would check to see if any additional handlers (in this case, the emulator) were installed, and then pass execution onto the emulator.

You could potentially do the same on a modern CPU to provide support for new command sets like AVX, etc. There's not a lot of point in this, because most compilers will produce both AVX and non-AVX code in the same executable, and automatically select the correct version at run-time. Because of the huge overheads of exception handling, the emulated version would be ridiculously slow.

That's crazy! I can only imagine how slow that thing would be.

Definitely the right way to handle missing instructions is at the compiler or JIT level, not at the OS level. Plowing forward through exceptions is just so wrong.
 

Merad

Platinum Member
May 31, 2010
2,586
19
81
Definitely the right way to handle missing instructions is at the compiler or JIT level, not at the OS level. Plowing forward through exceptions is just so wrong.

Option A:
User installs and runs software. Software fails with error about missing CPU features. User calls support. Support walks user through downloading and installing version of software compiled with emulation features. User runs software. User calls support to complain about software being slow as balls. Support tells user to get a better PC.

Option B:
User installs and runs software. User calls support to complain about software being slow as balls. Support tells user to get a better PC.

When you're emulating hardware features in software, you're pretty much guaranteed to have a bad time no matter how it's implemented, so most companies will take the option that's less painful for them.