87 lines
3.3 KiB
Plaintext
87 lines
3.3 KiB
Plaintext
NEC V20/V30 Bug
|
||
Howard Vigorita
|
||
New York Amateur Computer Club
|
||
|
||
I recently saw a message from Jonathan Platt on a Florida bulletin
|
||
board which mentioned rumors of a bug in the NEC V20/V30 processor.
|
||
For those of you that are interested, I've documented the bug below
|
||
using a V30 chip. Basically, the NEC chips fail to implement the 2
|
||
byte version of the POP instruction. This is not a serious bug;
|
||
the Intel register PUSH & POP instructions are duplicated in two
|
||
sets of instructions and all the assemblers and compilers I've seen
|
||
default to the shorter single byte set in favor of the two byte
|
||
set.
|
||
|
||
For those unfamiliar with the longer PUSH/POP form, the two byte
|
||
form of the PUSH (which works) will be shown first. The 'debug'
|
||
program is fed input from the 'testpush' file. The AX register is
|
||
loaded with FFFF hex, pushed onto the stack with the two byte PUSH,
|
||
then POPed into the CX register with the single byte POP opcode.
|
||
Note that the two byte PUSH is entered using a DB to load in the
|
||
FFF0 opcode. The '-u' command issued below shows that although
|
||
debug's '-a' command defaults to the short form POP, the long form
|
||
is interpreted properly when encountered.
|
||
|
||
A>debug < testpush
|
||
|
||
-a 100
|
||
|
||
0A7F:0100 mov ax,ffff
|
||
0A7F:0103 db ff,f0
|
||
0A7F:0105 pop cx
|
||
0A7F:0106 nop
|
||
0A7F:0107
|
||
|
||
-u 100,106
|
||
|
||
0A7F:0100 B8FFFF MOV AX,FFFF
|
||
0A7F:0103 FFF0 PUSH AX
|
||
0A7F:0105 59 POP CX
|
||
0A7F:0106 90 NOP
|
||
|
||
-g =100 106
|
||
|
||
AX=FFFF BX=0000 CX=FFFF DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
|
||
DS=0A7F ES=0A7F SS=0A7F CS=0A7F IP=0106 NV UP DI PL NZ NA PO NC
|
||
0A7F:0106 90 NOP
|
||
|
||
-q
|
||
|
||
The CX register ended up with FFFF hex as expected.
|
||
|
||
But the inverse operation does not work on the NEC chip. Below, 'testpop'
|
||
feeds input to 'debug'. The AX register is loaded with FFFF, a one byte
|
||
opcode PUSH AX is done, followed by the two byte form of the POP into CX.
|
||
Again, the two byte POP is implemented by DB'ing its 8FC1 opcode. Although
|
||
the SP register (stack pointer) is properly adjusted by the POP, the FFFF
|
||
hex does not end up in CX as it should:
|
||
|
||
A>debug < testpop
|
||
|
||
-a 100
|
||
|
||
0A7F:0100 mov ax,ffff
|
||
0A7F:0103 push ax
|
||
0A7F:0104 db 8f,c1
|
||
0A7F:0106 nop
|
||
0A7F:0107
|
||
|
||
-u 100,106
|
||
|
||
0A7F:0100 B8FFFF MOV AX,FFFF
|
||
0A7F:0103 50 PUSH AX
|
||
0A7F:0104 8FC1 POP CX
|
||
0A7F:0106 90 NOP
|
||
|
||
-g =100 106
|
||
|
||
AX=FFFF BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
|
||
DS=0A7F ES=0A7F SS=0A7F CS=0A7F IP=0106 NV UP DI PL NZ NA PO NC
|
||
0A7F:0106 90 NOP
|
||
|
||
-q
|
||
|
||
The above 'feature' can be exploited in distinguishing between NEC and
|
||
Intel chips. It is much simpler than the technique of issuing a unique
|
||
NEC instruction and intercepting the error trap interrupt.
|
||
|