Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Intel 8086 opcodes

1,646 views
Skip to first unread message

roch...@laposte.net

unread,
Aug 28, 2007, 8:25:07 AM8/28/07
to
Is anybody out there
who would be interested in starting a thread
about the exact patterns of the Intel 8086 opcodes?

When disassembling ASM-86 Version 1.1,
I could not prevent myself from noticing that
it was generating code different from RASM 1.4.

To study where was the difference, I wrote
an I8086.A86 file...

Unfortunately, I have not been able to
generate any of the 82 opcodes...

What am I missing?

(The following listing was produced using
RASM 1.4 under DR-DOS. By the way, anybody
has a RASM manual? My "Programmer's Utility
Guide" says that RASM has 25 error messages,
but when I dump it, I find much more (even one
in lowercase...) and the 8087 mnemonics,
which are not mentioned anywhere... Also,
the EXE file is 4 or 5 years older than the PUG.)

Yours Sincerely,
Mr Emmanuel Roche


; I8086.A86
; ---------
;
; Intel 8086 opcodes in numerical order.
;
;--------------------------------
; Small Memory model.

CSEG
DSEG
ORG 0100h

;--------------------------------
ORG 1111h
1111 23 label_b db 23h

ORG 2222h
2222 8967 label_w dw 6789h
;--------------------------------
CSEG $
;--------------------------------
adr:
0000 00061111 R add label_b,al
0004 01062222 R add label_w,ax
0008 02061111 R add al,label_b
000C 03062222 R add ax,label_w
0010 0412 add al,12h
0012 055634 add ax,3456h
0015 06 push es
0016 07 pop es
0017 08061111 R or label_b,al
001B 09062222 R or label_w,ax
001F 0A061111 R or al,label_b
0023 0B062222 R or ax,label_w
0027 0C12 or al,12h
0029 0D5634 or ax,3456h
002C 0E push cs
; 0F -- pop cs -- not used
002D 10061111 R adc label_b,al
0031 11062222 R adc label_w,ax
0035 12061111 R adc al,label_b
0039 13062222 R adc ax,label_w
003D 1412 adc al,12H
003F 155634 adc ax,3456h
0042 16 push ss
0043 17 pop ss
0044 18061111 R sbb label_b,al
0048 19062222 R sbb label_w,ax
004C 1A061111 R sbb al,label_b
0050 1B062222 R sbb ax,label_w
0054 1C12 sbb al,12h
0056 1D5634 sbb ax,3456h
0059 1E push ds
005A 1F pop ds
005B 20061111 R and label_b,al
005F 21062222 R and label_w,ax
0063 22061111 R and al,label_b
0067 23062222 R and ax,label_w
006B 2412 and al,12h
006D 255634 and ax,3456h
0070 2600060000 add es:.0,al
0075 27 daa
0076 28061111 R sub label_b,al
007A 29062222 R sub label_w,ax
007E 2A061111 R sub al,label_b
0082 2B062222 R sub ax,label_w
0086 2C12 sub al,12h
0088 2D5634 sub ax,3456h
008B 2E00060000 add cs:.0,al
0090 2F das
0091 30061111 R xor label_b,al
0095 31062222 R xor label_w,ax
0099 32061111 R xor al,label_b
009D 33062222 R xor ax,label_w
00A1 3412 xor al,12h
00A3 355634 xor ax,3456h
00A6 3600060000 add ss:.0,al
00AB 37 aaa
00AC 38061111 R cmp label_b,al
00B0 39062222 R cmp label_w,ax
00B4 3A061111 R cmp al,label_b
00B8 3B062222 R cmp ax,label_w
00BC 3C12 cmp al,12h
00BE 3D5634 cmp ax,3456h
00C1 00060000 add ds:.0,al ; 3E ???
00C5 3F aas
00C6 40 inc ax
00C7 41 inc cx
00C8 42 inc dx
00C9 43 inc bx
00CA 44 inc sp
00CB 45 inc bp
00CC 46 inc si
00CD 47 inc di
00CE 48 dec ax
00CF 49 dec cx
00D0 4A dec dx
00D1 4B dec bx
00D2 4C dec sp
00D3 4D dec bp
00D4 4E dec si
00D5 4F dec di
00D6 50 push ax
00D7 51 push cx
00D8 52 push dx
00D9 53 push bx
00DA 54 push sp
00DB 55 push bp
00DC 56 push si
00DD 57 push di
00DE 58 pop ax
00DF 59 pop cx
00E0 5A pop dx
00E1 5B pop bx
00E2 5C pop sp
00E3 5D pop bp
00E4 5E pop si
00E5 5F pop di
; 60-6F -- not used (8087 instructions)
disp:
00E6 70FE 00E6 jo disp
00E8 71FC 00E6 jno disp
00EA 72FA 00E6 jb disp ; 72
00EC 72F8 00E6 jnae disp ; 72
00EE 72F6 00E6 jc disp ; 72
00F0 73F4 00E6 jnb disp ; 73
00F2 73F2 00E6 jae disp ; 73
00F4 73F0 00E6 jnc disp ; 73
00F6 74EE 00E6 je disp ; 74
00F8 74EC 00E6 jz disp ; 74
00FA 75EA 00E6 jne disp ; 75
00FC 75E8 00E6 jnz disp ; 75
00FE 76E6 00E6 jbe disp ; 76
0100 76E4 00E6 jna disp ; 76
0102 77E2 00E6 jnbe disp ; 77
0104 77E0 00E6 ja disp ; 77
0106 78DE 00E6 js disp
0108 79DC 00E6 jns disp
010A 7ADA 00E6 jp disp ; 7A
010C 7AD8 00E6 jpe disp ; 7A
010E 7BD6 00E6 jnp disp ; 7B
0110 7BD4 00E6 jpo disp ; 7B
0112 7CD2 00E6 jl disp ; 7C
0114 7CD0 00E6 jnge disp ; 7C
0116 7DCE 00E6 jnl disp ; 7D
0118 7DCC 00E6 jge disp ; 7D
011A 7ECA 00E6 jle disp ; 7E
011C 7EC8 00E6 jng disp ; 7E
011E 7FC6 00E6 jnle disp ; 7F
0120 7FC4 00E6 jg disp ; 7F
0122 8006111112 R add label_b,12h ; 80
0127 800E111112 R or label_b,12h ; 80
012C 8016111112 R adc label_b,12h ; 80
0131 801E111112 R sbb label_b,12h ; 80
0136 8026111112 R and label_b,12h ; 80
013B 802E111112 R sub label_b,12h ; 80
0140 8036111112 R xor label_b,12h ; 80
0145 803E111112 R cmp label_b,12h ; 80
014A 810622225634 R add label_w,3456h ; 81
0150 810E22225634 R or label_w,3456h ; 81
0156 811622225634 R adc label_w,3456h ; 81
015C 811E22225634 R sbb label_w,3456h ; 81
0162 812622225634 R and label_w,3456h ; 81
0168 812E22225634 R sub label_w,3456h ; 81
016E 813622225634 R xor label_w,3456h ; 81
0174 813E22225634 R cmp label_w,3456h ; 81
017A 03E8 add bp,ax ; 82
; 82 -- mod 001 r/m -- not used
017C 13E8 adc bp,ax ; 82
017E 1BE8 sbb bp,ax ; 82
; 82 -- mod 100 r/m -- not used
0180 2BE8 sub bp,ax ; 82
; 82 -- mod 110 r/m -- not used
0182 3BE8 cmp bp,ax ; 82
0184 83C512 add bp,12h ; 83
; 83 -- mod 001 r/m -- not used
0187 83D512 adc bp,12h ; 83
018A 83DD12 sbb bp,12h ; 83
; 83 -- mod 100 r/m -- not used
018D 83ED12 sub bp,12h ; 83
; 83 -- mod 110 r/m -- not used
0190 83FD12 cmp bp,12h ; 83
0193 84061111 R test label_b,al
0197 85062222 R test label_w,ax
019B 86061111 R xchg al,label_b
019F 87062222 R xchg ax,label_w
01A3 884600 mov [bp],al
01A6 894600 mov [bp],ax

01A9 8AC1 mov al,cl
01AB 8BC1 mov ax,cx
01AD 8CD8 mov ax,ds
; 8C -- xx 1xxxxx -- not used
01AF 8D061111 R lea ax,label_b
01B3 8ED8 mov ds,ax
; 8E -- xx 1xxxxx -- not used
01B5 8F062222 R pop label_w
; 8F -- xx 001 xx -- not used
; 8F -- xx 010 xx -- not used
; 8F -- xx 011 xx -- not used
; 8F -- xx 100 xx -- not used
; 8F -- xx 101 xx -- not used
; 8F -- xx 110 xx -- not used
; 8F -- xx 111 xx -- not used
01B9 90 nop
01BA 91 xchg ax,cx
01BB 92 xchg ax,dx
01BC 93 xchg ax,bx
01BD 94 xchg ax,sp
01BE 95 xchg ax,bp
01BF 96 xchg ax,si
01C0 97 xchg ax,di
01C1 98 cbw
01C2 99 cwd
01C3 9A00000000 R callf adr
01C8 9B wait
01C9 9C pushf
01CA 9D popf
01CB 9E sahf
01CC 9F lahf
01CD A01111 R mov al,label_b
01D0 A12222 R mov ax,label_w
01D3 A21111 R mov label_b,al
01D6 A32222 R mov label_w,ax
01D9 A4 movsb
01DA A5 movsw
01DB A6 cmpsb
01DC A7 cmpsw
01DD A812 test al,12h
01DF A95634 test ax,3456h
01E2 AA stosb
01E3 AB stosw
01E4 AC lodsb
01E5 AD lodsw
01E6 AE scasb
01E7 AF scasw
01E8 B012 mov al,12h
01EA B112 mov cl,12h
01EC B212 mov dl,12h
01EE B312 mov bl,12h
01F0 B412 mov ah,12h
01F2 B512 mov ch,12h
01F4 B612 mov dh,12h
01F6 B712 mov bh,12h
01F8 B85634 mov ax,3456h
01FB B95634 mov cx,3456h
01FE BA5634 mov dx,3456h
0201 BB5634 mov bx,3456h
0204 BC5634 mov sp,3456h
0207 BD5634 mov bp,3456h
020A BE5634 mov si,3456h
020D BF5634 mov di,3456h
; C0 -- not used
; C1 -- not used
0210 C25634 ret 3456h
0213 C3 ret
0214 C47E06 les di,6[bp]
0217 C57606 lds si,6[bp]
021A C606111112 R mov label_b,12h
; C6 -- xx 001 xxx -- not used
; C6 -- xx 010 xxx -- not used
; C6 -- xx 011 xxx -- not used
; C6 -- xx 100 xxx -- not used
; C6 -- xx 101 xxx -- not used
; C6 -- xx 110 xxx -- not used
; C6 -- xx 111 xxx -- not used
021F C70622225634 R mov label_w,3456h
; C7 -- xx 001 xxx -- not used
; C7 -- xx 010 xxx -- not used
; C7 -- xx 011 xxx -- not used
; C7 -- xx 100 xxx -- not used
; C7 -- xx 101 xxx -- not used
; C7 -- xx 110 xxx -- not used
; C7 -- xx 111 xxx -- not used
; C8 -- not used
; C9 -- not used
0225 CA5634 retf 3456h
0228 CB retf
0229 CC int 3
022A CD12 int 12h
022C CE into
022D CF iret
022E D0C0 rol al,1
0230 D0C8 ror al,1
0232 D0D0 rcl al,1
0234 D0D8 rcr al,1
0236 D0E0 sal al,1 ; D0
0238 D0E0 shl al,1 ; D0
023A D0E8 shr al,1
; D0 -- xx 110 xxx -- not used
023C D0F8 sar al,1
023E D1C0 rol ax,1
0240 D1C8 ror ax,1
0242 D1D0 rcl ax,1
0244 D1D8 rcr ax,1
0246 D1E0 sal ax,1 ; D1
0248 D1E0 shl ax,1 ; D1
024A D1E8 shr ax,1
; D1 -- xx 110 xxx -- not used
024C D1F8 sar ax,1
024E D2C1 rol cl,cl
0250 D2C9 ror cl,cl
0252 D2D1 rcl cl,cl
0254 D2D9 rcr cl,cl
0256 D2E1 sal cl,cl ; D2
0258 D2E1 shl cl,cl ; D2
025A D2E9 shr cl,cl
; D0 -- xx 110 xxx -- not used
025C D2F9 sar cl,cl
025E D3C1 rol cx,cl
0260 D3C9 ror cx,cl
0262 D3D1 rcl cx,cl
0264 D3D9 rcr cx,cl
0266 D3E1 sal cx,cl ; D3
0268 D3E1 shl cx,cl ; D3
026A D3E9 shr cx,cl
; D0 -- xx 110 xxx -- not used
026C D3F9 sar cx,cl
026E D40A aam
0270 D50A aad
; D6 -- not used
; xlat -- does not work...
0272 D7 xlat al ; Work with
a register???
0273 D8C0 esc 0,al
0275 D9C1 esc 8,cl
0277 DAC2 esc 16,dl
0279 DBC3 esc 24,bl
027B DCC0 esc 32,al
027D DDC1 esc 40,cl
027F DEC2 esc 48,dl
0281 DFC3 esc 56,bl
disp2:
0283 E0FE 0283 loopne disp2 ; E0
0285 E0FC 0283 loopnz disp2 ; E0
0287 E1FA 0283 loope disp2 ; E1
0289 E1F8 0283 loopz disp2 ; E1
028B E2F6 0283 loop disp2
028D E3F4 0283 jcxz disp2
028F E412 in al,12h
0291 E5FF in ax,0FFh
0293 E612 out 12h,al
0295 E7FF out 0FFh,ax
0297 E866FD 0000 call adr
029A E963FD 0000 jmp adr
029D EA00000000 R jmpf adr
02A2 EBDF 0283 jmps disp2
02A4 EC in al,dx
02A5 ED in ax,dx
02A6 EE out dx,al
02A7 EF out dx,ax
02A8 F090 lock nop
; F1 -- not used
02AA F290 repne nop ; F2
02AC F290 repnz nop ; F2
02AE F390 rep nop ; F3
02B0 F390 repe nop ; F3
02B2 F390 repz nop ; F3
02B4 F4 hlt
02B5 F5 cmc
02B6 F606111112 R test label_b,12h
; F6 -- xx 001 xxx -- not used
02BB F6161111 R not label_b
02BF F61E1111 R neg label_b
02C3 F6261111 R mul label_b
02C7 F62E1111 R imul label_b
02CB F6361111 R div label_b
02CF F63E1111 R idiv label_b
02D3 F70622225634 R test label_w,3456h
; F7 -- xx 001 xxx -- not used
02D9 F7162222 R not label_w
02DD F71E2222 R neg label_w
02E1 F7262222 R mul label_w
02E5 F72E2222 R imul label_w
02E9 F7362222 R div label_w
02ED F73E2222 R idiv label_w
02F1 F8 clc
02F2 F9 stc
02F3 FA cli
02F4 FB sti
02F5 FC cld
02F6 FD std
02F7 FE061111 R inc label_b
02FB FE0E1111 R dec label_b
; FE -- xx 010 xxx -- not used
; FE -- xx 011 xxx -- not used
; FE -- xx 100 xxx -- not used
; FE -- xx 101 xxx -- not used
; FE -- xx 110 xxx -- not used
; FE -- xx 111 xxx -- not used
02FF FF062222 R inc label_w
0303 FF0E2222 R dec label_w
0307 FF162222 R call word ptr label_w
030B FF5600 call word ptr 0[bp]
030E FF262222 R jmp word ptr label_w
0312 FF6600 jmp word ptr 0[bp]
0315 FF362222 R push word ptr label_w
; FF -- xx 111 xxx -- not used

;--------------------------------
END


End of assembly. Number of errors: 0. Use factor: 0%


EOF

s_dub...@yahoo.com

unread,
Aug 28, 2007, 3:37:54 PM8/28/07
to
On Aug 28, 6:25 am, roche...@laposte.net wrote:
> Is anybody out there
> who would be interested in starting a thread
> about the exact patterns of the Intel 8086 opcodes?
>

Yes, Hello Emmanuel...

First, do you have this..?

http://www.intel.com/design/intarch/manuals/270950.htm

It has the opcode construction tables in the appendixes. And the 8087
stuff IIRC.

> When disassembling ASM-86 Version 1.1,
> I could not prevent myself from noticing that
> it was generating code different from RASM 1.4.
>

I'm sorry I don't see what you mean. ASM86 outputs a binary form,
RASM a relocatable form for LINK86.

> To study where was the difference, I wrote
> an I8086.A86 file...
>
> Unfortunately, I have not been able to
> generate any of the 82 opcodes...
>
> What am I missing?

Probably at least two things:

1) The 8086 byte codes are variable length depending on the
instruction form. {1..6 IIRC for the 8086, more max length for the
later cpu's}.

2) The destination address, say for a call or jump, is not hard coded
into the instruction itself, but the destination's relative offset is,
that is, the distance from the current instruction makes the
destination address, the distance is the address encoded into the byte
code for the (let's say) jump instruction. So, for:

start: jmp end
start2: jmp end
end: nop

The two instructions 'jmp end' will yield different byte strings
because 'start:' is further from 'end:' than 'start2:' is.

Under 1), above, the byte 82h is an information byte about how the
rest of the instruction is to be interpreted, 82h means immediate byte
source, with a register or memory destination, operation. Other
byte[s] determine just what operation, register, or memory.

Maybe I'm not answering your question, maybe I didn't understand your
question. It is a start.

The source to ASM86 is available, I think it is in the DRIPAK.ZIP, but
most of it is PL/M source. The programmer uses the 'code macro'
method to construct the byte codes for the instructions.

You could also research the Netwide Assembler source code written in
C, but there is alot to wade through. But, using the the appendix and
sid, is easiest, poke in some bytes and let sid decode it, [list]. Or,
try some instructions to see how they assemble into byte strings...

--------------------------------------------------
*** Symbolic Instruction Debugger *** Release 3.2
Copyright (c) 1983,1984,1985,1988,1990,1991
Digital Research, Inc. All Rights Reserved
--------------------------------------------------

#f0,+1ff,0
#x
AX BX CX DX SP BP SI DI CS DS SS ES
IP
--I------ 0000 0000 0000 0000 0000 0000 0000 0000 0BF8 0BF8 0BF8 0BF8
0100
ADD [BX+SI],AL =00
#a0
0BF8:0000 jmp 100
0BF8:0003 jmp 100
0BF8:0006 jmp 100
0BF8:0009 .
#d0,f
0BF8:0000 E9 FD 00 E9 FA 00 E9 F7 00 00 00 00 00 00 00
00 ................
#

So.. the destination of the first jump is 00FDh in distance, the
second is 00FAh away, the third is 00F7h away.
E9 FD 00
E9 FA 00
E9 F7 00

see?

Steve

Barry Watzman

unread,
Aug 28, 2007, 10:09:40 PM8/28/07
to
I think that a more relevant point is that there are different binary
codes that yield the exact same opcode execution. I don't have an
example, but different assemblers could and did produce different binary
from the exact same source, but they would execute the exact same way.
There were some possible ambiguities in how some instructions could be
expressed in binary object code.

roch...@laposte.net

unread,
Aug 29, 2007, 8:55:27 AM8/29/07
to
Hello, Steve!

> First, do you have this..?

No. I only have the "Intel 8086 Family User's Guide" (which I find
useless). I just found on the Internet a 1981 Intel manual which
should help me. I should receive it in one week.

> > When disassembling ASM-86 Version 1.1,
> > I could not prevent myself from noticing that
> > it was generating code different from RASM 1.4.
>
> I'm sorry I don't see what you mean. ASM86 outputs a binary form,
> RASM a relocatable form for LINK86.

ASM-86 (can) outputs an Intel 8086 hex file, RASM-86 an Intel OBJ
file.

By "code", I was meaning: the resulting CMD file (after GENCMDing it,
or LINKing it). ASM-86 and RASM-86 (and PL/M-86) all don't produce the
same "code". (And SID-86 has its own Assembler and Lister (like Good
Old 8-bit SID), but let us not mix everything.)

> > To study where was the difference, I wrote
> > an I8086.A86 file...
>
> > Unfortunately, I have not been able to
> > generate any of the 82 opcodes...
>
> > What am I missing?

017A 03E8 add bp,ax ; 82


; 82 -- mod 001 r/m -- not used
017C 13E8 adc bp,ax ; 82
017E 1BE8 sbb bp,ax ; 82
; 82 -- mod 100 r/m -- not used
0180 2BE8 sub bp,ax ; 82
; 82 -- mod 110 r/m -- not used
0182 3BE8 cmp bp,ax ; 82

You will note that none of the above lines start with an 82 opcodes.

This is my question: I am able to generate all the other opcodes, but
how do I generate the 82 opcodes?

> Maybe I'm not answering your question, maybe I didn't understand your
> question. It is a start.

Yes. Thanks.

> The source to ASM86 is available, I think it is in the DRIPAK.ZIP, but
> most of it is PL/M source. The programmer uses the 'code macro'
> method to construct the byte codes for the instructions.

I should know: I have disassembled ASM-86 Version 1.1 (that is to say;
precisely the one whose source code is available... Maybe it is a
coincidence?) (By the way, this use of the "codemacro" concept means
that ASM-86 is a table-driven assembler...)

> You could also research the Netwide Assembler source code written in
> C, but there is alot to wade through. But, using the the appendix and
> sid, is easiest, poke in some bytes and let sid decode it, [list]. Or,
> try some instructions to see how they assemble into byte strings...

1) Since I am a CP/M fan, I could not care less about other assemblers
running under other operating systems. What I want is to keep using CP/
M Plus on an IBM Clown, so I need an 8086 assembler, and I need it to
be the best possible (so, at the minimum, to generate all the Intel
8086 opcodes...).

2) SID-86 has a totally different way to assemble and list programs
being debugged. So, let us not mix everything, and concentrate
precisely on the Intel 8086 instruction set. (I hope that you know
that Digital Research assemblers have a variant of 4 Intel 8086
mnemonics?)

> So.. the destination of the first jump is 00FDh in distance, the
> second is 00FAh away, the third is 00F7h away.
> E9 FD 00
> E9 FA 00
> E9 F7 00
>
> see?

Yes. These are E9 opcodes, not 82 opcodes. QED.

> > (The following listing was produced using
> > RASM 1.4 under DR-DOS. By the way, anybody
> > has a RASM manual? My "Programmer's Utility
> > Guide" says that RASM has 25 error messages,
> > but when I dump it, I find much more (even one
> > in lowercase...) and the 8087 mnemonics,
> > which are not mentioned anywhere... Also,
> > the EXE file is 4 or 5 years older than the PUG.)

To finish:

1) My copy of the PUG says that RASM-86 has 25 error messages. I
counted: RASM-86 Version 1.4 has 35...

2) My copy of the PUG only mention 8086 mnemonics, a dump of the
program shows that it understands8087 mnemonics. (At first sight,
RASM-86 uses non-standard 8087 mnemonics. Or, some of them are non-
standard.)

So, if someone has a later guide or manual giving the exact list of
the mnemonics recognized by RASM-86, he is welcomed...

Roger Ivie

unread,
Aug 29, 2007, 10:55:34 AM8/29/07
to
On 2007-08-29, roch...@laposte.net <roch...@laposte.net> wrote:
> 017A 03E8 add bp,ax ; 82

I don't understand why you think this should be an 82 opcode. As I
read the various references on the net, I see an 82 opcode being
more like ADD DS:[BX+SI],Imm8. And MS-DOS debug concurs:

-u100
0B70:0100 820000 ADD BYTE PTR [BX+SI],00

I don't know the RASM syntax for this instruction, but I'm pretty
certain it doesn't involve either BP or AX.
--
roger ivie
ri...@ridgenet.net

s_dub...@yahoo.com

unread,
Aug 29, 2007, 12:29:03 PM8/29/07
to
On Aug 29, 6:55 am, roche...@laposte.net wrote:
> Hello, Steve!
>
> > First, do you have this..?
>
> No. I only have the "Intel 8086 Family User's Guide" (which I find
> useless). I just found on the Internet a 1981 Intel manual which
> should help me. I should receive it in one week.
>
Yes, perhaps you cannot use a .pdf file. It would be convenient to
work off a common, commonly available, document.

> > > To study where was the difference, I wrote
> > > an I8086.A86 file...
>
> > > Unfortunately, I have not been able to
> > > generate any of the 82 opcodes...
>
> > > What am I missing?
>

Point 3 is what Barry mentions.
3) There is more than one avenue to the same destination.

> 017A 03E8 add bp,ax ; 82
> ; 82 -- mod 001 r/m -- not used
> 017C 13E8 adc bp,ax ; 82
> 017E 1BE8 sbb bp,ax ; 82
> ; 82 -- mod 100 r/m -- not used
> 0180 2BE8 sub bp,ax ; 82
> ; 82 -- mod 110 r/m -- not used
> 0182 3BE8 cmp bp,ax ; 82
>
> You will note that none of the above lines start with an 82 opcodes.
>
> This is my question: I am able to generate all the other opcodes, but
> how do I generate the 82 opcodes?
>

A) Well, you definitely won't with those instructions, as Roger says,
the instruction form is OP reg8|mem8,Immediate Value8. Plus, it is a
5 bytes long interpretation.
ex. ADD AX,9

B) Still, there is the issue of the assembler itself, it may optimize
the instruction to an alternate convenient form - you may not be able
to generate the 5 byte instruction with the assembler except through
the inline DB directive.

>
> > So.. the destination of the first jump is 00FDh in distance, the
> > second is 00FAh away, the third is 00F7h away.
> > E9 FD 00
> > E9 FA 00
> > E9 F7 00
>
> > see?
>
> Yes. These are E9 opcodes, not 82 opcodes. QED.
>

Very well, returning to SID...

--------------------------------------------------
*** Symbolic Instruction Debugger *** Release 3.2
Copyright (c) 1983,1984,1985,1988,1990,1991
Digital Research, Inc. All Rights Reserved
--------------------------------------------------

#f0,+1ff,0
#a0
0BF8:0000 add ax,5
0BF8:0003 adc ax,6
0BF8:0006 sbb ax,7
0BF8:0009 cmp ax,8
0BF8:000C .
#d0,f
0BF8:0000 05 05 00 15 06 00 1D 07 00 3D 08 00 00 00 00
00 .........=......

We see above that SID generates the short form of these instructions,
no 82h.

#a10
0BF8:0010 add [100],9
ambiguous operand
0BF8:0010 add byte[100],9
0BF8:0015 .
#d10,1f
0BF8:0010 80 06 00 01 09 00 00 00 00 00 00 00 00 00 00
00 ................

The above, less common instruction ADD mem,immed - is generated as the
5 byte form, but still no 82H, but an equivalently interpreted form.

But, will SID at least correctly decode the 82h form?
#s20
0BF8:0020 00 82
0BF8:0021 00 06
0BF8:0022 00 00
0BF8:0023 00 01
0BF8:0024 00 09
0BF8:0025 00 .
#l20,+5
0BF8:0020 ADD BYTE [0100],09
0BF8:0025 ADD [BX+SI],AL
#

QED.

Steve

s_dub...@yahoo.com

unread,
Aug 29, 2007, 1:34:38 PM8/29/07
to
On Aug 29, 6:55 am, roche...@laposte.net wrote:
> Hello, Steve!

> > You could also research the Netwide Assembler source code written in


> > C, but there is alot to wade through. But, using the the appendix and
> > sid, is easiest, poke in some bytes and let sid decode it, [list]. Or,
> > try some instructions to see how they assemble into byte strings...
>
> 1) Since I am a CP/M fan, I could not care less about other assemblers
> running under other operating systems. What I want is to keep using CP/
> M Plus on an IBM Clown, so I need an 8086 assembler, and I need it to
> be the best possible (so, at the minimum, to generate all the Intel
> 8086 opcodes...).
>

I have no criticism of what you say, just an observation. Gary cross
developed CP/M itself.

'to generate all the Intel 8086 opcodes', including the 32bit forms?
I've done alittle with code macro definitions to try some of this,
which works in pricinple, but it is a big effort, and I'm not sure the
internal code macro symbol table is big enough to hold the entire
effort. That is why I turned my attention to NASM.

> 2) SID-86 has a totally different way to assemble and list programs
> being debugged. So, let us not mix everything, and concentrate
> precisely on the Intel 8086 instruction set. (I hope that you know
> that Digital Research assemblers have a variant of 4 Intel 8086
> mnemonics?)
>

Do you have a table of these? I sense another Roche document is
needed!

It is funny that the SID disassembly syntax is very close to NASM's
syntax, closer to NASM than to ASM86!

But, after all, we are talking about variance in Syntax, not unlike
that found in various Basics, no?

Steve

p.s. in my previous example I used ex. ADD AX,9 in following your
listing, but as I noted the 82h opcode is for a form of ADD AL,9 that
is, OP reg8,immed8 and I wasn't clear enough about that.

Jonathan Graham Harston

unread,
Aug 30, 2007, 10:09:17 AM8/30/07
to
>Message-ID: <E1IQ6zn-...@stasis.kostecke.net>


s_dub...@yahoo.com wrote:
> http://www.intel.com/design/intarch/manuals/270950.htm
>
> It has the opcode construction tables in the appendixes. And the 8087

I'll grab that, thanks.


> start: jmp end
> start2: jmp end
> end: nop
> The two instructions 'jmp end' will yield different byte strings
> because 'start:' is further from 'end:' than 'start2:' is.

There are some instruction sequences I just couldn't work out how
to get my assembler to issue.
http://mdfs.net/Docs/Comp/80x86/OpDump is what I managed some
months ago when I was last messing about with it.

--
J.G.Harston - j...@arcade.demon.co.uk - mdfs.net/User/JGH
BBC IDE Hard Drive Interface - http://mdfs.net/Info/Comp/BBC/IDE

Jonathan Graham Harston

unread,
Aug 30, 2007, 10:09:17 AM8/30/07
to
>Message-ID: <E1IQPG4-...@stasis.kostecke.net>


Roger Ivie <ri...@ridgenet.net> wrote:
> On 2007-08-29, roch...@laposte.net <roch...@laposte.net> wrote:
> > 017A 03E8 add bp,ax ; 82
>
> I don't understand why you think this should be an 82 opcode. As I
> read the various references on the net, I see an 82 opcode being
> more like ADD DS:[BX+SI],Imm8. And MS-DOS debug concurs:
>
> -u100
> 0B70:0100 820000 ADD BYTE PTR [BX+SI],00

ADD BYTE PTR [BX+SI],0 gives 80 00 00 on my assembler. I've never
managed to get it to emit an 82 sequence.

There are difference opcode sequences that produce the same effect
due to different encoding producing the same result, so it's down
to the assembler author what particular sequence it emits. It will
usually emit the shortest sequence. Just like LD HL,(nnnn) on the
Z80:

2A nn nn LD HL,(nnnn)
ED 6B nn nn LD HL,(nnnn)The most perfect world is an imperfect world as the imperfections
give people a reason to strive to change it.

Jonathan Graham Harston

unread,
Aug 30, 2007, 10:09:16 AM8/30/07
to
>Message-ID: <E1IQ0g0-...@stasis.kostecke.net>


roch...@laposte.net wrote:
> Is anybody out there
> who would be interested in starting a thread
> about the exact patterns of the Intel 8086 opcodes?

http://mdfs.net/Docs/Comp/80x86/OpList is what I managed to put
together when trying to write an 80x86 module for my disassembler.
It seems rediculously difficult tracking down 80x86 opcode
information. Loads of documents saying "ADD AL,AL" but almost
nothing saying "00 nn nn : ADD rn,rn".Sheffield Boundary Review at http://mdfs.net/User/JGH/Docs/Politics/ParlReview

s_dub...@yahoo.com

unread,
Aug 30, 2007, 10:11:52 PM8/30/07
to
On Aug 30, 8:09 am, j...@arcade.demon.co.uk (Jonathan Graham Harston)
wrote:
> >Message-ID: <E1IQ6zn-0004ad...@stasis.kostecke.net>

> s_dubrov...@yahoo.com wrote:
> >http://www.intel.com/design/intarch/manuals/270950.htm
>
> > It has the opcode construction tables in the appendixes. And the 8087
>
> I'll grab that, thanks.
>
> > start: jmp end
> > start2: jmp end
> > end: nop
> > The two instructions 'jmp end' will yield different byte strings
> > because 'start:' is further from 'end:' than 'start2:' is.
>
> There are some instruction sequences I just couldn't work out how
> to get my assembler to issue.http://mdfs.net/Docs/Comp/80x86/OpDumpis what I managed some

> months ago when I was last messing about with it.
>
> --
> J.G.Harston - j...@arcade.demon.co.uk - mdfs.net/User/JGH
> BBC IDE Hard Drive Interface -http://mdfs.net/Info/Comp/BBC/IDE

I haven't checked out your reference yet, but I wanted to post this
reference while I have it handy. It is a look at the instruction set
through the eyes of Octal, perhaps you've considered this..

http://groups.google.com/group/comp.sys.intel/browse_frm/thread/e0bd3216597a950c/69019e5471c90dc3?lnk=gst&q=Mark+Hopkins&rnum=23#69019e5471c90dc3

Steve

roch...@laposte.net

unread,
Aug 31, 2007, 6:54:57 AM8/31/07
to
Hello, Steve and Jonathan!

With both of you, I am convinced that we will manage to understand the
8086 opcodes.


> I have no criticism of what you say, just an observation. Gary cross
> developed CP/M itself.

Yes, using IBM S/360 and DECsystem-10 mainframes. Me, I am using one
IBM Clown running at 400-MHz (100 times faster than my Beloved Epson
QX-10) as my "mainframe". My main word-processing machine is a
portable running at 6-MHz. I save the files on a 3.5" floppy, then
either publish them here, or store them on the hard disk of my main
machine, running under DR-DOS.

> 'to generate all the Intel 8086 opcodes', including the 32bit forms?
> I've done alittle with code macro definitions to try some of this,
> which works in pricinple, but it is a big effort, and I'm not sure the
> internal code macro symbol table is big enough to hold the entire
> effort. That is why I turned my attention to NASM.

There are about 290 tables to define the 8086 opcodes of ASM-86
Version 1.1, since a table is required for all the forms of the
mnemonics... (17 for "MOV"!) But this is the only way to get a table-
driven assembler. And it works. (For your information, there is 321
procedures in the assembler, so that means that RASM-86 has more
tables defining the opcodes than procedures to produce them! As you
may remember, I have disassembled, ASM Version 2, MAC Version 2, SID
Version 3, and ZSID Version 2.5. I am realizing that the 8086 is even
worse than the Z-80, with its 820 opcodes... Sigh! All that just to
keep using CP/M Plus on IBM Clowns... Too bad Zilog never managed to
produce faster Z-80-compatible microprocessors. Now, the only
solution, to keep using CP/M Plus, is to run it on an IBM Clown, so to
manage its awful CPU.)

> > (...) (I hope that you know


> > that Digital Research assemblers have a variant of 4 Intel 8086
> > mnemonics?)
>
> Do you have a table of these? I sense another Roche document is
> needed!

Are you joking, Steve? It is in all my copies of ASM-86 and RASM-86
guides: RETF, CALLF, CALLS, and JMPS. This way, no "short" word is
needed, thus reducing a little the verbosity of the instruction set.

> It is funny that the SID disassembly syntax is very close to NASM's
> syntax, closer to NASM than to ASM86!

As my I8086.A86 program shows, there are several opcodes that are
produced by different mnemonics. This is the first time that I see a
CPU with this horror. That means that the debugger can only use of
these forms, and that, when debugging, you will NEVER see some
mnemonics that are in your source code! This is totally silly, crazy,
etc. The Assemble portion of SID-86 is probably the shortest 8086
assembler possible. But I have not yet disassembled it: one step at a
time.

Last week, jokingly, I wrote to one of my correspondent that I had
nothing to read... Yesterday, I received 4 messages needing long
technical replies... Last night, I only managed to write one answer...
This night, I will work on this thread, so I can publish my answer
tomorrow, the last day of this week where I will be able to reach the
Internet.

Tom Lake

unread,
Aug 31, 2007, 7:37:01 AM8/31/07
to

<roch...@laposte.net> wrote in message
news:1188557697.1...@x35g2000prf.googlegroups.com...

Too bad Zilog never managed to
> produce faster Z-80-compatible microprocessors. Now, the only
> solution, to keep using CP/M Plus, is to run it on an IBM Clown, so to
> manage its awful CPU.)

50 MHz isn't fast enough for you? It runs rings around even the first
Pentium
@ 60 MHz. (for operations that don't need the math coprocessor!).

Tom Lake


glen herrmannsfeldt

unread,
Aug 31, 2007, 9:30:20 AM8/31/07
to
roch...@laposte.net wrote:
(snip)

> As my I8086.A86 program shows, there are several opcodes that are
> produced by different mnemonics. This is the first time that I see a
> CPU with this horror. That means that the debugger can only use of
> these forms, and that, when debugging, you will NEVER see some
> mnemonics that are in your source code!

I don't think it is that unusual, though maybe worse here.

In many cases NOP is another machine instruction that doesn't
actually do anything. A move of a register to itself, or
a conditional branch with the condition turned off.
I believe the 8080 NOP is MOV A,A but someone here will tell
me if it isn't.

S/360 has the extended mnemonic branch instruction, instead
of having to remember the condition code bits, NOP and
NOPR being two of those.

-- glen

Dave Dunfield

unread,
Aug 31, 2007, 6:05:31 PM8/31/07
to
>> As my I8086.A86 program shows, there are several opcodes that are
>> produced by different mnemonics. This is the first time that I see a
>> CPU with this horror. That means that the debugger can only use of
>> these forms, and that, when debugging, you will NEVER see some
>> mnemonics that are in your source code!

>I don't think it is that unusual, though maybe worse here.

It's not uncommon - some simple examples are:

JE JZ / BE BZ Jump/Branch on Zero flag seg
JNE JNZ / BNE BNZ Jump/Brancj on Zero flag NOT set
JB JC / BLO BCS Jump/Branch on Carry flag set
JAEJNC / BHS BNC Jump/Branch on Carry flag NOT set
ASR LSR Arithemetic/Logical shift right

You only ever see one or the other in a larticular debugger.
There are more - the 8086 takes it one step further and provides
different encodings which mean the same thing.

>In many cases NOP is another machine instruction that doesn't
>actually do anything. A move of a register to itself, or
>a conditional branch with the condition turned off.
>I believe the 8080 NOP is MOV A,A but someone here will tell
>me if it isn't.

The 8080 has an opcode (00) reserved for NOP - MOV A,A
is (iirc) 7F - but essentially the same thing. Waste a couple of
cycles, move no data, and set no flags. You can use any of
the general purpose registers (B,B - C,C etc.) with the same
effect - except for M,M which is not a valid encoding - if the
assembler accepts it it results in a HLT (76) instruction.

>S/360 has the extended mnemonic branch instruction, instead
>of having to remember the condition code bits, NOP and
>NOPR being two of those.

Yes, exactly like the examples above (taken from Intel and
Motorola micros). BCS means branch on carry set - Carry
is set after a compare if unsigned A < B, therefore BLO
(Branch on LOwer) also encodes tothe same opcode (as
BCS)

Dave

--
dave06a@ Low-cost firmware development tools: www.dunfield.com
dunfield. Classic computer collection: www.classiccmp.org/dunfield
com Some stuff I have for sale: www.dunfield.com/sale

glen herrmannsfeldt

unread,
Aug 31, 2007, 8:01:01 PM8/31/07
to
Dave Dunfield wrote:

(snip)

> The 8080 has an opcode (00) reserved for NOP

Now I remember. It used to be that ERPOMs would
clear to 00 (in PMOS days), but NMOS ones clear to
FF. (I don't know why they couldn't put an inverter
in to change that.)

00 was considered an advantage for the 8080, one could
put in NOPs and later change them.

-- glen

roch...@laposte.net

unread,
Sep 1, 2007, 7:49:47 AM9/1/07
to
Hello, Jonathan!

> It seems rediculously difficult tracking down 80x86 opcode
> information. Loads of documents saying "ADD AL,AL" but almost
> nothing saying "00 nn nn : ADD rn,rn".

Yes, I agree with you.

As I already wrote many years ago, I have never met the owner of a CP/
M-80 system who had not at least a book on assembly language. However,
ever since I started using IBM Clown, it is the reverse: I have never
met someone else who has a book on the various assembly languages used
by the IBM Clown.

(The more I know about both (the IBM Clown and the various assembly
languages used by it), the more I understand that, since the IBM
Clown, with its so-called upward compatibility, is, without any doubt,
the most difficult computer to program now. Too bad the ARM chip was
not a success. The only time in my life I seriously considered leaving
CP/M when was I read an article about the Acorn Archimedes A440 and
its ARM chip. But it was not a success in France, despite making
circles around the IBM Clown.)

To finish: the only serious book I have found on the 8086 is "The 8086
Primer". Be sure to get the second edition. Stephen Morse, Hayden
Book, 1982. He was one of the four newbies electronics engineers who
"designed" the 8086 CPU. He claims the fame of several bugs of the
8086 CPU in his book...

roch...@laposte.net

unread,
Sep 1, 2007, 7:58:13 AM9/1/07
to
Hello, Glen!

> 00 was considered an advantage for the 8080, one could
> put in NOPs and later change them.

One of my (big) surprise, when moving to the 8086, was that NOP is now
90h...

The problem being that GENCMD, LINK, etc, all fill unused space with
00h, with is now a valid 8086 opcode!

(ASM-86 fills erroneous fields with 90hs.)

I simply cannot understand why the newbies Intel electronics engineers
chose 90h, rather than continue to use 00h.

roch...@laposte.net

unread,
Sep 1, 2007, 8:14:59 AM9/1/07
to
Re-hello, Steve and Jonathan!

> This night, I will work on this thread, so I can publish my answer
> tomorrow, the last day of this week where I will be able to reach the
> Internet.

I am really sorry, but this stuff is so technically difficult that I
did not manage to produce anything publishable on the comp.os.cpm
Newsgroup last night. I worked until my eyes were closing, then
decided to go to bed.

Among other things, I noted that all the versions of SID-86 for CP/
M-86 that I have recognized the byte pattern proposed by Steve. I also
found that 04 12 and 82 C0 12 both produce ADD AL,12h... I also had
the idea to search for any "82" in my source code: there is none. But
the problem is that some opcodes are produced as bytes, and some are
combined to produce a byte... Anyway, it is a difficult subject, and I
think that I will spend the week-end working on it...

One reason is that, the afternoon, I spent 3 hours with the manager of
the cybercafe from where I am sending this, trying to make Windows 98
SE recognize a WiFi PCMCIA card and the CD-ROM drive of a second-hand
portable that I bought (my only computer with a CD-ROM). After 3 hours
of work, we decided to quit on failure. The manager had the idea of
using one of his CDs, booting a Linux distribution: it worked (very
slowly), and recognized the WiFi card! So, why is W98SE not
recognizing both? We have no idea. Is anybody out there who has a
unused copy of W98SE (the CD-ROM and its manual with the password)? We
think that the only solution is to re-install Windows (that's the way
99% of microcomputer shops now do) but, since it is a second-hand
portable, I don't have any original W98SE CD-ROM or booklet.

craigm

unread,
Sep 1, 2007, 9:07:41 AM9/1/07
to
Jonathan Graham Harston wrote:

>>Message-ID: <E1IQ0g0-...@stasis.kostecke.net>
>
> roch...@laposte.net wrote:
>> Is anybody out there
>> who would be interested in starting a thread
>> about the exact patterns of the Intel 8086 opcodes?
>
> http://mdfs.net/Docs/Comp/80x86/OpList is what I managed to put
> together when trying to write an 80x86 module for my disassembler.
> It seems rediculously difficult tracking down 80x86 opcode
> information. Loads of documents saying "ADD AL,AL" but almost
> nothing saying "00 nn nn : ADD rn,rn".
>


Have you looked a the opcode tables referenced here?
http://www.sandpile.org/ia32/index.htm

Also, Appendix A of the intel 386 DX Microprocessor Programmer's Reference
Manual has an opcode map. A similar map is in the 486 documentation.

Try googling on "8086 opcode map".

Jonathan Graham Harston

unread,
Sep 1, 2007, 8:30:54 AM9/1/07
to
>Message-ID: <E1IQ6zn-...@stasis.kostecke.net>


s_dub...@yahoo.com wrote:
> On Aug 28, 6:25 am, roche...@laposte.net wrote:
> > about the exact patterns of the Intel 8086 opcodes?
>
> http://www.intel.com/design/intarch/manuals/270950.htm

Annoyingly, that's got quite a few errors in it. For instance it
claims 2E is DS: prefix (it's CS:), 38-3D are XOR (they are CMP).

I've been playing around with my assembler again and have managed
to get it to produce http://mdfs.net/Docs/Comp/80x86/OpDump
I still haven't worked out how to get 80 C0.. sequences or 82..
sequences.

I'm reading through the posting on alt.lang.asm to see if that
throws any extra light on things.

Thierry B.

unread,
Sep 1, 2007, 9:56:29 AM9/1/07
to
--{ roch...@laposte.net a plopé ceci: }--


> Too bad the ARM chip was
> not a success. The only time in my life I seriously considered leaving
> CP/M when was I read an article about the Acorn Archimedes A440 and
> its ARM chip.

I agree. Back in the 80s, I was working on one of the first
Archimedes who come in France, porting a vidéogame (mostly
written in C), and playing with a really nice combo Basic/ASM.

The ARM cpu was, at this time, a wonderfull example of simplicity
and elegance. And I think that buiding a simple os in the cp/m
spirit for wil be an easy task. Or a bootable z80 system emulator,
who can boot cp/m :)

Thierry, ex ARM-addict.

--
>En fait, ce qu'il est question de faire -- avec l'accord des modérateurs
>de fur, cela va de soi --, c'est un [DOC] bisannuel qui récapitulerait les
>3 [ÉTATS]. Mais on hésite sur le format.
Liquide avec bulles, ça le fait pas ?

roch...@laposte.net

unread,
Sep 1, 2007, 11:25:11 AM9/1/07
to
Hello, Craig!

> Have you looked a the opcode tables referenced here?http://www.sandpile.org/ia32/index.htm


>
> Also, Appendix A of the intel 386 DX Microprocessor Programmer's Reference
> Manual has an opcode map. A similar map is in the 486 documentation.
>
> Try googling on "8086 opcode map".

The problem with your above ideas is that they are both 32-bits...

As I said several times, me, I prefer to do things step by step.

Then, everything is simpler.

The only problem is the number of steps involved.

Apparently, some people do less steps than others.

roch...@laposte.net

unread,
Sep 1, 2007, 11:27:17 AM9/1/07
to
Hello, Jonathan!

> >http://www.intel.com/design/intarch/manuals/270950.htm
>
> Annoyingly, that's got quite a few errors in it. For instance it
> claims 2E is DS: prefix (it's CS:), 38-3D are XOR (they are CMP).

Interesting... But the title of the manual says: "80186"...

So, this is not exactly 8086.

Anyway, I am waiting the 1981 Intel manual. This one should be
relevant (I hope!).

David Given

unread,
Sep 1, 2007, 12:17:10 PM9/1/07
to
roch...@laposte.net wrote:
[...]

> Too bad the ARM chip was
> not a success. The only time in my life I seriously considered leaving
> CP/M when was I read an article about the Acorn Archimedes A440 and
> its ARM chip.

Actually, the ARM is probably the most successful 32-bit microprocessor in the
world today, and may be the most successful ever... there is pretty much only
*one* choice when it comes to an embedded 32-bit microprocessor, and that's
ARM. There are very few other processors that can achieve the same combination
of performance, power, and cheapness. They're in pocket calculators,
telephones, PDAs, cars, DVD players, set-top boxes, games consoles, GPS kit,
wireless cards, you name it. Those 'firmware blobs' that need to get uploaded
into your favourite peripheral on Linux before they work? It's usually ARM
machine code. It's just that they don't seem to show up in PCs very often, so
people don't notice them.

(Traditionally that's been --- apart from the Windows dependence on the x86
--- because they have lousy floating point performance. However, there's a new
FPU design that should fix that; my old company had prototypes earlier in the
year...)

(Yes, I grew up on the Archimedes too. In fact, I have a Risc PC in the corner
of my office... pity it's an order of magnitude slower than the Amstrad
Emailer sitting on the top shelf.)

--
┌── dg@cowlark.com ─── http://www.cowlark.com ───────────────────

│ "There does not now, nor will there ever, exist a programming language in
│ which it is the least bit hard to write bad programs." --- Flon's Axiom

David Given

unread,
Sep 1, 2007, 12:24:43 PM9/1/07
to
roch...@laposte.net wrote:
[...]

> The problem with your above ideas is that they are both 32-bits...

The 32-bit x86 and 16-bit x86 instruction set is the same. 'add ax, ax' is
encoded in exactly the same way as 'add eax, eax'. The only difference is what
mode the processor's in.

There are a few subtleties --- for example, the 32-bit version of 'mov ax,
0x1234' actually expects a four-byte parameter instead of a 16-bit one --- but
that's pretty much it. You can use the 0x66 prefix byte to force an
instruction to be executed in 32-bit mode, or 0x67 for 16-bit mode, or you can
set it permanently in a processor flag.

It's quite common to see this sort of construction in simple assemblers:

dc.b 0x66
xor ax ! actually clears eax

(Actual opcode validity may vary...)

David Given

unread,
Sep 1, 2007, 1:43:44 PM9/1/07
to
David Given wrote:
[...]

> You can use the 0x66 prefix byte to force an
> instruction to be executed in 32-bit mode, or 0x67 for 16-bit mode,

D'oh. More accurately:

0x66 toggles the size of the operands (16 to 32 or vice versa);
0x67 toggles the size of the effective address generated.

So given:

add [foo], ax

no prefixes: sizeof(foo) = 16; sizeof(*foo) = 16; sizeof(ax) = 16

0x66: sizeof(foo) = 32; sizeof(*foo) = 16; sizeof(ax) = 16

0x67: sizeof(foo) = 16; sizeof(*foo) = 32; sizeof(ax) = 16
(but I don't think this is useful, given you've read 32 bits from *foo but
your destination register is only 16 bits wide)

0x66 & 0x67: sizeof(foo) = 32; sizeof(*foo) = 32; sizeof(ax) = 32.

But I don't think that's relevant to what you want --- I just thought I should
clarify my mistake.

s_dub...@yahoo.com

unread,
Sep 1, 2007, 6:07:23 PM9/1/07
to

It is a combination manual, just as my manual for the 8080 is
8080/8085. There are only a few differences, one is that the 80186
has the opcodes pusha & popa (push all & pop all).

Steve

CBFalconer

unread,
Sep 1, 2007, 11:45:31 PM9/1/07
to
s_dub...@yahoo.com wrote:
> roche...@laposte.net wrote:
>
... snip ...

>
>> Interesting... But the title of the manual says: "80186"...
>>
>> So, this is not exactly 8086.
>>
>> Anyway, I am waiting the 1981 Intel manual. This one should be
>> relevant (I hope!).
>
> It is a combination manual, just as my manual for the 8080 is
> 8080/8085. There are only a few differences, one is that the 80186
> has the opcodes pusha & popa (push all & pop all).

And the 80186/8 had a collection of added hardware built in. The
CPU was compatible with 8086/8.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>

--
Posted via a free Usenet account from http://www.teranews.com

Jonathan Graham Harston

unread,
Sep 2, 2007, 1:01:36 PM9/2/07
to
>Message-ID: <E1IRTz9-...@stasis.kostecke.net>


"Thierry B." <t...@prout.stex> wrote:
> The ARM cpu was, at this time, a wonderfull example of simplicity
> and elegance. And I think that buiding a simple os in the cp/m
> spirit for wil be an easy task. Or a bootable z80 system emulator,
> who can boot cp/m :)

http//mdfs.net/Apps/Emulators/Tube/Z80Tube.zipThere are three food groups: brown, green and ice cream.

Jonathan Graham Harston

unread,
Sep 2, 2007, 1:01:36 PM9/2/07
to
>Message-ID: <E1IR66V-...@stasis.kostecke.net>


glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
> In many cases NOP is another machine instruction that doesn't
> actually do anything. A move of a register to itself, or
> a conditional branch with the condition turned off.
> I believe the 8080 NOP is MOV A,A but someone here will tell

NOP is a specific instruction 00, but MOV A,A; MOV B,B; MOV C,C;
MOV D,D; MOV E,E; MOV H,H and MOV L,L are effectively NOPs.

JR $+2 and JP $+3 are also effectively NOPs.BBC BASIC for Windows and Internationalisation
See http://mdfs.net/Software/BBCBasic/Windows/ProgTips

Jonathan Graham Harston

unread,
Sep 2, 2007, 1:01:36 PM9/2/07
to
>Message-ID: <E1IRElc-...@stasis.kostecke.net>


Dave.D...@use.techsupport.link.on.my.website (Dave Dunfield) wrote:
> There are more - the 8086 takes it one step further and provides
> different encodings which mean the same thing.

00 is ADD rm8,r8 and 02 is ADD r8,rm8

00 C0 is ADD rm8,AL where rm8=AL -> ADD AL,AL
02 C0 is ADD AL,rm8 where rm8=AL -> ADD AL,AL

which your assembler emits is down to the assembler author and
programming conventions.BBC BASIC for 30+ platforms - http://mdfs.net/Software/BBCBasic

Jonathan Graham Harston

unread,
Sep 2, 2007, 1:01:36 PM9/2/07
to
>Message-ID: <E1IRSoZ-...@stasis.kostecke.net>

craigm <no...@domain.invalid> wrote:

> Jonathan Graham Harston wrote:
> > http://mdfs.net/Docs/Comp/80x86/OpList is what I managed to put
>
> Have you looked a the opcode tables referenced here?
> http://www.sandpile.org/ia32/index.htm

Yes, that's what the OpList document is based on, along with the
1985 Collins Computer Diary which lists most instructions with
bitfield encodings.

roch...@laposte.net

unread,
Sep 3, 2007, 4:54:53 AM9/3/07
to
82OPCODE.WS4 "How to produce 82 opcodes with ASM-86"
------------

(This text is dedicated to Robert ("Bob") Silberstein, the
author (in 1981) of ASM-86, the CP/M 8086 assembler of Digital
Research.)

After disassembling ASM-86 Version 1.1 (whose PL/M source code
has been released to the public domain by Caldera after buying
DR-DOS), I finally had the idea of testing it.

Before, when we used 8-bit CP/M 2.2, the opcodes of the 8080/Z-
80 were so easy that, at a glance, we knew what they were
standing for.

This is no longer, unfortunately, the case with the 8086 CPU of
the IBM Clown. A proof of that sad state is ASM-86, which is 5
TIMES bigger than ASM 2.0!

So, to be sure not to make an error, I took my well worn copy of
"The 8086 Primer", the book written by one of the four
electronics engineers who designed the 8086 CPU for Intel.

Appendix B is titled: "8086 Opcode Space", and contains a 16x16
matrix, with a "Secondary Opcode Space" table giving the
mnemonics using 2 bytes of opcode. (The 8086 CPU has 32 2-byte
opcodes: the rest are 1-byte opcodes.)

With that, I produced a I8086.A86 file that produced all the
opcodes mentioned, EXCEPT the 82 series. The "Secondary Opcode
Space" table was saying that there are four ADD instructions,
starting with a 80, 81, 82, and 83 opcodes. I had no problem
with the other three opcodes but, no matter what I tried, I did
not manage to produce any 82 opcode for the ADD instruction.

So, back to reading yet-another-time the book. This book is a
pain to use, because everything is in binary...

Ho, by the way,
80h = 1000 0000
81h = 1000 0001
82h = 1000 0010
83h = 1000 0011

Time to re-read the book.

The ADD instruction (Figure 3.18) performs a byte or word
addition of the contents of the source and destination operands,
and stores the result back in the destination operand. One of
the operands can be in a register or in memory (MOD and R/M
field); the other operand can be in a register (REG field) or in
the instruction (IMMediate field). Both a general form and a
short form of the immediate-operand ADD instruction are
provided.

+-------------+---+---+ +-----+-----+-----+
| 0 0 0 0 0 0 | d | w | | mod | reg | r/m |
+-------------+---+---+ +-----+-----+-----+
ADD: add register/memory with register to either

+--------+---+---+ +-----+-----+-----+ +------+ +------------------+
| 100000 | s | w | | mod | 000 | r/m | | data | | data if S,W = 01 |
+--------+---+---+ +-----+-----+-----+ +------+ +------------------+
ADD: add immediate with register/memory to register/memory

+---------------+---+ +------+ +---------------+
| 0 0 0 0 0 1 0 | w | | data | | data if W = 1 |
+---------------+---+ +------+ +---------------+
ADD: add immediate with accumulator to accumulator

Figure 3.18 Formats of ADD instruction

Ok. First thing to notice: they were using 6 bits to code their
one-byte long opcodes, so

80h = 100000 00
81h = 100000 01
82h = 100000 10
83h = 100000 11

The first and third forms of ADD start with a 0 bit, so are not
what we are searching for. The second, however, starts with a 1
and follows with five 0 bits, so this is the one we are
investigating.

This figure means, as far as I understand, that this instruction
produces either 3 or 4 bytes of opcode ("data if S,W = 01"). We
have just seen that "01" is the case for 81h. Logically, the 82
opcode should be followed by a byte (since 81 is followed by a
word).

Searching for more clues, I found figure 2.24.

Figure 2.24 shows an example of such an instruction. In this
example, the value 0000 0000 0000 1111 is added to the contents
of a word in memory, and the result placed back into the memory
word. The memory word is in the data segment at the offset
contained in DI. Note that one byte is eliminated by having the
S field.

opcode S W MOD opcode R/M data
+-------------+---+---+ +-----+-------+-------+ +-----------------+
| 1 0 0 0 0 0 | 1 | 1 | | 0 0 | 0 0 0 | 1 1 1 | | 0 0 0 0 1 1 1 1 |
+-------------+-+-+-+-+ +-+---+-------+-------+ +-----------------+
ADD | | | ADD DI
| | +--> memory
| +--> word
+--> sign extend

Figure 2.24 Example of immediate-operand instruction containing an S
field


Argh! This time, it is a 83 opcode...

But, for 82, since S=1, W is false (0), hence it is a byte. Qed!

It is also interesting to note the "opcode = 000 = ADD" comment
in the mod/rm byte... This could be the key to understand the
"Secondary Opcode Space".

Ok. This is all I managed to find in the book. Back to the PL/M
code.

It shows a "code-macro table" with mnemonics in alphabetic
order. However, when I disassembled ASM-86, I found that a lot
(not all) of mnemonics were spread all over the code-macro
table, instead of following the PL/M program. So, to help you, I
am re-arranging the code of my A86 file.

add1 dw nil ; ADD dst:Eb,src:Db
db 2
db specE,modB
db specD,modB
db msegfix,dst
db mdbn,80h
db mmodrm1,0,dst
db mdbf,src
db mendm

add2 dw add1 ; ADD dst:Ew,src:Db
db 2
db specE,modW
db specD,modB
db msegfix,dst
db mdbn,81h
db mmodrm1,0,dst
db mdwf,src
db mendm

add3 dw add2 ; ADD dst:Ew,src:Dsb
db 2
db specE,modW
db specD,modSB
db msegfix,dst
db mdbn,83h
db mmodrm1,0,dst
db mdbf,src
db mendm

add4 dw add3 ; ADD dst:Ew,src:Dw
db 2
db specE,modW
db specD,modW
db msegfix,dst
db mdbn,81h
db mmodrm1,0,dst
db mdwf,src
db mendm

add5 dw add4 ; ADD dst:Ab,src:Db
db 2
db specA,modB
db specD,modB
db mdbn,04h
db mdbf,src
db mendm

add6 dw add5 ; ADD dst:Aw,src:Db
db 2
db specA,modW
db specD,modB
db mdbn,05h
db mdwf,src
db mendm

add7 dw add6 ; ADD dst:Aw,src:Dw
db 2
db specA,modW
db specD,modW
db mdbn,05h
db mdwf,src
db mendm

add8 dw add7 ; ADD dst:Eb,src:Rb
db 2
db specE,modB
db specR,modB
db msegfix,dst
db mdbn,00h
db mmodrm2,src,dst
db mendm

add9 dw add8 ; ADD dst:Ew,src:Rw
db 2
db specE,modW
db specR,modW
db msegfix,dst
db mdbn,01h
db mmodrm2,src,dst
db mendm

add10 dw add9 ; ADD dst:Rb,src:Eb
db 2
db specR,modB
db specE,modB
db msegfix,src
db mdbn,02h
db mmodrm2,dst,src
db mendm

add11 dw add10 ; ADD dst:Rw,src:Ew
db 2
db specR,modW
db specE,modW
db msegfix,src
db mdbn,03h
db mmodrm2,dst,src
db mendm

Gasp! What's that?

They are code macros. That is to say: when Silberstein (or
Digital Research) decided to write a 8086 assembler to port CP/M
on the 8086 CPU, they noticed that NONE of the 6X opcodes were
documented by Intel... That is to say: Intel was planing to
introduce other CPUs, with opcodes to be added to the ones of
the 8086. So, how to write an assembler, if you don't know at
the start what will be the final instruction set?

Apparently, they had some technical information from Intel, and
could design a set of pseudo-instructions able to generate
appropriate opcodes. The only known example is the 8087.LIB
file, enabling ASM-86 Version 1.0 and 1.1 to generate 8087
opcodes.

Technically, we notice that each code macro has a comment... So,
that means that this comment was enough for the original author
to understand what it was meaning... So, we'd better be as
intelligent as him!

ADD dst:Eb,src:Db
ADD dst:Ew,src:Db
ADD dst:Ew,src:Dsb
ADD dst:Ew,src:Dw
ADD dst:Ab,src:Db
ADD dst:Aw,src:Db
ADD dst:Aw,src:Dw
ADD dst:Eb,src:Rb
ADD dst:Ew,src:Rw
ADD dst:Rb,src:Eb
ADD dst:Rw,src:Ew

Obviously, "dst:" means "destination", and "src:" means
"source".

Now, we see in upper case: A, D, E, and R, and in lower case: b,
sb, and w.

According to my disassembly,
A = Accumulator (AX or AL)
D = Data (number used as immediate data)
E = Effective address (either memory or register)
R = Register only

b = Byte
sb = Signed Byte (-128, +127)
w = Word

That's all! So, where is the bug?

Ok. Time to have a look to the I8086.LST file. (By the way,
anybody has an idea what "R" means? It is not in the PUG.)

0122 8006111112 R add label_b,12h ; 80

014A 810622225634 R add label_w,3456h ; 81

017A 03E8 add bp,ax ; 82

0184 83C512 add bp,12h ; 83

So, we see that 80 adds a byte at an address, 82 adds a word at
an address. It is curious that both 82 and 83 adds a byte, but
so be it.

Upon re-reading the code macros, we find that:

ADD dst:Eb,src:Db add1 = 80
ADD dst:Ew,src:Db add2 = 81
ADD dst:Ew,src:Dsb add3 = 83
ADD dst:Ew,src:Dw add4 = 81
ADD dst:Ab,src:Db add5 =
ADD dst:Aw,src:Db add6 =
ADD dst:Aw,src:Dw add7 =
ADD dst:Eb,src:Rb add8 =
ADD dst:Ew,src:Rw add9 =
ADD dst:Rb,src:Eb add10 =
ADD dst:Rw,src:Ew add11 =

The other code macros are, obviously, the other ADD opcodes
starting with a 0 bit. But 2 questions are raised:

1) Why is there two 81 opcodes?
2) Why is the 83 opcode the only one involved with "Signed Byte"
(-127, +128)?

1) Upon closer examination,
ADD dst:Ew,src:Db add2 = 81
ADD dst:Ew,src:Dw add4 = 81
it is obvious that the difference is that ADD2 uses a byte as
its source, while ADD4 uses a word.

2) Now for the 83 opcode.
ADD dst:Ew,src:Dsb add3 = 83
We have seen that its explanation (Figure 2.24) was precisely
saying that, due to the S field (sign extent), it was indeed
designed for signed byte.

Now, how to check this?

I tried to assemble a file with various byte values:
0006 83C57E add bp,126
0009 83C57F add bp,127
000C 81C58000 add bp,128
0010 81C58100 add bp,129
0014 83C500 add bp,0
0017 83C5FF add bp,-1
001A 83C5FE add bp,-2
001D 83C581 add bp,-127
0020 83C580 add bp,-128
0023 81C57FFF add bp,-129
0027 81C57EFF add bp,-130
but, as can be seen, ADD3 does not complain when values outside
the signed byte domain are used... (Or, more exactly, ASM-86
then uses 81 opcodes, without outputting any error message.)
(But how would an assembler know if a byte variable is signed or
not?)

Haha! And if tried EQUated variables? (Rather than immediate
values.)

Argh! Despite being now able to check the values EQUated, ASM-86
still does not complain, and outputs the same stuff. I simply
don't know why there is this "signed byte" distinction, since
ASM-86 do not seem to take care of it.

So, we have a problem. Or, Silberstein coded the code macro of
ADD3 thinking that it was an unsigned byte. This way, the ADD3
code macro would be, in fact, the code macro for the 82 opcode.
But how to know?

Since I have my A86 file available, I searched for "signed
bytes". They don't exist for "destination", only for "source".

Maybe you remember that the "Secondary Opcode Space" says that
there are 8 opcodes starting with 80-83? Well, I only found 5
comments with "sb": those of ADC, ADD, CMP, SBB, and SUB.
Missing are: AND, OR, and XOR.

I then had a look to the code macros of those 3 mnemonnics: all
have 80 and 81 (twice), but none has a 82 or 83 opcode... That
means that 8 code macros (at the minimum) will have to be added
to the assembler...

But the biggest problem remains: what is the difference between
82 and 83 opcodes, since both are dealing with bytes?

Since it would be curious that Intel designed a CPU with
redundant opcodes, and since, over and over, all the
instructions are repeated for byte or word, for integer and
signed integer, the only reasonable solution that I can see is
that the 82 opcode was designed for unsigned bytes, commonly
called "bytes"...

So, its comment would be:
ADD dst:Ew,src:Db add82 = 82
and, since the first three instructions are involved with bytes
before taking care of words,
ADD dst:Eb,src:Db add1 = 80
ADD dst:Ew,src:Db add2 = 81
ADD dst:Ew,src:Dsb add3 = 83
ADD dst:Ew,src:Dw add4 = 81
that means that 82 should be between ADD2 and ADD3 (82 between
81 and 83!).

By the way, the 3 logical opcodes only have 80, 81, 81: this
could mean that they all miss 82 and 83 opcodes... (Isn't
assembly language wonderfully logical?)

As I wrote in the comp.os.cpm Newsgroup, I am waiting to receive
an 1981 Intel book detailing the opcodes of the 8086 CPU.

By the way, speaking of technical documentation, all the
documentations of ASM-86 I have read mention: "For a more
detailed description of each instruction, see Intel's "MCS-86
Assembly Language Reference Manual". For descriptions of the
instruction bit patterns and operations, see Intel's "MCS-86
User's Manual". I have been trying to find these, especially the
latter, since it was it that led the programmer to include 5
mentions of a "signed byte" operand in the code macros, but
without any success... Google only has a handful of MCS-86
links. They seem to be totally lost. (Intel if famous for losing
its documentation, like InSite...)

If someone has any idea or comment meanwhile, he is welcome!

You may have noticed that I spend my time asking: "Why?" Here is
another question that I simply cannot prevent from haunting me:
we have seen that there are 4 secondary opcodes: 80, 81, 82, and
83.
0122 8006111112 R add label_b,12h ; 80
014A 810622225634 R add label_w,3456h ; 81


017A 03E8 add bp,ax ; 82

0184 83C512 add bp,12h ; 83
80 adds a byte, 81 adds a word. Since everything in the 8086
instruction set is so systematically regular (byte then word,
integer then signed integer), I agree that 82 should immediately
adds a byte to the accumulator but, why is 83 not adding a word,
since its W field is 1 (83h = 100000 11, if you remember: that
is to say: extend the sign (useless if it is a word...) and word
value...)...

Isn't the 8086 CPU instruction set wonderful? Still provoking
discussions 30 years after its introduction! (And notice how
badly documented it is, 30 years later, since nobody in this
world-wide Newsgroup has been able to say anything about the 82
series of opcodes! Officially, there are HUNDREDS of millions
IBM Clowns in the world, and nobody has the slightest idea what
its instruction set is... Isn't it wonderful? We are, truly,
living in a fantasy land... Hollywood has won! Harder will be
the fall.)

s_dub...@yahoo.com

unread,
Sep 3, 2007, 9:51:40 AM9/3/07
to
On Sep 3, 2:54 am, roche...@laposte.net wrote:
> 82OPCODE.WS4 "How to produce 82 opcodes with ASM-86"
> ------------

> So, its comment would be:


> ADD dst:Ew,src:Db add82 = 82

According to the Appendix A: Machine Instruction Decoding Guide, the
form of 82h is:
OP reg8|mem8,Immed8.
dst:Ew should be dst:Eb for 82h. The destination is a byte register,
not word register.

This is starting to be alittle more clearer, if the destination is a
register, in this case the byte sized register like AL, then the byte
string generated is 3 byte form, the register is encoded in the reg
field of the second byte, the immed value is the third byte. If the
destination is an EA, effective address, then the 5 byte string is
formed with byte 3 := low_displacement, byte 4 := high_displacement,
byte 5 := Immed byte value. The displacement is a word-sized offset
to byte data location.

Steve

B'ichela

unread,
Sep 3, 2007, 11:01:40 AM9/3/07
to
In article <1188809693.5...@d55g2000hsg.googlegroups.com>, roch...@laposte.net wrote:
> 82OPCODE.WS4 "How to produce 82 opcodes with ASM-86"

Just a quick question. of the Major processors used in Home PCs from
the 4004, 8008, 8080,8086 (I doubt this one), 6502, 6510 and 6809
which chip is the closes to RISC? I know what Risc stands for "Reduced
Instruction Set Code" but from the practical standpoint what defines a
Risc chip? The 6502 had less than 200 instructions (thats from memory
and I could be wrong), the 6809 had about 1064 of them in total. and
given what I am reading of the 8086, its loaded to the gills with
instructions.

no....@no.uce.bellatlantic.net

unread,
Sep 3, 2007, 1:02:44 PM9/3/07
to
On Mon, 3 Sep 2007 15:01:40 GMT, B'ichela <mda...@pinkrose.dhis.org>
wrote:

>In article <1188809693.5...@d55g2000hsg.googlegroups.com>, roch...@laposte.net wrote:
>> 82OPCODE.WS4 "How to produce 82 opcodes with ASM-86"
>
>Just a quick question. of the Major processors used in Home PCs from
>the 4004,


4004 never made it as PC cpu way to small (4bit data path).

8008 start of teh revolution at 8bits but still limited. NOT RISC.

8080,8086 (I doubt this one) NOT RISC by any stretch.


, 6502, 6510 CLOSE, May even qualify.

6809 NOT close , very CISC.
Same for 8085, Z80 Ti9900 and a much more.

>which chip is the closes to RISC? I know what Risc stands for "Reduced
>Instruction Set Code" but from the practical standpoint what defines a

Also usualy implies reduced instruction set cycle count too.
If it were only instructions 1802 would qualify but the 8/16/24 clock
cycles to execute instructions does not fit.

>Risc chip? The 6502 had less than 200 instructions (thats from memory
>and I could be wrong), the 6809 had about 1064 of them in total. and
>given what I am reading of the 8086, its loaded to the gills with
>instructions.

Total number of instructions is not a definate criteria. USually RISC
designs were more biased by simple archetectures that were very fast
(for there time) that executed simple instructions in or or two clock
cycles max. SPARC, ARM are RISC examples and 8086, 6809, 68000,
PSP11 and VAX are examples of CISC.

However ponder PDP-8, small instruction set, the real machines
(not the CMOS equivilents) executed instructions in very few cycles.

None of the machines that run CP/M or any varient is RISC.

Allison

David Given

unread,
Sep 3, 2007, 2:13:55 PM9/3/07
to
no....@no.uce.bellatlantic.net wrote:
[...]

> Total number of instructions is not a definate criteria. USually RISC
> designs were more biased by simple archetectures that were very fast
> (for there time) that executed simple instructions in or or two clock
> cycles max. SPARC, ARM are RISC examples and 8086, 6809, 68000,
> PSP11 and VAX are examples of CISC.

OTOH the PowerPC, which is marketed as RISC, has about 300 instructions, more
than the uncontroversially CISC 8080 and 6502; and while the 68000 is CISC,
the Coldfire, which uses *exactly the same instruction set* [1], is RISC!

These days I reckon that modern processor design has taken on board the good
features of both the classic RISC *and* CISC designs, and as a result the
terms don't mean much any more.

[1] Okay, okay, not quite exactly. The Coldfire actually uses a subset of the
68000 opcodes. However, it's such a large subset that people have been
building binary-compatible Amiga clones using Coldfire processors. I have no
idea how *anyone* can consider these things RISC.

Thierry B.

unread,
Sep 3, 2007, 3:32:58 PM9/3/07
to
--{ B'ichela a plopé ceci: }--

> Risc chip? The 6502 had less than 200 instructions (thats from memory
> and I could be wrong), the 6809 had about 1064 of them in total. and
> given what I am reading of the 8086, its loaded to the gills with
> instructions.

If my memory wasn't corrupted by cosmic rays, first ARM chips
have only 27 instructions...

--
"Le médecin, depuis qu'il a l'ordinateur, quand il te parle, il te
regarde plus : il regarde son ordinateur avec une tronche, mon pauvre,
on dirait qu'il a bouffé un ver."

glen herrmannsfeldt

unread,
Sep 3, 2007, 5:34:09 PM9/3/07
to
B'ichela wrote:

> Just a quick question. of the Major processors used in Home PCs from
> the 4004, 8008, 8080,8086 (I doubt this one), 6502, 6510 and 6809
> which chip is the closes to RISC? I know what Risc stands for "Reduced
> Instruction Set Code" but from the practical standpoint what defines a
> Risc chip?

Among others are fixed size, or a small number sizes of instructions,
and simple addressing modes. Usually a load/store architecture.
That is, load and store to memory, all operations are between
registers.

> The 6502 had less than 200 instructions (thats from memory
> and I could be wrong), the 6809 had about 1064 of them in total. and
> given what I am reading of the 8086, its loaded to the gills with
> instructions.

Are you including different addressing modes in the instruction count?

There was a trend for a while in making more complex instructions
to simplify life for assembly programmers. When it was found that
compilers didn't need those, the RISC idea was formed.

-- glen

no....@no.uce.bellatlantic.net

unread,
Sep 3, 2007, 6:39:26 PM9/3/07
to
On Mon, 03 Sep 2007 19:13:55 +0100, David Given <d...@cowlark.com>
wrote:

>no....@no.uce.bellatlantic.net wrote:
>[...]
>> Total number of instructions is not a definate criteria. USually RISC
>> designs were more biased by simple archetectures that were very fast
>> (for there time) that executed simple instructions in or or two clock
>> cycles max. SPARC, ARM are RISC examples and 8086, 6809, 68000,
>> PSP11 and VAX are examples of CISC.
>
>OTOH the PowerPC, which is marketed as RISC, has about 300 instructions, more
>than the uncontroversially CISC 8080 and 6502; and while the 68000 is CISC,
>the Coldfire, which uses *exactly the same instruction set* [1], is RISC!

A large instruction set is usually a function of instruction word
size.

>These days I reckon that modern processor design has taken on board the good
>features of both the classic RISC *and* CISC designs, and as a result the
>terms don't mean much any more.
>
>

I'd argue that the one instuction per clock cycle is a significant
part of the criteria.

>[1] Okay, okay, not quite exactly. The Coldfire actually uses a subset of the
>68000 opcodes. However, it's such a large subset that people have been
>building binary-compatible Amiga clones using Coldfire processors. I have no
>idea how *anyone* can consider these things RISC.

Likely because of the small number of clock cycles needed to execute
an instruction compared to any varient of the 68k.

In it's heyday of usage RISC and MIPS(millions of instructions per
second) usually were associated with raw speed.

How about DEC Alpha wich is supposedly RISC but can run soft emulation
code to run VAX a notably CISC machine?

After the mid 90s between sophisticated compilers and increasingly
sophisticated archetectures the distincion of RISC still stands
against noticeably CISC machines.

For me processors like 6502 were near RISC and proved simple and
moderatly fast is viable against complex of the same general computing
speed. What drove RISC in the 80s was for a given silicon
foundary capability a die could have only so many transistors and
with that upper limit complexity or speed was the trade. So the ARM,
SPARC and other similar designs were cheap to build silicon, fast and
for the number of transistors on the die small.

As to reduced instruction sets, I still hold the PDP8 cut it to the
bone and still proved to be effective. In it's day it was trying to
reduce the amount of logic (transistors!) required to make a viable
machine. Nearly 20years later the proces repeats itself as how
many transistors on a die.


Allison


glen herrmannsfeldt

unread,
Sep 3, 2007, 8:33:45 PM9/3/07
to
no....@no.uce.bellatlantic.net wrote:

(snip)

>>OTOH the PowerPC, which is marketed as RISC, has about 300 instructions, more
>>than the uncontroversially CISC 8080 and 6502; and while the 68000 is CISC,
>>the Coldfire, which uses *exactly the same instruction set* [1], is RISC!

Instruction count isn't a very good measure. You could be CISC with
a very small number of instructions and a large number of instruction
modifiers.

I would say that the 6502 and 8080 should be in a different class
altogether. CISC uses a lot of logic, often with microcode, to
implement complex operations. (Even floating point was pretty
complex for a 360/40.) RISC uses a lot of transistors to do simple
operations fast, often with many registers. For the 8080 and 6502,
I would say the goal wasn't fast, but to do useful operations at all.

One I still remember is that the 6502 CALL doesn't store the address
of the next instruction, but one byte earlier.

> A large instruction set is usually a function of instruction word
> size.

>>These days I reckon that modern processor design has taken on board the good
>>features of both the classic RISC *and* CISC designs, and as a result the
>>terms don't mean much any more.

> I'd argue that the one instuction per clock cycle is a significant
> part of the criteria.

I agree, though I don't know that it was the right way. That included
leaving multiply and divide out of early processors (and not so early
ones) because they couldn't be done in one cycle.

>>[1] Okay, okay, not quite exactly. The Coldfire actually uses a subset of the
>>68000 opcodes. However, it's such a large subset that people have been
>>building binary-compatible Amiga clones using Coldfire processors. I have no
>>idea how *anyone* can consider these things RISC.

> Likely because of the small number of clock cycles needed to execute
> an instruction compared to any varient of the 68k.

> In it's heyday of usage RISC and MIPS(millions of instructions per
> second) usually were associated with raw speed.

MIPS - Meaningless Indicator of Processor Speed.

> How about DEC Alpha wich is supposedly RISC but can run soft emulation
> code to run VAX a notably CISC machine?

That doesn't seem quite fair. Any good machine can emulate most
other machines. Alpha does have an advantage in hardware
support for VAX floating point formats, though.

> After the mid 90s between sophisticated compilers and increasingly
> sophisticated archetectures the distincion of RISC still stands
> against noticeably CISC machines.

> For me processors like 6502 were near RISC and proved simple and
> moderatly fast is viable against complex of the same general computing
> speed. What drove RISC in the 80s was for a given silicon
> foundary capability a die could have only so many transistors and
> with that upper limit complexity or speed was the trade. So the ARM,
> SPARC and other similar designs were cheap to build silicon, fast and
> for the number of transistors on the die small.

I would say that even the 6502 has too many address modes, and
too variable instruction length, but definitely is low in transistors.

For RISC, I see the goal not as low transistors but the most
processing for a given number of transistors. RISC is often
register rich. The CDP1802 would probably be the most RISC-like
of the early generation microprocessors.

> As to reduced instruction sets, I still hold the PDP8 cut it to the
> bone and still proved to be effective. In it's day it was trying to
> reduce the amount of logic (transistors!) required to make a viable
> machine. Nearly 20years later the proces repeats itself as how
> many transistors on a die.

I agree, the PDP-8 does seem RISC like.

In one of Knuth's books there is discussion of a two instruction
machine.

-- glen

Roger Ivie

unread,
Sep 3, 2007, 10:30:47 PM9/3/07
to
On 2007-09-04, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:

> no....@no.uce.bellatlantic.net wrote:
>> As to reduced instruction sets, I still hold the PDP8 cut it to the
>> bone and still proved to be effective. In it's day it was trying to
>> reduce the amount of logic (transistors!) required to make a viable
>> machine. Nearly 20years later the proces repeats itself as how
>> many transistors on a die.
>
> I agree, the PDP-8 does seem RISC like.

Much as I love the sleek, simple, PDP-8 instruction set, have you folks
considered all the work that has to go on for something like
JSR I Z 10?

- Fetch instruction
- Fetch Z 10
- Write incremented Z 10
- Write return address

Not exactly the RISC ideal. When I though about it a few years ago, it
looked to me like you'd need five-ported memory to execute a PDP-8
instruction in one cycle. But then, I might have been fiddling with the
PDP-5, which stores the PC at location 0...

> In one of Knuth's books there is discussion of a two instruction
> machine.

If you spend some time with Google, you can find some folks who have
played with a single instruction: subtract and branch on borrow.

Another scheme I've seen involved a single instruction that moved a word
in a byte-addressed machine. Addition was performed by constructing
suitable tables. Branches were done by making the PC addressable. Most
practical MOVE machines that I've seen discussed (like the British DEUCE
of the '50s) simply moved the opcode into the address space, so I'm not
really certain they count.
--
roger ivie
ri...@ridgenet.net

Message has been deleted

David Given

unread,
Sep 4, 2007, 4:49:38 AM9/4/07
to
Roger Ivie wrote:
[...]

> If you spend some time with Google, you can find some folks who have
> played with a single instruction: subtract and branch on borrow.

Yeah, OISC machines. While they can be implemented with an impressively small
number of transistors, the memory bandwidth is prohibitive; each 'instruction'
consists of three words (source address, address of value to subtract, address
to jump to on borrow) and the 'instructions' are so primitive that you need to
churn your way through lots of them to achieve anything.

> Most
> practical MOVE machines that I've seen discussed (like the British DEUCE
> of the '50s) simply moved the opcode into the address space, so I'm not
> really certain they count.

Indeed. I designed an ISA like this once when I was feeling bored; it exposed
all the internal devices, and each 'instruction' consisted of
pick-up-value-at-this-internal-address, write-to-that-internal-address. It
allowed a number of interesting features, like multiple ALUs and memory access
devices; but it was extremely interesting that when I tried hand-rolling some
code for it, the code density was extremely similar to that of traditional
processors...

http://www.cowlark.com/nisc.html

Now all I need to do is to learn enough VHDL to implement one. (Or, more
likely, discover out why it wouldn't work.)

roch...@laposte.net

unread,
Sep 4, 2007, 8:00:37 AM9/4/07
to
Hello, Steve!

(The following was written last night, before seeing your
message today.)

While waiting for the 1981 Intel book (did not arrive today),
I played a little with the code-macro capability of ASM-86.
After a few trials, here is what I get:

;--------------------------------
CodeMacro xadd dst:Eb,src:Db
segfix dst
db 82h
modrm 0,dst
db src
endm
;--------------------------------
0000 82C012 xadd al,12h
0003 82C112 xadd cl,12h
0006 82C212 xadd dl,12h
0009 82C312 xadd bl,12h
000C 82C412 xadd ah,12h
000F 82C512 xadd ch,12h
0012 82C612 xadd dh,12h
0015 82C712 xadd bh,12h
;--------------------------------
END


End of assembly. Number of errors: 0. Use factor: 0%

Hope it will interest you.

In my comp.os.cpm message, I was thinking that 82 = byte,
and 83 = word...

Since then (a very long time!), I have been thinking that,
instead of the SOURCE operand, the byte/word difference
could be, in fact, the DESTINATION operand...

That is to say: both 82 and 83 opcodes are both adding
an immediate 8-bit value, but 82 adds it to an 8-bit
register, while 83 adds it to an 16-bit register!

I cannot wait to receive the 1981 Intel book, to
know if I am right!

B'ichela

unread,
Sep 4, 2007, 7:34:29 PM9/4/07
to
In article <UqmdnanNF6l-80Hb...@comcast.com>, glen herrmannsfeldt wrote:
> Are you including different addressing modes in the instruction count?
In the case of the 6809 I was. not because I was trying to be
a fool but because the number of instructions/variation of
instructions stuck in my head at over 1,464. I don't remember how manh
the 6502 and its kin had.

>
> There was a trend for a while in making more complex instructions
> to simplify life for assembly programmers. When it was found that
> compilers didn't need those, the RISC idea was formed.
Given now that the computer compiles programs written in high
level languages, the neat shortcuts are not as often used. but... Do
these shortcut instructions really save time in program execution vs
a compiled program written in C or Pascal? Certainly a compiler could
make use of the shortcuts if the compiler could be designed to use the
shortcuts effectivly.

--

From the Desk of the Sysop of:
Planet Maca's Opus, a Free open BBS system. telnet://pinkrose.dhis.org
Web Site: http://pinkrose.dhis.org, Dialup 860-618-3091 300-33600 bps
The New Cnews maintainer
B'ichela

glen herrmannsfeldt

unread,
Sep 4, 2007, 9:34:14 PM9/4/07
to
B'ichela wrote:

(snip)

> Given now that the computer compiles programs written in high
> level languages, the neat shortcuts are not as often used. but... Do
> these shortcut instructions really save time in program execution vs
> a compiled program written in C or Pascal? Certainly a compiler could
> make use of the shortcuts if the compiler could be designed to use the
> shortcuts effectivly.

I could crosspost to comp.compilers, but...

It is easy to use a dynamic programming algorithm in a compiler to
select the optimal instruction sequence if you can put a cost to each
instruction or instruction group. What is easy for a compiler may not
be so easy for a person, and vice versa.

Also, when memory was more expensive there was more need for
compact instructions sets, another advantage for CISC.
VAX is said to have been designed to reduce code size at the
expense of complex instructions. Some examples are a bounds
check instruction for array access and POLY to evaluate a
polynomial. On some processors those were slower than doing
the operation using separate instructions!

-- glen

pe...@nospam.demon.co.uk

unread,
Sep 5, 2007, 12:58:00 AM9/5/07
to
In article <JnvAt...@pinkrose.net.dhis.org>
mda...@pinkrose.dhis.org "B'ichela" writes:

> In article <UqmdnanNF6l-80Hb...@comcast.com>, glen herrmannsfeldt
> wrote:
> > Are you including different addressing modes in the instruction count?
> In the case of the 6809 I was. not because I was trying to be
> a fool but because the number of instructions/variation of
> instructions stuck in my head at over 1,464. I don't remember how manh
> the 6502 and its kin had.

It's years since I worked with a 6502 but seem to recall there
were only around 40 or 50 instructions. The 6811 I worked on
more recently had a few more for the additional accumulator, but
the total must have been still firmly in double figures. And
this latter's instruction set is wonderfully orthogonal.

Pete
--
"We have not inherited the earth from our ancestors,
we have borrowed it from our descendants."

David Given

unread,
Sep 5, 2007, 3:19:26 PM9/5/07
to
B'ichela wrote:
[...]

> Given now that the computer compiles programs written in high
> level languages, the neat shortcuts are not as often used. but... Do
> these shortcut instructions really save time in program execution vs
> a compiled program written in C or Pascal? Certainly a compiler could
> make use of the shortcuts if the compiler could be designed to use the
> shortcuts effectivly.

Here's an interesting comment I found in the 68000 code generator for the ACK:

/* #define FANCY_MODES 1
/* On the M68020, there are some real fancy addressing modes.
Their use makes the code a bit shorter, but also much slower.
The FANCY_MODES #define enables the use of these addressing
modes.
*/

So that author obviously thought not.

roch...@laposte.net

unread,
Sep 6, 2007, 5:27:48 AM9/6/07
to
80OPC2.WS4
----------

- "82 opcodes: a bug made in 1978?"

I have finally received the 1981 Intel manual. I took my pen, a
sheet of paper, and the Intel "The 8086 Family User's Manual",
October 1979.

I systematically compared both manuals: the only differences
were:

1) the Device Specifications appendix was different.

2) the new manual has a supplement, titled "The 8087 Numeric
Data Processor", so I will finally be able to do some 8087
programming (until then, I had nothing about it in my
collection: floating-point doesn't seem to interest many
persons...).

So, this manual was a big deception. I compared page-by-page the
125 pages dealing with the 8086 in both versions: they were
identical.

Studying one manual, I noticed that they have a 16x16 opcode
matrix, like "The 8086 Primer" (the book authored by one of the
authors of the 8086 CPU) but, BIG DIFFERENCE: before this
matrix, there is "Machine Instruction Decoding Guide", giving
each 8086 opcode in hex (for the opcode) and binary for the
MODRM byte... (The 8086 primer only contains binary: apparently,
the author decodes multi-bytes binary patterns at a glance...)
(and like particularly to "boxes" them in his book)

With this "Decoding Guide", I checked my I8086.A86 file: they
now use the same variables.

While comparing the "Decoding Guide" with the 16x16 matrix (and
especially its "Secondary Opcode Space" table), I finally
noticed something...

The "Primary Opcode Space" table being a 16x16 table filled with
mnemonics, I simply cannot reproduce it here (since some
regulars insist that only 64 columns be used). So, you will have
to understand that the following is portions of the 16x16
matrix:

.0 .1 .2 .3
+-------+-------+-------+-------+--
8. | Immed | Immed | Immed | Immed | (...)
| b,r/m | w,r/m | b,r/m | is,r/m|
+-------+-------+-------+-------+--

.0 .1 .2 .3
+-------+-------+-------+-------+--
D. | Shift | Shift | Shift | Shift | (...)
| b | w | b,v | w,v |
+-------+-------+-------+-------+--

.6 .7 .E .F
--+-------+-------+-- --+-------+-------+
F. (...) | Grp 1 | Grp 1 | (...) | Grp 2 | Grp 2 |
| b,r/m | w,r/m | | b,r/m | w,r/m |
--+-------+-------+-- --+-------+-------+

See? I want to draw your attention to opcodes 80-83, D0-D3, F6-
F7, and FE-FF.

Why? Because the "Secondary Opcode Space" table is said to
describe the 2-byte opcodes of the 8086 CPU.

opc. | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111
------+-----+-----+-----+-----+-----+-----+-----+-----
Immed | ADD | OR | ADC | SBB | AND | SUB | XOR | CMP
------+-----+-----+-----+-----+-----+-----+-----+-----
Shift | ROL | ROR | RCL | RCR | SHL*| SHR | --- | SAR (*=SAL)
------+-----+-----+-----+-----+-----+-----+-----+-----
Grp 1 | TEST| --- | NOT | NEG | MUL | IMUL| DIV | IDIV
------+-----+-----+-----+-----+-----+-----+-----+-----
Grp 2 | INC | DEC | CALL| CALL| JMP | JMP | PUSH| ---
| | | id | L,id| id | L,id| |
------+-----+-----+-----+-----+-----+-----+-----+-----

In our case, it all started when I tried to generate some 82
opcodes, to check that ASM-86 could produce all the legal 8086
opcodes. I had no trouble generating the 80, 81, and 83 opcodes
of ADD but, no matter what I tried, I simply was not able to
generate the 82 opcode. As I wrote in a short message, using a
"codemacro" (a feature of ASM-86), I was finally able to
generate them. By the way, let us review them:

0122 8006111112 R add mem_8,12h ; 80
0127 800E111112 R or mem_8,12h ; 80
012C 8016111112 R adc mem_8,12h ; 80
0131 801E111112 R sbb mem_8,12h ; 80
0136 8026111112 R and mem_8,12h ; 80
013B 802E111112 R sub mem_8,12h ; 80
0140 8036111112 R xor mem_8,12h ; 80
0145 803E111112 R cmp mem_8,12h ; 80

014A 810622225634 R add mem_16,3456h ; 81
0150 810E22225634 R or mem_16,3456h ; 81
0156 811622225634 R adc mem_16,3456h ; 81
015C 811E22225634 R sbb mem_16,3456h ; 81
0162 812622225634 R and mem_16,3456h ; 81
0168 812E22225634 R sub mem_16,3456h ; 81
016E 813622225634 R xor mem_16,3456h ; 81
0174 813E22225634 R cmp mem_16,3456h ; 81

017A 82C012 add82 al,12h ; 82
; 82 -- mod 001 r/m -- not used
017D 82C012 adc82 al,12h ; 82
0180 82C012 sbb82 al,12h ; 82
; 82 -- mod 100 r/m -- not used
0183 82C012 sub82 al,12h ; 82
; 82 -- mod 110 r/m -- not used
0186 82C012 cmp82 al,12h ; 82

0189 83C512 add bp,12h ; 83
; 83 -- mod 001 r/m -- not used
018C 83D512 adc bp,12h ; 83
018F 83DD12 sbb bp,12h ; 83
; 83 -- mod 100 r/m -- not used
0192 83ED12 sub bp,12h ; 83
; 83 -- mod 110 r/m -- not used
0195 83FD12 cmp bp,12h ; 83

Now, what is the problem (now that we can generate 82 opcodes at
will)?

The problem is that the "Secondary Opcode Space" table says that
there are 8 opcodes for "Immed"(iate) values, when opcodes 82
and 83 visibly only allow 5! QED!

That is to say: the line for "Immed" correspond to opcodes 80
and 81, but one line (that we are going to call "Imm5") is
missing for opcodes 82 and 83:

opc. | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111
------+-----+-----+-----+-----+-----+-----+-----+-----
Imm5 | ADD | --- | ADC | SBB | --- | SUB | --- | CMP
------+-----+-----+-----+-----+-----+-----+-----+-----

And, of course, the "Primary Opcode Space" table needs to be
updated:

.0 .1 .2 .3
+-------+-------+-------+-------+--
8. | Immed | Immed | Imm5 | Imm5 | (...)
| b,r/m | w,r/m | b,r/m | is,r/m|
+-------+-------+-------+-------+--

Haaaaaa!!! The official Intel doc now reflects the reality...

But, by the way, the "Seconday Opcode Space" table has 4
lines... So, what about the other lines?

The Shift line is good for the D0, D1, D2, and D3 opcodes (as a
close study of the "Decoding Guide" will reveal).

The Grp 1 line is good for the F6 and F7 opcodes.

However, when we reach the end of the opcodes, there is a
problem: my listing (and the "Decoding Guide") say that:

0300 FE061111 R inc mem_8
0304 FE0E1111 R dec mem_8
; FE -- mod 010 r/m -- not used
; FE -- mod 011 r/m -- not used
; FE -- mod 100 r/m -- not used
; FE -- mod 101 r/m -- not used
; FE -- mod 110 r/m -- not used
; FE -- mod 111 r/m -- not used

0308 FF062222 R inc mem_16
030C FF0E2222 R dec mem_16
0310 FFD0 call ax
0312 FF162222 R call mem_16
0316 FFE0 jmp ax
0318 FF262222 R jmp mem_16
031C FF362222 R push mem_16
; FF -- mod 111 r/m -- not used

That is to say: there are only 2 opcodes starting with FE, but 7
starting with FF... and, another time, the "Secondary Opcode
Space" table does not correspond with reality:

opc. | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111
------+-----+-----+-----+-----+-----+-----+-----+-----
Grp 3 | INC | DEC | --- | --- | --- | --- | --- | ---
------+-----+-----+-----+-----+-----+-----+-----+-----

.E .F
--+-------+-------+
F. (...) | Grp 3 | Grp 2 |
| b,r/m | w,r/m |
--+-------+-------+

Ha! That's better! I prefer to have my technical documentation
reflect the reality.

So, if you are still programming your IBM Clown in 8086
assembler, the correct "Secondary Opcode Space" table is:

opc. | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111
------+-----+-----+-----+-----+-----+-----+-----+-----
Immed | ADD | OR | ADC | SBB | AND | SUB | XOR | CMP
------+-----+-----+-----+-----+-----+-----+-----+-----
Imm5 | ADD | --- | ADC | SBB | --- | SUB | --- | CMP
------+-----+-----+-----+-----+-----+-----+-----+-----
Shift | ROL | ROR | RCL | RCR | SHL*| SHR | --- | SAR (*=SAL)
------+-----+-----+-----+-----+-----+-----+-----+-----
Grp 1 | TEST| --- | NOT | NEG | MUL | IMUL| DIV | IDIV
------+-----+-----+-----+-----+-----+-----+-----+-----
Grp 2 | INC | DEC | CALL| CALL| JMP | JMP | PUSH| ---
| | | id | L,id| id | L,id| |
------+-----+-----+-----+-----+-----+-----+-----+-----
Grp 3 | INC | DEC | --- | --- | --- | --- | --- | ---
------+-----+-----+-----+-----+-----+-----+-----+-----

(Don't forget to also patch the "Primary Opcode Space" table.)

All this don't explain why Robert ("Bob") Silberstein introduced
a "signed byte" type of operand in ASM-86 (used only 5 times in
a 40 KB program). The only thing I have found is that the
comment for the 83 opcode is "is,r/m" and "is" is said to mean
"immediate byte, sign extended". Except that, I have been unable
to find any reference to a "signed byte" in either "The 8086
Primer" or "The 8086 Family User's Manual". Many instructions
have a "integer" and "signed integer" variation, but I have been
unable to find such a distinction for bytes.

roch...@laposte.net

unread,
Sep 11, 2007, 10:29:17 AM9/11/07
to
82OPC3.WS4
----------

"82 opcodes: the end?"

For some unknown reason, my last message about the 82 opcodes
did not seem to generate much response...

Anyway, I finally have a file able to generate all the legal
("legal" in the sense of recognized by ASM-86, since it appears
that most assemblers do NOT follow exactly the syntax used by
Intel in 1978... One more "feature" of the IBM Clown!)
instructions of the 8086 CPU.

After a while, I was wondering how to test it? The only solution
was to test it against SID-86, since an assembler is only one
part of an assembly language development system, whose other
side is the debugger (how do you debug an assembler without a
(good) working debugger?). In our case, I got:

18E8:01A3 ADD BYTE [1111],12
18E8:01A8 OR BYTE [1111],12
18E8:01AD ADC BYTE [1111],12
18E8:01B2 SBB BYTE [1111],12
18E8:01B7 AND BYTE [1111],12
18E8:01BC SUB BYTE [1111],12
18E8:01C1 XOR BYTE [1111],12
18E8:01C6 CMP BYTE [1111],12

18E8:01CB ADD WORD [2222],3456
18E8:01D1 OR WORD [2222],3456
18E8:01D7 ADC WORD [2222],3456
18E8:01DD SBB WORD [2222],3456
18E8:01E3 AND WORD [2222],3456
18E8:01E9 SUB WORD [2222],3456
18E8:01EF XOR WORD [2222],3456
18E8:01F5 CMP WORD [2222],3456

18E8:01FB ADD AL,12
18E8:01FE ADC AL,12
18E8:0201 SBB AL,12
18E8:0204 SUB AL,12
18E8:0207 CMP AL,12

18E8:020A ADD BP,0012
18E8:020D ADC BP,0012
18E8:0210 SBB BP,0012
18E8:0213 SUB BP,0012
18E8:0216 CMP BP,0012

(I have added empty lines to separate the various (80, 81, 82,
and 83) opcodes.)

The obvious thing to notice is that SID-86 is adding a pair of
zeroes in front of each byte to be ADDed, etc. to the 16-bit
register. Since those "00" are not part of the H86 or CMD file,
this is clearly a bug (that will have to be removed).

Note also the "BYTE [xxxx]" and "WORD [xxxx]" added by SID-86:
they were not present in the A86 file, which contained only
"mem_8" and "mem-16", following the Intel "Machine Instruction
Decoding Guide". As already noted, everything in the 8086 is
very verbose, and I simply don't know if we should keep this
"feature" since, if we debug our programs, we would have the
source code nearby, to find where was the bug. On the other
hand, this display tells us whether the variable was a DB or a
DW, so maybe it is worthwhile? (If you have an opinion on this,
you are welcome.)

I had also commented on the stupidity of having multiple
mnemonics generating the same opcode. For instance, SID-86
displays:

18E8:016B JB 0167
18E8:016D JB 0167
18E8:016F JB 0167
18E8:0171 JNB 0167
18E8:0173 JNB 0167
18E8:0175 JNB 0167
18E8:0177 JZ 0167
18E8:0179 JZ 0167
18E8:017B JNZ 0167
18E8:017D JNZ 0167
18E8:017F JBE 0167
18E8:0181 JBE 0167
18E8:0183 JA 0167
18E8:0185 JA 0167
18E8:0187 JS 0167
18E8:0189 JNS 0167
18E8:018B JP 0167
18E8:018D JP 0167
18E8:018F JNP 0167
18E8:0191 JNP 0167
18E8:0193 JL 0167
18E8:0195 JL 0167
18E8:0197 JNL 0167
18E8:0199 JNL 0167
18E8:019B JLE 0167
18E8:019D JLE 0167
18E8:019F JG 0167
18E8:01A1 JG 0167

18E8:030D LOOPNE 030D
18E8:030F LOOPNE 030D
18E8:0311 LOOPE 030D
18E8:0313 LOOPE 030D

18E8:0334 REPNE NOP
18E8:0336 REPNE NOP
18E8:0338 REP NOP
18E8:033A REP NOP
18E8:033C REP NOP

So, my opinion is reinforced: it is totally crazy to have an
assembler use mnemonics that are NEVER to be displayed by the
debugger! When I started, one common wisdom was: "Garbage in,
garbage out". And, the only way I can see to remove this garbage
is to remove those useless mnemonics in the future version of
ASM-86... (At least, this will free some space.)

Finally, I have written, somewhere: "the 32 2-bytes of the 8086
CPU". After having finally managed to spot the error in the
"Secondary Opcode Space" table, I had doubts about this value...
So, let us study what we now know:

80 opcodes --> Immed --> 8 2-bytes opcodes
81 --> Immed --> 8
82 --> Imm5 --> 5
83 --> Imm5 --> 5

D0 --> Shift --> 7
D1 --> Shift --> 7
D2 --> Shift --> 7
D3 --> Shift --> 7

F6 --> Grp 1 --> 7
F7 --> Grp 1 --> 7

FE --> Grp 3 --> 2
FF --> Grp 2 --> 7

Total: 77 2-bytes 8086 opcodes

Now, this is not the end of the story, since there are simply
blanks in the official Intel 8086 "Machine Instruction Decoding
Guide". The following opcodes: 0F, 60-6F, C0, C1, C8, C9, D6,
and F1 are not even documented as "not used" or "reserved": they
are simply "holes" in the instruction set! (Yet another
"feature" of this CPU!) (By the way, if anybody out there knows
what Intel made of them, later, he is welcome.)

So, on a byte, you can have 256 opcodes. There are 23 "holes"
opcodes. Our investigation of the "Secondary Opcode Space" table
involved 12 opcodes ( 4 + 4 + 2 + 2 = 4 * 3 = 12). Those "holes"
and "secondary opcodes" are, obviously, not one byte long
opcodes. So, 23 + 12 = 35 opcodes to remove from 256 = 256 -35 =
221 one-byte long opcodes. To those one-byte long opcodes, we
can add the 77 two-bytes long opcodes just listed. Total: the
Intel 8086 CPU has 298 "legal" opcodes.

This may not seem big. However, to some Old Timers who remember
that the Zilog Z-80 had 144 documented instructions (there were
an additional hundred undocumented opcodes...), those 144
instructions were generating some 820 (or was it 916?)
opcodes... So, with so many 8086 instructions dealing with 16-
bit values, checking that a 8086 debugger was really recognizing
correctly all the "legal" bit patterns could be quite
difficult... (In fact, we have just demonstrated a bug in SID-86
Version 3.2...)

Me, when I disassembled ZSID Version 2.5, I made a file
containing all the legal Z-80 opcodes. Since I could not find
any assembler able to generate them (remember, some hundred
opcodes are undocumented!), I ended using a file containing only
DB statements, so that any assembler could assemble it.
Fortunately, the Z-80 instruction set being so regular, I could
use BASIC to produce pages after pages (the final version of the
test file was 20 pages long) of opcodes. Is it a waste of time,
checking a debugger? In my case, I found 4 bugs in ZSID Version
2.5...

(Knowing the kind of job to do, and thinking what will need to
be done on this 8086 debugger, I tremble!)

no....@no.uce.bellatlantic.net

unread,
Sep 11, 2007, 1:12:52 PM9/11/07
to
On Tue, 11 Sep 2007 07:29:17 -0700, roch...@laposte.net wrote:

>82OPC3.WS4
>----------
>
>"82 opcodes: the end?"
>
>For some unknown reason, my last message about the 82 opcodes
>did not seem to generate much response...

It's an 80x86 archetecture discussion not really CP/M.

Any programmer knows 90% or so of real work is done with far
less than 80% of the instruction set. Some few percent of the
instructions are often best found in the rare if every used pile and
would not be missed if deleted.

------->x86 stuff deleted.<---------------


>This may not seem big. However, to some Old Timers who remember
>that the Zilog Z-80 had 144 documented instructions (there were
>an additional hundred undocumented opcodes...), those 144
>instructions were generating some 820 (or was it 916?)
>opcodes...

The Z80 has 158 instructions according to Zilog and also their
publications. That does not include the Z180 and Z280 that extend the
instruction set further.

The 8086 stuff is better served in Alt.Arch.intel.x86.

>Me, when I disassembled ZSID Version 2.5, I made a file
>containing all the legal Z-80 opcodes. Since I could not find
>any assembler able to generate them (remember, some hundred
>opcodes are undocumented!), I ended using a file containing only
>DB statements, so that any assembler could assemble it.
>Fortunately, the Z-80 instruction set being so regular, I could
>use BASIC to produce pages after pages (the final version of the
>test file was 20 pages long) of opcodes. Is it a waste of time,
>checking a debugger? In my case, I found 4 bugs in ZSID Version
>2.5...
>

There are several lists of Z80 "undocumented" instructions and the
analysis. The good news is everybody elses Z80 executes them
completely and faithfully.

A few moments reading available docuuments on line would
reveal this.


Allison

s_dub...@yahoo.com

unread,
Sep 12, 2007, 12:27:27 AM9/12/07
to
On Sep 6, 3:27 am, roche...@laposte.net wrote:
> 80OPC2.WS4
> ----------
>
> - "82 opcodes: a bug made in 1978?"

More like poor documentation, a notorious 'feature' of intel docs
in general.

> That is to say: there are only 2 opcodes starting with FE, but 7
> starting with FF... and, another time, the "Secondary Opcode
> Space" table does not correspond with reality:
>

>


> Ha! That's better! I prefer to have my technical documentation
> reflect the reality.
>

Yes, good catch.. this is separated in the later 486 manual for
example, as:
FE := Grp4 INC/DEC
FF := Grp5 INC/DEC

>
> All this don't explain why Robert ("Bob") Silberstein introduced
> a "signed byte" type of operand in ASM-86 (used only 5 times in
> a 40 KB program). The only thing I have found is that the
> comment for the 83 opcode is "is,r/m" and "is" is said to mean
> "immediate byte, sign extended". Except that, I have been unable
> to find any reference to a "signed byte" in either "The 8086
> Primer" or "The 8086 Family User's Manual". Many instructions
> have a "integer" and "signed integer" variation, but I have been
> unable to find such a distinction for bytes.
>

But you know the signed byte significance, +127, -128.

The issue here is that the source is a signed byte, but the
destination
is word_sized, so..

83 nn OP Reg16|Mem16,signed Immed8

assures sign extention into the larger destination. I wonder how many
subtle bugs involve this detail being missed.

Steve

roch...@laposte.net

unread,
Sep 13, 2007, 4:27:35 AM9/13/07
to
ESCAPE2.WS4
-----------

As we saw in the last message, there is an unresolved problem
with the 8086 ESC instruction.

SID-86 3.2 RASM-86 1.4A
------------ ------------
ESC 00,AL esc 0,al
ESC 08,CX <--- ?? ---> esc 8,cl
ESC 10,DL esc 16,dl
ESC 18,BX <--- ?? ---> esc 24,bl
ESC 20,AH esc 32,ah
ESC 28,BP <--- ?? ---> esc 40,ch
ESC 30,DH esc 48,dh
ESC 38,DI <--- ?? ---> esc 56,bh

The problem with this bug (?) is that the ESC instruction is
little interstood, since it was intended to be a mechanism by
which the 8086 CPU could "share" instructions with a co-
processor and (1) only the 8087 used this mechanism, (2) it was
found that a bad 8087 opcode could hang the whole system (the
original mechanism was providing for only 64 additional
instructions, but the 8087 ended by using 2 bytes for its
opcode...), so later Intel numerical data processor use another
way to get their commands from the CPU.

So, in a sense, this discussion is outdated, since our sample
coding uses 2 bytes, while now Intel CPUs use 3 bytes to
communicate with their NDPs. In addition, if you wanted to use
the ESC mechanism, you would need to build your own motherboard
with a 8086 CPU, since Intel CPUs now incorporate the NDP inside
the same chip...

Anyway, the subject is so technical that we'd better have a look
to "The 8086 Primer (2nd Edition)":

The subordinate processor operates by watching the 8086 and
being constantly aware of the instruction being executed. In
particular, it is watching for the special instruction ESCape,
which is the embodiement of all instructions that the 8086 needs
help executing. The ESC instruction has a 3-bit field (X)
indicating which subordinate processor is needed, and a 3-bit
field (Y) indicating the instruction that processor should
execute. Both of these fields are ignored by the 8086 processor.
(This description is slightly simplified; in reality, the six
ignored bits may arbitrarily be used to distinguish 64
combinations of processor and/or instruction.) Furthermore, the
ESC instruction has a MOD field and an R/M field that designate
a memory operand for the subordinate processor. These two fields
are, indeed, used by the 8086; the 8086 computes the memory
address of the operand, and then actually reads the value of the
operand from memory, although it ignores the value when it gets
it. The subordinate processor is watching all this, and now
knows the address of the operand, as well as the value of the
operand. The subordinate processor now has everything it needs
(instruction and operand) in order to execute the required
operation.

The form of the ESC instruction is shown in Figure 3.48.

+-----------+---+ +-----+---+-----+
| 1 1 0 1 1 | x | | mod | y | r/m |
+-----------+---+ +-----+---+-----+
ESC: escape

Figure 3.48

Ok. We just need to keep in mind that the X and Y fields are 3
bits wide, so a better figure would be:

+-----------+-------+ +-----+-------+-----+
| 1 1 0 1 1 | x x x | | mod | y y y | r/m |
+-----------+-------+ +-----+-------+-----+
ESC: escape

Now, let us look to the problematic opcodes:

esc 0,al = D8 C0 = 11011 000 11 000 000
esc 8,cl = D9 C1 = 11011 001 11 000 001
esc 16,dl = DA C2 = 11011 010 11 000 010
esc 24,bl = DB C3 = 11011 011 11 000 011
esc 32,ah = DC C4 = 11011 100 11 000 100
esc 40,ch = DD C5 = 11011 101 11 000 101
esc 48,dh = DE C6 = 11011 110 11 000 110
esc 56,bh = DF C7 = 11011 111 11 000 111

Whew! Let us now study those bit patterns. "The 8086 Primer"
does not contain one single line of assembly language
(apparently, its author only works in binary). The only "coding
sample" I could find is in "The 8086 Family User's Manual", and
consists only of the following 2 lines:

esc 6,array[si]
esc 20,al

Assembling them, we get:

D8 B4 34 12 esc 6,array[si]
DA E0 esc 20,al

Let us start by the simpler opcode:

DA E0 = 11011 010 11 100 000
----- --- --- --- ---
ESC X MOD Y R/M

Let see... 20 = 10100b and X=010 and Y=100, so XY = 010100b. The
000b in R/M can mean "AL" if W=0.

Since Y is only 3 bits wide, let us assemble a few ESC
instructions:

ESC X MOD Y R/M
----- --- --- --- ---
D8C0 11011 000 11 000 000 esc 0,al
D8C8 11011 000 11 001 000 esc 1,al
D8D0 11011 000 11 010 000 esc 2,al
D8D8 11011 000 11 011 000 esc 3,al
D8E0 11011 000 11 110 000 esc 4,al
D8E8 11011 000 11 101 000 esc 5,al
D8F0 11011 000 11 110 000 esc 6,al
D8F8 11011 000 11 111 000 esc 7,al

D9C0 11011 001 11 000 000 esc 8,al
DAC0 11011 010 11 000 000 esc 16,al
DBC0 11011 011 11 000 000 esc 24,al
DCC0 11011 100 11 000 000 esc 32,al
DDC0 11011 101 11 000 000 esc 40,al
DEC0 11011 110 11 000 000 esc 48,al
DFC0 11011 111 11 000 000 esc 56,al

DFC8 11011 111 11 001 000 esc 57,al
DFD0 11011 111 11 010 000 esc 58,al
DFD8 11011 111 11 011 000 esc 59,al
DFE0 11011 111 11 100 000 esc 60,al
DFE8 11011 111 11 101 000 esc 61,al
DFF0 11011 111 11 110 000 esc 62,al
DFF8 11011 111 11 111 000 esc 63,al

It works! So, the famous 0-63 range is coded using the X and Y
fields contiguously. (Isn't this 8086 CPU wonderful, with its
opcodes and operands split into 2? In France, we have a saying
that I did not manage to find in my English dictionaries:
"Pourquoi faire simple, alors qu'il est si facile de faire
complique?" (Why make it simple, when it is so easy to make it
complex?). Obviously, the "designer" of this CPU had this turn
of mind.)

Now that we know were are stored the 0-63 range, let us turn our
attention to the register. (By the way, did you notice that all
the MOD bits encountered so far are "11", that is to say:
register mode (no displacement)?)

0032 D8C0 esc 0,al
0034 D8C1 esc 0,cl
0036 D8C2 esc 0,dl
0038 D8C3 esc 0,bl
003A D8C4 esc 0,ah
003C D8C5 esc 0,ch
003E D8C6 esc 0,dh
0040 D8C7 esc 0,bh

0042 D8C0 esc 0,ax
0044 D8C1 esc 0,cx
0046 D8C2 esc 0,dx
0048 D8C3 esc 0,bx
004A D8C4 esc 0,sp
004C D8C5 esc 0,bp
004E D8C6 esc 0,si
0050 D8C7 esc 0,di

0052 D8C0 esc 0,es
0054 D8C1 esc 0,cs
0056 D8C2 esc 0,ss
0058 D8C3 esc 0,ds

??? Could it be possible that only 8-bit registers are allowed?

Time to have a look to the other "coding sample":

D8 B4 34 12 esc 6,array[si]

ESC X MOD Y R/M Addr.
----- --- --- --- --- ------
D8 B4 34 12 11011 000 10 110 100 (etc.) esc 6,array[si]

XY = 000110b = 6. MOD=10 = Memory Mode, 16-bit displacement
follows, so it is normal to have the 34 12 bytes after. R/M=100
= (SI)+D16 according to the "R/M Field Encoding" table. Indeed,
we have a "si" in [si], and an address (D16) in "array" (just a
DB statement in my A86 file). This gives me an idea: let us
check the values found in the "R/M Field Encoding" table for
MOD=10.

0000 D8B03412 R esc 6, array[bx+si]
0004 D8B13412 R esc 6, array[bx+di]
0008 3ED8B23412 R esc 6, array[bp+si]
000D 3ED8B33412 R esc 6, array[bp+di]
0012 D8B43412 R esc 6, array[si]
0016 D8B53412 R esc 6, array[di]
001A 3ED8B63412 R esc 6, array[bp]
001F D8B73412 R esc 6, array[bx]

Whaow! First thing to notice: all instances of BP are "prefixed"
with a 3E byte, which means "Data Segment override". Let us put
them aside for now.

ESC X MOD Y R/M Addr.
----- --- --- --- --- ------
D8B03412 11011 000 10 110 000 (etc.) esc 6, array[bx+si]
D8B13412 11011 000 10 110 001 (etc.) esc 6, array[bx+di]
D8B23412 11011 000 10 110 010 (etc.) esc 6, array[bp+si]
D8B33412 11011 000 10 110 011 (etc.) esc 6, array[bp+di]
D8B43412 11011 000 10 110 100 (etc.) esc 6, array[si]
D8B53412 11011 000 10 110 101 (etc.) esc 6, array[di]
D8B63412 11011 000 10 110 110 (etc.) esc 6, array[bp]
D8B73412 11011 000 10 110 111 (etc.) esc 6, array[bx]

Yes, we finally recognize (in the R/M column) the MOD=10 column
of the "R/M Field Encoding" table.

Normally, if we remove "array" from each line, we should get
MOD=00, but how do you get a MOD=01 (8-bit displacement)?

Well, well... The only cases where RASM-86 accepted the
statements are:

006B D8F6 esc 6, si
006D D8F7 esc 6, di
006F D8363412 R esc 6, array
0073 D8F3 esc 6, bx

Everything else I tried was flagged as an error. So, let us
examine the ones that passed:

ESC X MOD Y R/M Addr.
----- --- --- --- --- ------
D8F6 11011 000 11 110 110 esc 6, si
D8F7 11011 000 11 110 111 esc 6, di
D8363412 11011 000 01 110 110 (etc.) esc 6, array
D8F3 11011 000 11 110 011 esc 6, bx

Let see... MOD=11 and R/M=110 so esc 6,si is good. MOD=11 and
R/M=111, so esc 6,di is good. MOD=11 and R/M=011 so esc 6,BX is
good. But why is MOD=01 (Memory Mode, 8-bit displacement) when I
was expecting a MOD=00 for a direct address? At least, this gave
me an idea for MOD=11 (since I already have 3 of them):

0000 D8F0 esc 6, ax
0002 D8F1 esc 6, cx
0004 D8F2 esc 6, dx
0006 D8F3 esc 6, bx
0008 D8F4 esc 6, sp
000A D8F5 esc 6, bp
000C D8F6 esc 6, si
000E D8F7 esc 6, di

It seems to have worked. Let us check them (why cannot this
bloody IBM Clown do all this drill job?):

ESC X MOD Y R/M
----- --- --- --- ---
D8F0 11011 000 11 110 000 esc 6, ax
D8F1 11011 000 11 110 001 esc 6, cx
D8F2 11011 000 11 110 010 esc 6, dx
D8F3 11011 000 11 110 011 esc 6, bx
D8F4 11011 000 11 110 100 esc 6, sp
D8F5 11011 000 11 110 101 esc 6, bp
D8F6 11011 000 11 110 110 esc 6, si
D8F7 11011 000 11 110 111 esc 6, di

Phew! This is becoming boring... But at least I know how to
generate the W=1 (word) register values of the "R/M Field
Encoding" table for MOD=11.

So, so far, we managed to produce the bit patterns for MOD=11-
W=0, MOD=11-W=1, and MOD=10. The problem is the last 2 modes: 00
and 01.

To be continued?

glen herrmannsfeldt

unread,
Sep 13, 2007, 6:26:00 AM9/13/07
to
roch...@laposte.net wrote:
> ESCAPE2.WS4
> -----------

> As we saw in the last message, there is an unresolved problem
> with the 8086 ESC instruction.

> SID-86 3.2 RASM-86 1.4A
> ------------ ------------
> ESC 00,AL esc 0,al
> ESC 08,CX <--- ?? ---> esc 8,cl
> ESC 10,DL esc 16,dl
> ESC 18,BX <--- ?? ---> esc 24,bl
> ESC 20,AH esc 32,ah
> ESC 28,BP <--- ?? ---> esc 40,ch
> ESC 30,DH esc 48,dh
> ESC 38,DI <--- ?? ---> esc 56,bh

> The problem with this bug (?) is that the ESC instruction is
> little interstood, since it was intended to be a mechanism by
> which the 8086 CPU could "share" instructions with a co-
> processor and (1) only the 8087 used this mechanism, (2) it was
> found that a bad 8087 opcode could hang the whole system (the
> original mechanism was providing for only 64 additional
> instructions, but the 8087 ended by using 2 bytes for its
> opcode...), so later Intel numerical data processor use another
> way to get their commands from the CPU.

If I (remember,understand) right, the 8086 fetches one byte from
the target address. It doesn't modify the register indicated, but
does it ever fetch two bytes? I believe an 8088 will only fetch
one, as will an 8086 with an odd address. In the case of an
even address, does the 8086 fetch the whole word, even when only
one byte is needed? Does a load of al from an even memory
address do a 16 bit fetch or an 8 bit fetch?

-- glen

no....@no.uce.bellatlantic.net

unread,
Sep 13, 2007, 7:47:30 AM9/13/07
to

If memory is right the 86 fetches three and the 88 only one.

However what has been forgotton is the 8089 IOP also hasan interacting
mechanism like a NDP.

Allison

roch...@laposte.net

unread,
Sep 13, 2007, 9:29:44 AM9/13/07
to
Hello, Steve!

> The issue here is that the source is a signed byte, but the
> destination is word_sized, so..
>
> 83 nn OP Reg16|Mem16,signed Immed8
>
> assures sign extention into the larger destination. I wonder how many
> subtle bugs involve this detail being missed.

Hum... Question: Do you think that I should leave it alone?

My first feeling was to remove the "signed byte" distinction, and to
replace it with "byte".

But, then, of course, the sign bit would not be "extended"...

Damned! All that for 5 bytes out of 40 K! As I said, I could not find
any instance of a "signed byte" anywhere else in the Intel doc. (It
would be funny to ask this question to some "gurus"...)

Opinions welcomed.

roch...@laposte.net

unread,
Sep 13, 2007, 9:45:00 AM9/13/07
to
Hello, Glen!

> If I (remember,understand) right, the 8086 fetches one byte from
> the target address. It doesn't modify the register indicated, but
> does it ever fetch two bytes? I believe an 8088 will only fetch
> one, as will an 8086 with an odd address. In the case of an
> even address, does the 8086 fetch the whole word, even when only
> one byte is needed? Does a load of al from an even memory
> address do a 16 bit fetch or an 8 bit fetch?

As I said, isn't the 8086 family wonderful, still raising questions 30
years later?

I am writing this from the cybercafe, so have no access to my books.

However, if I have well understood, the only difference between the
8086 and the 8088 (that Intel was obliged to introduce 2 years later,
since everybody was using 8-bit systems at the time. Introducing a 16-
bit CPU alone, without any 16-bit environment was, of course, crazy.
Finally, a little company chose the 8088...) is the "size" of the I/O
words (16 versus 8). Internally, both are reading 16 bits, since they
are 16-bits CPUs. It is only for I/0 that there is a difference in
"size". However, as explained previously, there are still quite a lot
of "single byte" "primary opcode". (Remember that most instructions
are coded on 6 bits, with a "secondary opcode" (re-re-see my last
message, where the so-called "MODRM byte" -- its author calls it the
"secondary opcode" -- is explained at length.) So, it is a 16-bit CPU
that uses (most of the time) 6-bits instructions, and 77 times 6+3
bits instructions! Logical, isn't it?

Roger Ivie

unread,
Sep 13, 2007, 3:37:50 PM9/13/07
to
On 2007-09-13, roch...@laposte.net <roch...@laposte.net> wrote:
> However, if I have well understood, the only difference between the
> 8086 and the 8088 (that Intel was obliged to introduce 2 years later,
> since everybody was using 8-bit systems at the time. Introducing a 16-
> bit CPU alone, without any 16-bit environment was, of course, crazy.
> Finally, a little company chose the 8088...) is the "size" of the I/O
> words (16 versus 8).

As Allison has mentioned, they also differ in the depth of their
prefetch buffer. Software used to be able to detect which processor
(8088 vs 8086) they were running on by using self-modifying code,
changing an opcode close to where they were executing. If the old
opcode was executed, the processor was an 8086 with a deep buffer
(it had already prefetched the opcode, so missed the update). If
the new opcode was exectued, the processor was an 8088.

I don't recall which software I saw that tested this, or why it
needed to know.

IIRC, on an 8086 only even I/O ports can be 16 bits wide...
--
roger ivie
ri...@ridgenet.net

Lawrence Statton

unread,
Sep 13, 2007, 3:54:41 PM9/13/07
to
Roger Ivie <ri...@ridgenet.net> writes:
>
> I don't recall which software I saw that tested this, or why it
> needed to know.

I could imagine that precisely BECAUSE of the different prefetch
behavior that information could be used to color various unrolling
decisions.

> IIRC, on an 8086 only even I/O ports can be 16 bits wide...

I seem to remember the same requirement for the 8088 - I had a
programmer friend who swore up and down that you couldn't do 16-bit
IN/OUT instructions at ALL on the 8088, and was flabbergasted when I
showed my system that used them all the time (talking to an on-board
68000) ...

--
Lawrence Statton - lawre...@abaluon.abaom s/aba/c/g
Computer software consists of only two components: ones and
zeros, in roughly equal proportions. All that is required is to
place them into the correct order.

no....@no.uce.bellatlantic.net

unread,
Sep 13, 2007, 8:06:16 PM9/13/07
to
On 13 Sep 2007 14:54:41 -0500, Lawrence Statton
<yankee...@gmail.com> wrote:

>Roger Ivie <ri...@ridgenet.net> writes:
>>
>> I don't recall which software I saw that tested this, or why it
>> needed to know.
>
>I could imagine that precisely BECAUSE of the different prefetch
>behavior that information could be used to color various unrolling
>decisions.

It wasn't that smart. If the prefetch was busted the que is flushed
and the next fetch was the required instruction or data and the que
refilled.

>
>> IIRC, on an 8086 only even I/O ports can be 16 bits wide...
>
>I seem to remember the same requirement for the 8088 - I had a
>programmer friend who swore up and down that you couldn't do 16-bit
>IN/OUT instructions at ALL on the 8088, and was flabbergasted when I
>showed my system that used them all the time (talking to an on-board
>68000) ...

Of course it can... 8bits at a time! ;)

Allison

no....@no.uce.bellatlantic.net

unread,
Sep 13, 2007, 8:20:35 PM9/13/07
to

Your flogging a dead horse.

One of the things you haven't considered is the work alike NEC V20
and friends. They are different inside and yet they execute all
Intel opcodes plus those for the 8080 emulation. They even fit the
same socket.

Soon as you look at 80186/8 and the later parts your vision will
clear.

The intel docs were official but not the most well written.

Allison

s_dub...@yahoo.com

unread,
Sep 13, 2007, 10:37:38 PM9/13/07
to
On Sep 13, 7:29 am, roche...@laposte.net wrote:
> Hello, Steve!
>
> > The issue here is that the source is a signed byte, but the
> > destination is word_sized, so..
>
> > 83 nn OP Reg16|Mem16,signed Immed8
>
> > assures sign extention into the larger destination. I wonder how many
> > subtle bugs involve this detail being missed.
>
> Hum... Question: Do you think that I should leave it alone?
>
Hello!

Yes, it is an important difference. If anything it should be
emphasized.
Byte FDh == -3, cast to a word_size with sign extention -> FFFDh ==
-3.
Byte FDh cast to word_size without extention -> 00FDh == 253.

Steve

glen herrmannsfeldt

unread,
Sep 14, 2007, 4:03:56 AM9/14/07
to
Lawrence Statton wrote:
(snip)

>>IIRC, on an 8086 only even I/O ports can be 16 bits wide...

> I seem to remember the same requirement for the 8088 - I had a
> programmer friend who swore up and down that you couldn't do 16-bit
> IN/OUT instructions at ALL on the 8088, and was flabbergasted when I
> showed my system that used them all the time (talking to an on-board
> 68000) ...

The 8088 presumably does two IN or OUT cycles to successive
addresses for word I/O instructions. The 8086 should do two
cycles for word I/O to an odd address. It will look to
the device like two 8 bit I/O instructions. That will work
for some devices, and not others.

I believe that the 8086's HBE does not go low for a byte IN on an
even address, but I can't be sure about that.

-- glen

glen herrmannsfeldt

unread,
Sep 14, 2007, 4:15:48 AM9/14/07
to
no....@no.uce.bellatlantic.net wrote:

> On Thu, 13 Sep 2007 02:26:00 -0800, glen herrmannsfeldt

(snip regarding 8086 ESC)

>>If I (remember,understand) right, the 8086 fetches one byte from
>>the target address. It doesn't modify the register indicated, but
>>does it ever fetch two bytes? I believe an 8088 will only fetch
>>one, as will an 8086 with an odd address. In the case of an
>>even address, does the 8086 fetch the whole word, even when only
>>one byte is needed? Does a load of al from an even memory
>>address do a 16 bit fetch or an 8 bit fetch?

> If memory is right the 86 fetches three and the 88 only one.

I am pretty sure it is only one cycle, and I believe one
byte even on the 8086. I am a little unsure in general if the
8086 guarantees to keep HBE high on an even byte read cycle.

It is much more important to get right on a write cycle!

> However what has been forgotton is the 8089 IOP also hasan interacting
> mechanism like a NDP.

I actually have an 8089, though nothing to use it on.

-- glen

roch...@laposte.net

unread,
Sep 14, 2007, 8:24:00 AM9/14/07
to
Hello, Glen!

Back home, here is what I found about the 8086/8088 difference
(I mistook "I/O" for "memory".)

(By the way, when re-(etc.)reading the book, I found somewhere
that "primary opcode" are usually coded on 5 bits, and
"secondary opcodes" are coded on 7 bits (in the "primary
opcode") and 3 bits (between MOD and R/M). So simple, isn't it?)

Yours Sincerely,
Mr Emmanuel Roche


The 8086, as well as the 8088, has some instructions that access
(read or write) bytes, and other instructions that access words.
Now, here comes the difference between the two processors. Let
us consider the 8088 first. The amount of information that the
8088 transfers to, or from, memory at one time is always 8 bits.
A byte instruction in the 8088 can perform its function with one
memory access, whereas an 8088 word instruction must do two
memory accesses to two consecutive bytes. Examples of 8088 byte
and word reads are shown in Figure 2.4.

8088 Memory
+------+ : : Lower addresses
| | <---- Byte being read ---- | // |
| | | |
+------+ : : Higher addresses

(a) Reading in a byte


8088 Memory
+------+ : : Lower
addresses
| | <-- 1st byte of word being read -- | // |
| | <-- 2nd byte of word being read -- | // |
+------+ : : Higher
addresses

(b) Reading in a word

Figure 2.4 Reading bytes and words from 8088 memory

Now for the 8086. The amount of information it transfers to, or
from, memory at one time is always 16 bits. In the case of byte
instructions, only eight of those bits are used, and the other
eight are ignored. The 16 bits are always the contents of two
consecutive bytes in memory, starting with a byte at an even
address. That means that a word instruction that reads, or
writes, a word starting at an even address can perform its
function with one memory access. However, word instructions for
words starting at odd addresses must do more work; they must do
two memory accesses to two consecutive even-address words,
ignore the unwanted half of each, and do some byte juggling with
the remaining halves. Examples of the various byte and word
reads are shown in Figure 2.5.


8088 Memory
+------+ : : Lower addresses
| | <---- Byte being read ---- | // | Even address
| | <---- Byte ignored ------- | | Odd address
+------+ : : Higher addresses

(a) Reading in even-addressed byte


8088 Memory
+------+ : : Lower addresses
| | <---- Byte ignored ------- | | Even address
| | <---- Byte being read ---- | // | Odd address
+------+ : : Higher addresses

(b) Reading in odd-addressed byte


8088 Memory
+------+ : : Lower addresses
| | <---- Word being read ---- | // | Even address
| | <---- Word being read ---- | // | Odd address
+------+ : : Higher addresses

(c) Reading in even-addressed word


8088 Memory
+------+ : : Lower addresses
| | <----- Byte ignored ------ | |
| | <--- 1st byte of word ---- | // | Even address
| | <--- 2nd byte of word ---- | // | Odd address
| | <----- Byte ignored ------ | |
+------+ : : Higher addresses

(d) Reading in odd-addressed word requires two memory accesses

Figure 2.5 Reading bytes and words from 8086 memory

The program in the 8086 (or 8088) is oblivious to all of these
memory-accessing contortions; an instruction merely requests the
accessing (reading or writing) of a particular byte or word, and
the processor does whatever is necessary to perform such an
access.


EOF


roch...@laposte.net

unread,
Sep 14, 2007, 8:24:57 AM9/14/07
to
Hello, Steve!

Re-re-(etc.)reading the bloody book, here is what I found about
the S field involved with "signed byte".

Notice the following sentence: "This is particularly true of
immediate operands used with addition, subtraction, and
comparison instructions; it is less true of immediate operands
used with logical instructions." So, with the exception that he
does not mention "addition with carry" and "subtract with
borrow", he confirms, indeed, that my "Imm5" line is correct...

opc. | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111
------+-----+-----+-----+-----+-----+-----+-----+-----
Immed | ADD | OR | ADC | SBB | AND | SUB | XOR | CMP
------+-----+-----+-----+-----+-----+-----+-----+-----
Imm5 | ADD | --- | ADC | SBB | --- | SUB | --- | CMP

It looks like I will, in the end, be obliged to keep the 83
opcode in ASM-86.

I particularly enjoyed the sentence: "Note that one byte is
eliminated by having the S field." I wonder how many
assemblers/compilers were aware of those 5 instructions, and
used them? The 8086 CPU instruction set really seems to have
been designed by newby electronics engineers for compilers, with
a total disrespect for the instruction set of the 8080, which
has stood the test of time (The 2 Mars rovers (still working
after 3 years on Mars!) use 8080 CPUs... 30+ years later!)


Yours Sincerely,
Mr Emmanuel Roche


Since two-operand instructions have only one W field, either
both operands must be 8 bits, or both must be 16 bits. However,
immediate operands are frequently small numbers that don't
require 16 bits. This is particularly true of immediate operands
used with addition, subtraction, and comparison instructions; it
is less true of immediate operands used with logical
instructions. It follows that we could reduce the size of
immediate-operand instructions if we did not have to use 16 bits
to house small numbers. To accomplish this, some of the
immediate-operand instructions (additions, subtractions, and
comparisons) contain an S field (S means Sign-extend). This
field only has significance for 16-bit operands (W = 1), and
signifies whether all 16 bits of the immediate operand are
contained in the instruction (S = 0), or whether only the 8
least significant bits are contained in the instruction and must
be sign-extended to form the 16-bit operand (S = 1). This form
is illustrated in Figure 2.24.

+--------+---+---+ +-----+----+-----+ +------+ +---------------------+
| opcode | S | W | | MOD |opc.| R/M | | data | | data if S, W = 0, 1 |
+--------+---+---+ +-----+----+-----+ +------+ +---------------------+

Figure 2.24 Immediate-operand instruction containing an S
field

Figure 2.25 shows an example of such an instruction. In this
example, the value 0000 0000 0000 1111 is added to the contents
of a word in memory, and the result placed back into the memory
word. The memory word is in the data segment at the offset
contained in DI. Note that one byte is eliminated by having the
S field.

opcode S W MOD opcode R/M data
+-------------+---+---+ +-----+-------+-------+ +-----------------+
| 1 0 0 0 0 0 | 1 | 1 | | 0 0 | 0 0 0 | 1 1 1 | | 0 0 0 0 1 1 1 1 |
+-------------+-+-+-+-+ +-+---+-------+-------+ +-----------------+
ADD | | | ADD DI
| | +--> memory
| +--> word
+--> sign extend

Figure 2.25 Example of immediate-operand instruction
containing an S field


EOF


roch...@laposte.net

unread,
Sep 14, 2007, 8:26:39 AM9/14/07
to
- "8086 Instruction Set: The End?"

Last evening, I wanted to know if I was really understanding
clearly the instruction set of the Intel 8086 CPU. (The only way
I know to check that you know a subject is to program a
computer, since it finds so easily all the errors in your
reasoning. Unfortunately, officially, this is not a subject to
be taught. Instead, schools and Universities are filled with
philosophers/sophists, who are talking and talking and
talking...) (As you probably understood, I prefer "hard"
Sciences.) So, I modified an old (8080) table-driven
"disassembler" (I prefer to call it a Lister, since it produces
an output as similar to an LST file as possible, from a CMD
file).

Testing it systematically against my I8086.A86 file, modeled
after the official Intel "Machine Instruction Decoding Guide", I
checked opcode after opcode.

Since the end of the opcodes was arriving, I decided to
continue, despite the very, very early hours of the next
morning...

It is then that I noticed the following patterns:

02C0 F606111112 R test mem_8,12h
; F6 -- mod 001 r/m -- not used
02C5 F6161111 R not mem_8
02C9 F61E1111 R neg mem_8
02CD F6261111 R mul mem_8
02D1 F62E1111 R imul mem_8
02D5 F6361111 R div mem_8
02D9 F63E1111 R idiv mem_8

02DD F70622225634 R test mem_16,3456h
; F7 -- mod 001 r/m -- not used
02E3 F7162222 R not mem_16
02E7 F71E2222 R neg mem_16
02EB F7262222 R mul mem_16
02EF F72E2222 R imul mem_16
02F3 F7362222 R div mem_16
02F7 F73E2222 R idiv mem_16

0309 FF062222 R inc mem_16
030D FF0E2222 R dec mem_16
0311 FFD0 call ax
0313 FF162222 R call mem_16
0317 FFE0 jmp ax
0319 FF262222 R jmp mem_16
031D FF362222 R push mem_16


; FF -- mod 111 r/m -- not used

In case you have not yet understood, those opcodes (F6, F7, and
FF) have VARYING lengths...

In the case of F6, only the first opcode is 5 bytes long: all
the others are 4 bytes long.

And, of course, my Lister is table-driven, has dozen of loops,
all based upon the data in the initial table... which is
expecting that opcodes have a fixed length (number of bytes)!

So, those 3 opcodes break the logic of a program which has run
without any problem since the Intel 8080 CPU was introduced in
1973...

Despair!


Yours Sincerely,
Mr Emmanuel Roche


EOF


glen herrmannsfeldt

unread,
Sep 14, 2007, 9:57:08 AM9/14/07
to
roch...@laposte.net wrote:
> Hello, Glen!
>
> Back home, here is what I found about the 8086/8088 difference
> (I mistook "I/O" for "memory".)

As far as I know, the difference between "memory" and I/O is
the value of the M/IO line.

> (By the way, when re-(etc.)reading the book, I found somewhere
> that "primary opcode" are usually coded on 5 bits, and
> "secondary opcodes" are coded on 7 bits (in the "primary
> opcode") and 3 bits (between MOD and R/M). So simple, isn't it?)

> The 8086, as well as the 8088, has some instructions that access


> (read or write) bytes, and other instructions that access words.
> Now, here comes the difference between the two processors. Let
> us consider the 8088 first. The amount of information that the
> 8088 transfers to, or from, memory at one time is always 8 bits.

That makes it a little easier to design into systems, the reason
that IBM chose it over the 8086 for the original IBM PC.

(snip)

> Now for the 8086. The amount of information it transfers to, or
> from, memory at one time is always 16 bits. In the case of byte
> instructions, only eight of those bits are used, and the other
> eight are ignored.

This isn't true on writes, and I don't believe for reads either.
The HBE and A0 lines are used to select which half of the word
is actually used. The 8086 is little-endian, so the low byte
is at the even address. A0 is low for either word or byte
access to an even address, and enables access to that byte.
HBE is low for word access and odd byte access, enables
access to that byte.

(snip)

> However, word instructions for
> words starting at odd addresses must do more work; they must do
> two memory accesses to two consecutive even-address words,
> ignore the unwanted half of each, and do some byte juggling with
> the remaining halves.

For memory, you can return the whole word on read. For write,
only the appropriate byte should be changed. I/O should
use A0 and HBE on read.

-- glen

no....@no.uce.bellatlantic.net

unread,
Sep 14, 2007, 12:02:10 PM9/14/07
to

I have a few of them, nasty things they are.

Allison

>
>-- glen

dke...@hotmail.com

unread,
Sep 14, 2007, 12:56:37 PM9/14/07
to
On Sep 3, 10:02 am, no.s...@no.uce.bellatlantic.net wrote:
> On Mon, 3 Sep 2007 15:01:40 GMT, B'ichela <mdal...@pinkrose.dhis.org>
> wrote:
>
> >In article <1188809693.591491.159...@d55g2000hsg.googlegroups.com>, roche...@laposte.net wrote:
> >> 82OPCODE.WS4 "How to produce 82 opcodes with ASM-86"
>
> >Just a quick question. of the Major processors used in Home PCs from
> >the 4004,
>
> 4004 never made it as PC cpu way to small (4bit data path).
>
> 8008 start of teh revolution at 8bits but still limited. NOT RISC.
>
> 8080,8086 (I doubt this one) NOT RISC by any stretch.
>
>
---snip---
Hi
I thought I'd add a little here. Current day x86 processors use RISC
engines
internally. Transmeta even took x86 instructions and created RISC
instructions
externally.
With a wide memory bandwidth, such as many minis and main frames had
in
the past, RISC makes a lot of sense. It has been shown to be most
effective
at getting things done.
This makes sense for a $100K machine. It doesn't make sense for a
$1.5K
machine. In order to make better use of memory bandwidth, the
compaction
of CISC like instructions makes better sense. Once in the processor,
these
can be expanded to RISC like operation in an internal cache.
As we move into the future, we'll see the memory bottle neck issue
even
move into the larger machines.
I'm not saying that the x86 set is the best useage of memory
bandwidth
but it is better than most RISC instruction sets.
A next generation processor would have to consider that effective use
of memory bandwidth is much more important than compiler simplicity.
More complicated CISC processors will continue to move ahead of
external RISC machines, even though the internal engine might still be
RISC in nature.
This is a simple problem of the speed increase of internal processing
exceding the speed of wires.
Dwight

David Given

unread,
Sep 14, 2007, 2:45:18 PM9/14/07
to
dke...@hotmail.com wrote:
[...]

> More complicated CISC processors will continue to move ahead of
> external RISC machines, even though the internal engine might still be
> RISC in nature.

Actually, the IA32 architecture is known for having lousy code density --- ARM
is better than it, and ARM Thumb is better than ARM, and the M-Core (a
Motorola Thumb rip-off) is even better than Thumb. All three processors are
about as RISC as they get.

(Comparing identical builds of gcc's cc1 internal executable, the ARM version
has a code segment size of 0x0037857c; the IA32 version is 0x0041c0d8.
Unfortunately I don't have a Thumb or M-Core version handy, but Thumb
typically gains 30% over ARM.)

It's interesting that one of the least code dense RISC processors is the
PowerPC --- which also has one of the least RISC instruction sets around...

roch...@laposte.net

unread,
Sep 15, 2007, 4:00:59 AM9/15/07
to
After quite a long session, I finally have something that seems
to work. Before publishing its source code, here you will find a
sample session, using the official "Machine Instruction Decoding
Guide" as a template. However, of course, this does not contain
all the possible combinations of the opcodes. So, it is quite
probable (given the complexity of the 8086 instruction set) that
some combinations of opcodes could produce erroneous values. You
have the week-end to check the following.

(I wanted to remove any "WORD" and "BYTE" (PTR) display but,
then, some mnemonics would be redundant, and it would not be
possible, at a glance, to know which particular form it is. I
amm thinking, in particular, to the pair of INC/DEC mnemonics...
Also, the [] helps to distinguish between opcodes 03 and 05.
Your comments on the syntax are welcomed. Example: how do you
distinguish the source and destination operands when both are to
be stored in 16-bit registers, but their values fit in a byte?
Do you need to add "WORD PTR" to both operands?)


Yours Sincerely,
Mr Emmanuel Roche


0000| 00 06 11 11 ADD [1111], AL ; ....
0004| 01 06 22 22 ADD [2222], AX ; ..""
0008| 02 06 11 11 ADD AL, [1111] ; ....
000C| 03 06 22 22 ADD AX, [2222] ; ..""
0010| 04 12 ADD AL, 12 ; ..
0012| 05 56 34 ADD AX, 3456 ; .V4
0015| 06 PUSH ES ; .
0016| 07 POP ES ; .
0017| 08 06 11 11 OR [1111], AL ; ....
001B| 09 06 22 22 OR [2222], AX ; ..""
001F| 0A 06 11 11 OR AL, [1111] ; ....
0023| 0B 06 22 22 OR AX, [2222] ; ..""
0027| 0C 12 OR AL, 12 ; ..
0029| 0D 56 34 OR AX, 3456 ; .V4
002C| 0E PUSH CS ; .
002D| 10 06 11 11 ADC [1111], AL ; ....
0031| 11 06 22 22 ADC [2222], AX ; ..""
0035| 12 06 11 11 ADC AL, [1111] ; ....
0039| 13 06 22 22 ADC AX, [2222] ; ..""
003D| 14 12 ADC AL, 12 ; ..
003F| 15 56 34 ADC AX, 3456 ; .V4
0042| 16 PUSH SS ; .
0043| 17 POP SS ; .
0044| 18 06 11 11 SBB [1111], AL ; ....
0048| 19 06 22 22 SBB [2222], AX ; ..""
004C| 1A 06 11 11 SBB AL, [1111] ; ....
0050| 1B 06 22 22 SBB AX, [2222] ; ..""
0054| 1C 12 SBB AL, 12 ; ..
0056| 1D 56 34 SBB AX, 3456 ; .V4
0059| 1E PUSH DS ; .
005A| 1F POP DS ; .
005B| 20 06 11 11 AND [1111], AL ; ...
005F| 21 06 22 22 AND [2222], AX ; !.""
0063| 22 06 11 11 AND AL, [1111] ; "...
0067| 23 06 22 22 AND AX, [2222] ; #.""
006B| 24 12 AND AL, 12 ; $.
006D| 25 56 34 AND AX, [3456] ; %V4
0070| 26 ES: ; &
0071| 00 06 00 00 ADD [0000], AL ; ....
0075| 27 DAA ; '
0076| 28 06 11 11 SUB [1111], AL ; (...
007A| 29 06 22 22 SUB [2222], AX ; ).""
007E| 2A 06 11 11 SUB AL, [1111] ; *...
0082| 2B 06 22 22 SUB AX, [2222] ; +.""
0086| 2C 12 SUB AL, 12 ; ,.
0088| 2D 56 34 SUB AX, 3456 ; -V4
008B| 2E CS: ; .
008C| 00 06 00 00 ADD [0000], AL ; ....
0090| 2F DAS ; /
0091| 30 06 11 11 XOR [1111], AL ; 0...
0095| 31 06 22 22 XOR [2222], AX ; 1.""
0099| 32 06 11 11 XOR AL, [1111] ; 2...
009D| 33 06 22 22 XOR AX, [2222] ; 3.""
00A1| 34 12 XOR AL, 12 ; 4.
00A3| 35 56 34 XOR AX, 3456 ; 5V4
00A6| 36 SS: ; 6
00A7| 00 06 00 00 ADD [0000], AL ; ....
00AB| 37 AAA ; 7
00AC| 38 06 11 11 CMP [1111], AL ; 8...
00B0| 39 06 22 22 CMP [2222], AX ; 9.""
00B4| 3A 06 11 11 CMP AL, [1111] ; :...
00B8| 3B 06 22 22 CMP AX, [2222] ; ;.""
00BC| 3C 12 CMP AL, 12 ; <.
00BE| 3D 56 34 CMP AX, 3456 ; =V4
00C1| 3E DS: ; >
00C2| 00 06 00 00 ADD [0000], AL ; ....
00C6| 3F AAS ; ?
00C7| 40 INC AX ; @
00C8| 41 INC CX ; A
00C9| 42 INC DX ; B
00CA| 43 INC BX ; C
00CB| 44 INC SP ; D
00CC| 45 INC BP ; E
00CD| 46 INC SI ; F
00CE| 47 INC DI ; G
00CF| 48 DEC AX ; H
00D0| 49 DEC CX ; I
00D1| 4A DEC DX ; J
00D2| 4B DEC BX ; K
00D3| 4C DEC SP ; L
00D4| 4D DEC BP ; M
00D5| 4E DEC SI ; N
00D6| 4F DEC DI ; O
00D7| 50 PUSH AX ; P
00D8| 51 PUSH CX ; Q
00D9| 52 PUSH DX ; R
00DA| 53 PUSH BX ; S
00DB| 54 PUSH SP ; T
00DC| 55 PUSH BP ; U
00DD| 56 PUSH SI ; V
00DE| 57 PUSH DI ; W
00DF| 58 POP AX ; X
00E0| 59 POP CX ; Y
00E1| 5A POP DX ; Z
00E2| 5B POP BX ; [
00E3| 5C POP SP ; \
00E4| 5D POP BP ; ]
00E5| 5E POP SI ; ^
00E6| 5F POP DI ; _
00E7| 70 FE JO 0167 ; p.
00E9| 71 FC JNO 0167 ; q.
00EB| 72 FA JB 0167 ; r.
00ED| 72 F8 JB 0167 ; r.
00EF| 72 F6 JB 0167 ; r.
00F1| 73 F4 JNB 0167 ; s.
00F3| 73 F2 JNB 0167 ; s.
00F5| 73 F0 JNB 0167 ; s.
00F7| 74 EE JZ 0167 ; t.
00F9| 74 EC JZ 0167 ; t.
00FB| 75 EA JNZ 0167 ; u.
00FD| 75 E8 JNZ 0167 ; u.
00FF| 76 E6 JBE 0167 ; v.
0101| 76 E4 JBE 0167 ; v.
0103| 77 E2 JA 0167 ; w.
0105| 77 E0 JA 0167 ; w.
0107| 78 DE JS 0167 ; x.
0109| 79 DC JNS 0167 ; y.
010B| 7A DA JP 0167 ; z.
010D| 7A D8 JP 0167 ; z.
010F| 7B D6 JNP 0167 ; {.
0111| 7B D4 JNP 0167 ; {.
0113| 7C D2 JL 0167 ; |.
0115| 7C D0 JL 0167 ; |.
0117| 7D CE JNL 0167 ; }.
0119| 7D CC JNL 0167 ; }.
011B| 7E CA JLE 0167 ; ~.
011D| 7E C8 JLE 0167 ; ~.
011F| 7F C6 JG 0167 ; ..
0121| 7F C4 JG 0167 ; ..
0123| 80 06 11 11 12 ADD [1111], 12 ; .....
0128| 80 0E 11 11 12 OR [1111], 12 ; .....
012D| 80 16 11 11 12 ADC [1111], 12 ; .....
0132| 80 1E 11 11 12 SBB [1111], 12 ; .....
0137| 80 26 11 11 12 AND [1111], 12 ; .&...
013C| 80 2E 11 11 12 SUB [1111], 12 ; .....
0141| 80 36 11 11 12 XOR [1111], 12 ; .6...
0146| 80 3E 11 11 12 CMP [1111], 12 ; .>...
014B| 81 06 22 22 56 34 ADD [2222], 3456 ; ..""V4
0151| 81 0E 22 22 56 34 OR [2222], 3456 ; ..""V4
0157| 81 16 22 22 56 34 ADC [2222], 3456 ; ..""V4
015D| 81 1E 22 22 56 34 SBB [2222], 3456 ; ..""V4
0163| 81 26 22 22 56 34 AND [2222], 3456 ; .&""V4
0169| 81 2E 22 22 56 34 SUB [2222], 3456 ; ..""V4
016F| 81 36 22 22 56 34 XOR [2222], 3456 ; .6""V4
0175| 81 3E 22 22 56 34 CMP [2222], 3456 ; .>""V4
017B| 82 C0 12 ADD AL, 12 ; ...
017E| 82 D0 12 ADC AL, 12 ; ...
0181| 82 D8 12 SBB AL, 12 ; ...
0184| 82 E8 12 SUB AL, 12 ; ...
0187| 82 F8 12 CMP AL, 12 ; ...
018A| 83 C5 12 ADD BP, 12 ; ...
018D| 83 D5 12 ADC BP, 12 ; ...
0190| 83 DD 12 SBB BP, 12 ; ...
0193| 83 ED 12 SUB BP, 12 ; ...
0196| 83 FD 12 CMP BP, 12 ; ...
0199| 84 06 11 11 TEST [1111], AL ; ....
019D| 85 06 22 22 TEST [2222], AX ; ..""
01A1| 86 06 11 11 XCHG AL, [1111] ; ....
01A5| 87 06 22 22 XCHG AX, [2222] ; ..""
01A9| 88 46 00 MOV [BP], AL ; .F.
01AC| 89 46 00 MOV [BP], AX ; .F.
01AF| 8A C1 MOV AL, CL ; ..
01B1| 8B C1 MOV AX, CX ; ..
01B3| 8C 1E 22 22 MOV [2222], DS ; ..""
01B7| 8D 06 22 22 LEA AX, [2222] ; ..""
01BB| 8E 1E 22 22 MOV DS, [2222] ; ..""
01BF| 8F 06 22 22 POP [2222] ; ..""
01C3| 90 NOP ; .
01C4| 91 XCHG AX, CX ; .
01C5| 92 XCHG AX, DX ; .
01C6| 93 XCHG AX, BX ; .
01C7| 94 XCHG AX, SP ; .
01C8| 95 XCHG AX, BP ; .
01C9| 96 XCHG AX, SI ; .
01CA| 97 XCHG AX, DI ; .
01CB| 98 CBW ; .
01CC| 99 CWD ; .
01CD| 9A 00 00 00 00 CALLF 0000:0000 ; .....
01D2| 9B WAIT ; .
01D3| 9C PUSHF ; .
01D4| 9D POPF ; .
01D5| 9E SAHF ; .
01D6| 9F LAHF ; .
01D7| A0 11 11 MOV AL, [1111] ; ...
01DA| A1 22 22 MOV AX, [2222] ; .""
01DD| A2 11 11 MOV [1111], AL ; ...
01E0| A3 22 22 MOV [2222], AX ; .""
01E3| A4 MOVSB ; .
01E4| A5 MOVSW ; .
01E5| A6 CMPSB ; .
01E6| A7 CMPSW ; .
01E7| A8 12 TEST AL, 12 ; ..
01E9| A9 56 34 TEST AX, 3456 ; .V4
01EC| AA STOSB ; .
01ED| AB STOSW ; .
01EE| AC LODSB ; .
01EF| AD LODSW ; .
01F0| AE SCASB ; .
01F1| AF SCASW ; .
01F2| B0 12 MOV AL, 12 ; ..
01F4| B1 12 MOV CL, 12 ; ..
01F6| B2 12 MOV DL, 12 ; ..
01F8| B3 12 MOV BL, 12 ; ..
01FA| B4 12 MOV AH, 12 ; ..
01FC| B5 12 MOV CH, 12 ; ..
01FE| B6 12 MOV DH, 12 ; ..
0200| B7 12 MOV BH, 12 ; ..
0202| B8 56 34 MOV AX, 3456 ; .V4
0205| B9 56 34 MOV CX, 3456 ; .V4
0208| BA 56 34 MOV DX, 3456 ; .V4
020B| BB 56 34 MOV BX, 3456 ; .V4
020E| BC 56 34 MOV SP, 3456 ; .V4
0211| BD 56 34 MOV BP, 3456 ; .V4
0214| BE 56 34 MOV SI, 3456 ; .V4
0217| BF 56 34 MOV DI, 3456 ; .V4
021A| C2 56 34 RET 3456 ; .V4

021D| C3 RET ; .

021E| C4 46 06 LES AX, 6[BP] ; .F.
0221| C5 46 06 LDS AX, 6[BP] ; .F.
0224| C6 06 11 11 12 MOV [1111], 12 ; .....
0229| C7 06 22 22 56 34 MOV [2222], 3456 ; ..""V4
022F| CA 56 34 RETF 3456 ; .V4

0232| CB RETF ; .

0233| CC INT 3 ; .
0234| CD 12 INT 12 ; ..
0236| CE INTO ; .
0237| CF IRET ; .

0238| D0 C0 ROL AL, 1 ; ..
023A| D0 C9 ROR CL, 1 ; ..
023C| D0 D2 RCL DL, 1 ; ..
023E| D0 DB RCR BL, 1 ; ..
0240| D0 E4 SHL AH, 1 ; ..
0242| D0 E5 SHL CH, 1 ; ..
0244| D0 EE SHR DH, 1 ; ..
0246| D0 FF SAR BH, 1 ; ..
0248| D1 C0 ROL AX, 1 ; ..
024A| D1 C9 ROR CX, 1 ; ..
024C| D1 D2 RCL DX, 1 ; ..
024E| D1 DB RCR BX, 1 ; ..
0250| D1 E0 SHL AX, 1 ; ..
0252| D1 E1 SHL CX, 1 ; ..
0254| D1 EA SHR DX, 1 ; ..
0256| D1 FB SAR BX, 1 ; ..
0258| D2 C0 ROL AL, CL ; ..
025A| D2 C9 ROR CL, CL ; ..
025C| D2 D2 RCL DL, CL ; ..
025E| D2 DB RCR BL, CL ; ..
0260| D2 E4 SHL AH, CL ; ..
0262| D2 E5 SHL CH, CL ; ..
0264| D2 EE SHR DH, CL ; ..
0266| D2 FF SAR BH, CL ; ..
0268| D3 C0 ROL AX, CL ; ..
026A| D3 C9 ROR CX, CL ; ..
026C| D3 D2 RCL DX, CL ; ..
026E| D3 DB RCR BX, CL ; ..
0270| D3 E0 SHL AX, CL ; ..
0272| D3 E1 SHL CX, CL ; ..
0274| D3 EA SHR DX, CL ; ..
0276| D3 FB SAR BX, CL ; ..
0278| D4 0A AAM ; ..
027A| D5 0A AAD ; ..
027C| D7 XLAT ; .
027D| D8 C0 ESC 0, AL ; ..
027F| D9 C1 ESC 8, CL ; ..
0281| DA C2 ESC 16, DL ; ..
0283| DB C3 ESC 24, BL ; ..
0285| DC C4 ESC 32, AH ; ..
0287| DD C5 ESC 40, CH ; ..
0289| DE C6 ESC 48, DH ; ..
028B| DF C7 ESC 56, BH ; ..
028D| E0 FE LOOPNE 030D ; ..
028F| E0 FC LOOPNE 030D ; ..
0291| E1 FA LOOPE 030D ; ..
0293| E1 F8 LOOPE 030D ; ..
0295| E2 F6 LOOP 030D ; ..
0297| E3 F4 JCXZ 030D ; ..
0299| E4 12 IN AL, 12 ; ..
029B| E5 12 IN AX, 12 ; ..
029D| E6 12 OUT 12, AL ; ..
029F| E7 12 OUT 12, AX ; ..
02A1| E8 5C FD CALL FD5C ; .\.
02A4| E9 59 FD JMP FD59 ; .Y.

02A7| EA 00 00 00 00 JMPF 0000:0000 ; .....

02AC| EB DF JMPS 030D ; ..

02AE| EC IN AL, DX ; .
02AF| ED IN AX, DX ; .
02B0| EE OUT DX, AL ; .
02B1| EF OUT DX, AX ; .
02B2| F0 90 LOCK 90 ; ..
02B4| F2 90 REPNE 90 ; ..
02B6| F2 90 REPNE 90 ; ..
02B8| F3 90 REP 90 ; ..
02BA| F3 90 REP 90 ; ..
02BC| F3 90 REP 90 ; ..
02BE| F4 HLT ; .
02BF| F5 CMC ; .
02C0| F6 06 11 11 12 TEST [1111], 12 ; ....
02C5| F6 16 11 11 NOT [1111] ; ....
02C9| F6 1E 11 11 NEG [1111] ; ....
02CD| F6 26 11 11 MUL [1111] ; .&..
02D1| F6 2E 11 11 IMUL [1111] ; ....
02D5| F6 36 11 11 DIV [1111] ; .6..
02D9| F6 3E 11 11 IDIV [1111] ; .>..
02DD| F7 06 22 22 56 34 TEST [2222], 3456 ; ..""
02E3| F7 16 22 22 NOT [2222] ; ..""
02E7| F7 1E 22 22 NEG [2222] ; ..""
02EB| F7 26 22 22 MUL [2222] ; .&""
02EF| F7 2E 22 22 IMUL [2222] ; ..""
02F3| F7 36 22 22 DIV [2222] ; .6""
02F7| F7 3E 22 22 IDIV [2222] ; .>""
02FB| F8 CLC ; .
02FC| F9 STC ; .
02FD| FA CLI ; .
02FE| FB STI ; .
02FF| FC CLD ; .
0300| FD STD ; .
0301| FE 06 11 11 INC [1111] ; ....
0305| FE 0E 11 11 DEC [1111] ; ....
0309| FF 06 22 22 INC [2222] ; ..""
030D| FF 0E 22 22 DEC [2222] ; ..""
0311| FF D0 CALL AX ; ..
0313| FF 16 22 22 CALL [2222] ; ..""
0317| FF E0 JMP AX ; ..
0319| FF 26 22 22 JMP [2222] ; .&""
031D| FF 36 22 22 PUSH [2222] ; .6""


EOF


s_dub...@yahoo.com

unread,
Sep 16, 2007, 10:13:11 AM9/16/07
to
On Sep 14, 6:26 am, roche...@laposte.net wrote:
> - "8086 Instruction Set: The End?"
>
Had you considered looking at the decode effort though using Octals?

for example...

01 ;; ok for nasm?
02 ;; -f bin -l tst_fsgs.lst -o tst_fsgs.bin tst_fsgs.nsm
03
04 00000000 8CC0 mov ax,es ;; Q214 Q300
05 00000002 8CC8 mov ax,cs ;; Q214 Q310
06 00000004 8CD0 mov ax,ss ;; Q214 Q320
07 00000006 8CD8 mov ax,ds ;; Q214 Q330
08 00000008 8CE0 mov ax,fs ;; Q214 Q340 ;;note continued logic
09 0000000A 8CE8 mov ax,gs ;; Q214 Q350 ;; for FS and GS
10
11 ;;eof
12
Note that 8Ch == Q214 octal which represents MOV Reg16|Mem16,SegmReg

With the later processor instruction extention to handle FS & GS, the
continued logic shows Octal as making simple sense where each byte
forms 3 octal digits, or 9bits where the first octal digit's first bit
is silent. i.e.
81h := 1000 0001b := x10 000 001b := Q201

I haven't gone thru the opcode table to see how the octal scheme
fares, but I am curious to do so.

Comments?

Steve

roch...@laposte.net

unread,
Sep 17, 2007, 4:52:57 AM9/17/07
to
Hello, Steve!

> Had you considered looking at the decode effort though using Octals?

> (...)


> I haven't gone thru the opcode table to see how the octal scheme
> fares, but I am curious to do so.

> Comments?

You bet!

LIST8086 started as a simple modification of LIST8080.BAS, which is
simply an array with 256 entries containing the mnemonics of the 8080
CPU.

(I did it this way 20 years ago because I wanted to be able to "play"
with any mnemonic: I wrote LIST8080 to investigate using another
"system language" syntax to replace the mnemonics of the 8080
assembler.)

All the "secondary opcodes" (the term used by one of the 4 authors of
the 8086 CPU) are decoded thanks to a table containing 8 entries for
each opcode. That is to say: I am obliged to use octal in their case,
since they are octal-coded.

However, after I finish to finally get this program to list all the
known 8086 opcodes, I could then modify it to display the opcodes in
octal, then decide if I rewrite it from scratch to use an octal jump
table.

Also, the table-driven version is much faster (on a 4-MHz Z-80) than a
version which was decoding each opcode, then deciding what to do. Of
course, now, with my 400-MHz system, speed is less important. But
table-driven programs are also much simpler to debug, then...

I suggest that we finish to debug the program first. As I mentioned
several times, Americans are fond of starting another thread at the
slightest problem, even before finishing the original job. As a
result, they often finish doing nothing. Me, I prefer to work step by
step. Only after having finished a step do I think about what to do
next. The comp.os.cpm Newsgroup now contains about 30 BASIC programs
that helped me settled various problems. Each time I wrote them, I had
no idea how I was going to solve the problem. Writing the programs
helped me to define more precisely the problem, and to find a
solution. If I rewrite the program, it would not be the first time
that, having finally understood fully the problem, I would rewrite the
program to more efficiently solve the problem. This is what I like
into programming: it is so much logical. Impossible to argue anything.

roch...@laposte.net

unread,
Sep 17, 2007, 4:54:43 AM9/17/07
to
- "The 8086 Instruction Set: The Sequel"

Well, well, well...

I was expecting today to publish the source code of a program
listing all the "legal" Intel 8086 opcodes and mnemonics.
Unfortunately, I have made a handful of discoveries this week-
end that need to be further investigated before deciding if the
program is finally fit for publication.

(I never had so much trouble understanding the opcodes of a
computer. Intel really goofed mightily when they designed the
8086 CPU instruction set.)

Ok. Let us start. This time, I used the Intel "The 8086 Family
User's Manual", October 1979, and particularly Table 4-13,
"Machine Instruction Decoding Guide", pages 4-27 to 4-35, as my
guide, checking systematically each opcode listed by my program
in this table.

It is then that I discovered another "feature" of the doc. You
may remember that I demonstrated (in "82 Opcodes: A bug made in
1978?") that the "secondary Opcode Space" table present in the
Appendix of the book "The 8086 Primer" written by one of the
authors of the 8086 CPU (and also present, a little bit
differently, in Table 4-14) is erroneous?

Well, I have found 3 other opcodes that are, obviously,
"secondary opcodes", yet are not documented in both books...

Consider the following:

0282| 8F 06 22 22 POP [2222] ; ..""
0286| 8F 08 22 22 --- [2222] ; ..""
028A| 8F 10 22 22 --- [2222] ; ..""
028E| 8F 18 22 22 --- [2222] ; ..""
0292| 8F 20 22 22 --- [2222] ; . ""
0296| 8F 28 22 22 --- [2222] ; .(""
029A| 8F 30 22 22 --- [2222] ; .0""
029E| 8F 38 22 22 --- [2222] ; .8""

(Reference: Pages 4-31 and 4-32.)

0305| C6 06 11 11 12 MOV BYTE [1111], 12 ; .....
030A| C6 08 11 11 12 --- BYTE [1111], 12 ; .....
030F| C6 10 11 11 12 --- BYTE [1111], 12 ; .....
0314| C6 18 11 11 12 --- BYTE [1111], 12 ; .....
0319| C6 20 11 11 12 --- BYTE [1111], 12 ; . ...
031E| C6 28 11 11 12 --- BYTE [1111], 12 ; .(...
0323| C6 30 11 11 12 --- BYTE [1111], 12 ; .0...
0328| C6 38 11 11 12 --- BYTE [1111], 12 ; .8...
032D| C7 06 22 22 56 34 MOV WORD [2222], 3456 ; ..""V4
0333| C7 08 22 22 56 34 --- WORD [2222], 3456 ; ..""V4
0339| C7 10 22 22 56 34 --- WORD [2222], 3456 ; ..""V4
033F| C7 18 22 22 56 34 --- WORD [2222], 3456 ; ..""V4
0345| C7 20 22 22 56 34 --- WORD [2222], 3456 ; . ""V4
034B| C7 28 22 22 56 34 --- WORD [2222], 3456 ; .(""V4
0351| C7 30 22 22 56 34 --- WORD [2222], 3456 ; .0""V4
0357| C7 38 22 22 56 34 --- WORD [2222], 3456 ; .8""V4

(Reference: Page 4-33.)

Only solution: to update yet another time the "Secondary Opcode
Space" table.

opc. | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111
------+-----+-----+-----+-----+-----+-----+-----+-----
Immed | ADD | OR | ADC | SBB | AND | SUB | XOR | CMP
------+-----+-----+-----+-----+-----+-----+-----+-----
Imm5 | ADD | --- | ADC | SBB | --- | SUB | --- | CMP

------+-----+-----+-----+-----+-----+-----+-----+-----
Grp 4 | POP | --- | --- | --- | --- | --- | --- | ---
------+-----+-----+-----+-----+-----+-----+-----+-----
Grp 5 | MOV | --- | --- | --- | --- | --- | --- | ---
------+-----+-----+-----+-----+-----+-----+-----+-----
Grp 6 | MOV | --- | --- | --- | --- | --- | --- | ---
------+-----+-----+-----+-----+-----+-----+-----+-----
Shift | ROL | ROR | RCL | RCR | SHL*| SHR | --- | SAR (*=SAL)
------+-----+-----+-----+-----+-----+-----+-----+-----
Grp 1 | TEST| --- | NOT | NEG | MUL | IMUL| DIV | IDIV
------+-----+-----+-----+-----+-----+-----+-----+-----
Grp 2 | INC | DEC | CALL| CALL| JMP | JMP | PUSH| ---
| | | id | L,id| id | L,id| |
------+-----+-----+-----+-----+-----+-----+-----+-----
Grp 3 | INC | DEC | --- | --- | --- | --- | --- | ---
------+-----+-----+-----+-----+-----+-----+-----+-----

(This was yet another bug in the official Intel doc.)

Now, continuing my systematic checking, I arrived to opcodes C4
and C5:

02FF| C4 46 06 LES AX, 6[BP] ; .F.


0302| C5 46 06 LDS AX, 6[BP] ; .F.

In case you did not notice, there is a problem with the above
lines. "The 8086 Family User's Guide" says Page 4-33 that they
should be 4 bytes long. However, Page 2-59, it says: "Bytes: 2-
4" which, as far as I understand English, means that they are
variable in length, which should be 2 to 4 bytes long. Let us
assume that this is an error, and try to find the information in
another source.

Address-Object Transfers
------------------------

The address-object transfers are LEA (Load Effective Address),
LDS (Load pointer into DS), and LES (Load pointer into ES).
These instructions provide the programmer with some control over
the addressing mechanism. The formats for these instructions are
shown in Figure 3.10.

+-----------------+ +-----+-----+-----+
| 1 0 0 0 1 1 0 1 | | mod | reg | r/m |
+-----------------+ +-----+-----+-----+
LEA: load EA to register

+-----------------+ +-----+-----+-----+
| 1 1 0 0 0 1 0 1 | | mod | reg | r/m |
+-----------------+ +-----+-----+-----+
LDS: load pointer to DS

+-----------------+ +-----+-----+-----+
| 1 1 0 0 0 1 0 0 | | mod | reg | r/m |
+-----------------+ +-----+-----+-----+
LES: load pointer to ES

Figure 3.10 Formats of address-object transfer instructions

Note that, although these instructions use a MOD and an R/M
field to specify one operand, and a REG field to specify the
other operand, there is no D field to specify which operand is
the source, and which is the destination. The D field is
unnecessary, because the source operand of these instructions
always comes from, or refer to, memory, and hence has to be
specified by the MOD and R/M fields. The reason why the source
operand must come from, or refer to, memory will become apparent
as each of the address-object transfers is described.

The LEA instruction provides access to the offset address of the
source operand, as opposed to the value of the operand. Hence,
this instruction would be meaningless if the source operand did
not refer to memory. The effect of the instruction is to
transfer the 16-bit offset address of the source operand to the
16-bit register designated as the destination operand. This
facility is useful for passing the offset address of a variable
from one part of the program to another, so that the other part
of the program can modify the value of the variable if it so
desired. Objects that are passed between different parts of the
program are called parameters, and the different parts of the
program are called subroutines. For example, suppose one
subroutine had the reponsibility for incrementing variables.
Other parts of the program could call on this incrementing
subroutine, and have it increment a specific variable. The
offset address of the variable to be incremented could be passed
as a parameter to the incrementing subroutine, by placing the
offset address in a mutually agreed upon register, such as BX,
prior to calling the incrementing subroutine. The LEA
instruction is tailor-made to do just that. The REG field of the
LEA instruction would designate the BX register (011), and the
MOD and R/M fields would designate the offset address of the
variable. The instruction would be executed prior to calling the
subroutine. The subroutine could then access the variable by
using the appropriate operand- address mode involving BX
(MOD=00, R/M=111). Note that, if the value of the variable,
instead of its offset, were passed to the incrementing
subroutine, the subroutine would know the value, but would be
unable to alter the variable.

The LDS instruction transfers four consecutive bytes (32 bits)
from a source operand to a pair of 16-bit destination registers.
The source operand must be in memory. One destination register
is the 16-bit destination operand specified by the REG field in
the instruction; the other destination register is DS. The LES
instruction is similar to LDS, except that the other destination
register is ES, instead of DS. The actual data transferred is
illustrated in Figure 3.11.

| +-------+
| | |
Offset address | |
as specified by | |
MOD and R/M fields | | 16-bit register
of instruction. | | specified by REG
| | | field of instruction.
| +-------+-+
+-------------->| 1 F | | +---------+
+-------+ +---> | 3 C 1 F |
| 3 C | | +---------+
+-------+-+
| A 5 | | +---------+
+-------+ +---> | 8 7 A 5 | DS or ES
| 8 7 | | +---------+
+-------+-+
| |
| |
+-------+

Figure 3.11 Data movement for LDS and LES instructions

The LDS and LES instructions provide an efficient means for
setting up the segment start address and offset address of a
variable, so that the variable can be accessed by succeeding
instructions. This combination of segment start address and
offset address is called a pointer; the LDS (or LES) instruction
transfers a pointer from memory into registers appropriate for
the operand-addressing modes. For example, assume offset
addresses 0F1C to 0F1F (four bytes) in the current data segment
contain a pointer to a 1-byte variable as shown in Figure
3.12(a).

Current
data segment
+---------+ +-----+
DS: | 8 0 0 0 +--+--> 80000 | |
+---------+ | | |
0F1C | |
| | |
| +-----+
+--> 80F1C | C 8 |
+-----+ Segment containing
| 1 0 | variable being
+-----+ pointed at.
| B 0 | +-----+
+-----+--+--> 14B00 | |
| 1 4 | | | |
+-----+ 10C8 | |
| | | +-----+
| | +--> 15BC8 | 3 F | One-
byte
| | +-----+
variable.
| | | |
| | | |
+-----+ +-----+

(a) Memory containing a pointer to a variable

The two-instruction sequence for loading the value of the
variable in the AL register is shown in Figure 3.12(b).

LSBits of MSBits of
offset offset
opcode MOD REG R/M address address
+----------+ +----+-----+-----+ +----------+ +----------+
| 11000101 | | 00 | 111 | 110 | | 00011100 | | 00001111 |
+----------+ +-+--+-----+-+---+ +----------+ +----------+
LDS \ BX / 1C 0F
\ /
Offset is in
next two bytes.

(i) Instruction that load pointer into registers DS and BX

+--------+---+---+ +----+-----+-----+
| 100010 | 1 | 0 | | 00 | 000 | 111 |
+--------+-+-+---+ +-+--+-----+-----+
MOV | byte | AL BX
| +--> no displacement
+--> to REG operand

(ii) Instruction that use operand-addressing mode
involving DS and BX to access variable being pointed at.

Figure 3.12 Example of using LDS instruction

- "The 8086 Primer, 2nd Edition"
Stephen P. Morse
Hayden Books, 1982

Figure 3.12 settle the question. The LEA, LDS, and LES
instructions all produce 4 bytes of opcode. The problem being
that ASM-86 (and RASM-86) produces 3 bytes for the LDS and LES
mnemonics (LEA produces 4 bytes). So, I am afraid that I have
discovered a real genuine bug inside both assemblers.

So, I added a pair of "codemacros" (a feature of ASM-86) to my
test file, resulting in the following output from my program:

02FF| C4 06 22 22 LES [2222] ; ..""
0303| C5 06 22 22 LDS [2222] ; ..""

Well! I was not expecting so much trouble, just to list the
mnemonics of a program...

Continuing, I finally arrived another time to the FF opcode...

0463| FF 06 22 22 INC WORD [2222] ; ..""
0467| FF 0E 22 22 DEC WORD [2222] ; ..""
046B| FF D0 22 22 CALL WORD [2222] ; ..""
046F| FF 16 22 22 CALL WORD [2222] ; ..""
0473| FF E0 22 22 JMP WORD [2222] ; ..""
0477| FF 26 22 22 JMP WORD [2222] ; .&""
047B| FF 36 22 22 PUSH WORD [2222] ; .6""
047F| FF 38 22 22 --- WORD [2222] ; .8""

Maybe you remember my question: "How do you distinguish between
opcodes FE and FF, since both have a pair of INC/DEC?" Well,
using SID-86, I got:

0443| FE 06 11 11 INC BYTE [1111] ; ....
0447| FE 0E 11 11 DEC BYTE [1111] ; ....

that is to say: this is yet another case where the 8086 CPU has
instructions first for bytes, then for words. So, FE=BYTE, and
FF=WORD. Hence the idea of displaying "WORD" in front of all the
FF opcodes (the subroutine is then much simpler...).

If we compare this output with an ASM-86 program generating the
opcodes:

0309 FF062222 R inc mem_16
030D FF0E2222 R dec mem_16
0311 FFD0 call ax
0313 FF162222 R call mem_16
0317 FFE0 jmp ax
0319 FF262222 R jmp mem_16
031D FF362222 R push mem_16
; FF -- mod 111 r/m -- not used

we notice that both CALL and JMP to 16-bit register does not
take a parameter, according to Digital Research. However, in the
Intel book, we find that all the FF opcodes are 4 bytes long...
This is the first problem.

The second problem is the comments for both CALL and JMP. Each
time, Intel writes that the first instance is "intrasegment",
while the second one is "intersegment". In Digital Research
syntax, that means CALL, CALLF, JMP, and JMPF. The problem
being, then, that the "intersegment" versions would be 6 bytes
long, not 4...

(The third problem is that ASM-86 refuses the CALLF and JMPF
mnemonics.)

So, is anybody out there who knows the "legal" forms of the FF
opcodes of the Intel 8086 CPU? (It was introduced in 1978... I
hope it is officially documented, by now?)

To finish, since I managed to reach opcode FF, you will find
following the output by the present program. Depending upon the
reactions to this message, I could modify the program, to
improve it.

(As you can see, at the moment, the program outputs "=??" to
signal a "not used" (primary) opcode, and "---" to signal "not
used secondary opcodes". The final version will output only
"=??", like the debuggers of Digital Research. For now, they
help debugging which table is holding the "mnemonic".)

Yours Sincerely,
Mr Emmanuel Roche


0080| 00 06 11 11 ADD [1111], AL ; ....
0084| 01 06 22 22 ADD [2222], AX ; ..""
0088| 02 06 11 11 ADD AL, [1111] ; ....
008C| 03 06 22 22 ADD AX, [2222] ; ..""
0090| 04 12 ADD AL, 12 ; ..
0092| 05 56 34 ADD AX, 3456 ; .V4
0095| 06 PUSH ES ; .
0096| 07 POP ES ; .
0097| 08 06 11 11 OR [1111], AL ; ....
009B| 09 06 22 22 OR [2222], AX ; ..""
009F| 0A 06 11 11 OR AL, [1111] ; ....
00A3| 0B 06 22 22 OR AX, [2222] ; ..""
00A7| 0C 12 OR AL, 12 ; ..
00A9| 0D 56 34 OR AX, 3456 ; .V4
00AC| 0E PUSH CS ; .
00AD| 0F =?? ; .
00AE| 10 06 11 11 ADC [1111], AL ; ....
00B2| 11 06 22 22 ADC [2222], AX ; ..""
00B6| 12 06 11 11 ADC AL, [1111] ; ....
00BA| 13 06 22 22 ADC AX, [2222] ; ..""
00BE| 14 12 ADC AL, 12 ; ..
00C0| 15 56 34 ADC AX, 3456 ; .V4
00C3| 16 PUSH SS ; .
00C4| 17 POP SS ; .
00C5| 18 06 11 11 SBB [1111], AL ; ....
00C9| 19 06 22 22 SBB [2222], AX ; ..""
00CD| 1A 06 11 11 SBB AL, [1111] ; ....
00D1| 1B 06 22 22 SBB AX, [2222] ; ..""
00D5| 1C 12 SBB AL, 12 ; ..
00D7| 1D 56 34 SBB AX, 3456 ; .V4
00DA| 1E PUSH DS ; .
00DB| 1F POP DS ; .
00DC| 20 06 11 11 AND [1111], AL ; ...
00E0| 21 06 22 22 AND [2222], AX ; !.""
00E4| 22 06 11 11 AND AL, [1111] ; "...
00E8| 23 06 22 22 AND AX, [2222] ; #.""
00EC| 24 12 AND AL, 12 ; $.
00EE| 25 56 34 AND AX, 3456 ; %V4
00F1| 26 ES: ; &
00F2| 00 06 00 00 ADD [0000], AL ; ....
00F6| 27 DAA ; '
00F7| 28 06 11 11 SUB [1111], AL ; (...
00FB| 29 06 22 22 SUB [2222], AX ; ).""
00FF| 2A 06 11 11 SUB AL, [1111] ; *...
0103| 2B 06 22 22 SUB AX, [2222] ; +.""
0107| 2C 12 SUB AL, 12 ; ,.
0109| 2D 56 34 SUB AX, 3456 ; -V4
010C| 2E CS: ; .
010D| 00 06 00 00 ADD [0000], AL ; ....
0111| 2F DAS ; /
0112| 30 06 11 11 XOR [1111], AL ; 0...
0116| 31 06 22 22 XOR [2222], AX ; 1.""
011A| 32 06 11 11 XOR AL, [1111] ; 2...
011E| 33 06 22 22 XOR AX, [2222] ; 3.""
0122| 34 12 XOR AL, 12 ; 4.
0124| 35 56 34 XOR AX, 3456 ; 5V4
0127| 36 SS: ; 6
0128| 00 06 00 00 ADD [0000], AL ; ....
012C| 37 AAA ; 7
012D| 38 06 11 11 CMP [1111], AL ; 8...
0131| 39 06 22 22 CMP [2222], AX ; 9.""
0135| 3A 06 11 11 CMP AL, [1111] ; :...
0139| 3B 06 22 22 CMP AX, [2222] ; ;.""
013D| 3C 12 CMP AL, 12 ; <.
013F| 3D 56 34 CMP AX, 3456 ; =V4
0142| 3E DS: ; >
0143| 00 06 00 00 ADD [0000], AL ; ....
0147| 3F AAS ; ?
0148| 40 INC AX ; @
0149| 41 INC CX ; A
014A| 42 INC DX ; B
014B| 43 INC BX ; C
014C| 44 INC SP ; D
014D| 45 INC BP ; E
014E| 46 INC SI ; F
014F| 47 INC DI ; G
0150| 48 DEC AX ; H
0151| 49 DEC CX ; I
0152| 4A DEC DX ; J
0153| 4B DEC BX ; K
0154| 4C DEC SP ; L
0155| 4D DEC BP ; M
0156| 4E DEC SI ; N
0157| 4F DEC DI ; O
0158| 50 PUSH AX ; P
0159| 51 PUSH CX ; Q
015A| 52 PUSH DX ; R
015B| 53 PUSH BX ; S
015C| 54 PUSH SP ; T
015D| 55 PUSH BP ; U
015E| 56 PUSH SI ; V
015F| 57 PUSH DI ; W
0160| 58 POP AX ; X
0161| 59 POP CX ; Y
0162| 5A POP DX ; Z
0163| 5B POP BX ; [
0164| 5C POP SP ; \
0165| 5D POP BP ; ]
0166| 5E POP SI ; ^
0167| 5F POP DI ; _
0168| 60 =?? ; `
0169| 61 =?? ; a
016A| 62 =?? ; b
016B| 63 =?? ; c
016C| 64 =?? ; d
016D| 65 =?? ; e
016E| 66 =?? ; f
016F| 67 =?? ; g
0170| 68 =?? ; h
0171| 69 =?? ; i
0172| 6A =?? ; j
0173| 6B =?? ; k
0174| 6C =?? ; l
0175| 6D =?? ; m
0176| 6E =?? ; n
0177| 6F =?? ; o
0178| 70 FE JO 0178 ; p.
017A| 71 FC JNO 0178 ; q.
017C| 72 FA JB 0178 ; r.
017E| 72 F8 JB 0178 ; r.
0180| 72 F6 JB 0178 ; r.
0182| 73 F4 JNB 0178 ; s.
0184| 73 F2 JNB 0178 ; s.
0186| 73 F0 JNB 0178 ; s.
0188| 74 EE JZ 0178 ; t.
018A| 74 EC JZ 0178 ; t.
018C| 75 EA JNZ 0178 ; u.
018E| 75 E8 JNZ 0178 ; u.
0190| 76 E6 JBE 0178 ; v.
0192| 76 E4 JBE 0178 ; v.
0194| 77 E2 JA 0178 ; w.
0196| 77 E0 JA 0178 ; w.
0198| 78 DE JS 0178 ; x.
019A| 79 DC JNS 0178 ; y.
019C| 7A DA JP 0178 ; z.
019E| 7A D8 JP 0178 ; z.
01A0| 7B D6 JNP 0178 ; {.
01A2| 7B D4 JNP 0178 ; {.
01A4| 7C D2 JL 0178 ; |.
01A6| 7C D0 JL 0178 ; |.
01A8| 7D CE JNL 0178 ; }.
01AA| 7D CC JNL 0178 ; }.
01AC| 7E CA JLE 0178 ; ~.
01AE| 7E C8 JLE 0178 ; ~.
01B0| 7F C6 JG 0178 ; ..
01B2| 7F C4 JG 0178 ; ..
01B4| 80 06 11 11 12 ADD BYTE [1111], 12 ; .....
01B9| 80 0E 11 11 12 OR BYTE [1111], 12 ; .....
01BE| 80 16 11 11 12 ADC BYTE [1111], 12 ; .....
01C3| 80 1E 11 11 12 SBB BYTE [1111], 12 ; .....
01C8| 80 26 11 11 12 AND BYTE [1111], 12 ; .&...
01CD| 80 2E 11 11 12 SUB BYTE [1111], 12 ; .....
01D2| 80 36 11 11 12 XOR BYTE [1111], 12 ; .6...
01D7| 80 3E 11 11 12 CMP BYTE [1111], 12 ; .>...
01DC| 81 06 22 22 56 34 ADD WORD [2222], 3456 ; ..""V4
01E2| 81 0E 22 22 56 34 OR WORD [2222], 3456 ; ..""V4
01E8| 81 16 22 22 56 34 ADC WORD [2222], 3456 ; ..""V4
01EE| 81 1E 22 22 56 34 SBB WORD [2222], 3456 ; ..""V4
01F4| 81 26 22 22 56 34 AND WORD [2222], 3456 ; .&""V4
01FA| 81 2E 22 22 56 34 SUB WORD [2222], 3456 ; ..""V4
0200| 81 36 22 22 56 34 XOR WORD [2222], 3456 ; .6""V4
0206| 81 3E 22 22 56 34 CMP WORD [2222], 3456 ; .>""V4
020C| 82 C0 12 ADD AL, 12 ; ...
020F| 82 08 12 --- AL, 12 ; ...
0212| 82 D0 12 ADC AL, 12 ; ...
0215| 82 D8 12 SBB AL, 12 ; ...
0218| 82 20 12 --- AL, 12 ; . .
021B| 82 E8 12 SUB AL, 12 ; ...
021E| 82 30 12 --- AL, 12 ; .0.
0221| 82 F8 12 CMP AL, 12 ; ...
0224| 83 C5 12 ADD BP, 12 ; ...
0227| 83 08 12 --- AX, 12 ; ...
022A| 83 D5 12 ADC BP, 12 ; ...
022D| 83 DD 12 SBB BP, 12 ; ...
0230| 83 20 12 --- AX, 12 ; . .
0233| 83 ED 12 SUB BP, 12 ; ...
0236| 83 30 12 --- AX, 12 ; .0.
0239| 83 FD 12 CMP BP, 12 ; ...
023C| 84 06 11 11 TEST [1111], AL ; ....
0240| 85 06 22 22 TEST [2222], AX ; ..""
0244| 86 06 11 11 XCHG AL, [1111] ; ....
0248| 87 06 22 22 XCHG AX, [2222] ; ..""
024C| 88 46 00 MOV [BP], AL ; .F.
024F| 89 46 00 MOV [BP], AX ; .F.
0252| 8A C1 MOV AL, CL ; ..
0254| 8B C1 MOV AX, CX ; ..
0256| 8C 1E 22 22 MOV [2222], DS ; ..""
025A| 8C 20 22 22 MOV [2222], -- ; . ""
025E| 8C 28 22 22 MOV [2222], -- ; .(""
0262| 8C 30 22 22 MOV [2222], -- ; .0""
0266| 8C 38 22 22 MOV [2222], -- ; .8""
026A| 8D 06 22 22 LEA AX, [2222] ; ..""
026E| 8E 1E 22 22 MOV DS, [2222] ; ..""
0272| 8E 20 22 22 MOV --, [2222] ; . ""
0276| 8E 28 22 22 MOV --, [2222] ; .(""
027A| 8E 30 22 22 MOV --, [2222] ; .0""
027E| 8E 38 22 22 MOV --, [2222] ; .8""
0282| 8F 06 22 22 POP [2222] ; ..""
0286| 8F 08 22 22 --- [2222] ; ..""
028A| 8F 10 22 22 --- [2222] ; ..""
028E| 8F 18 22 22 --- [2222] ; ..""
0292| 8F 20 22 22 --- [2222] ; . ""
0296| 8F 28 22 22 --- [2222] ; .(""
029A| 8F 30 22 22 --- [2222] ; .0""
029E| 8F 38 22 22 --- [2222] ; .8""
02A2| 90 NOP ; .
02A3| 91 XCHG AX, CX ; .
02A4| 92 XCHG AX, DX ; .
02A5| 93 XCHG AX, BX ; .
02A6| 94 XCHG AX, SP ; .
02A7| 95 XCHG AX, BP ; .
02A8| 96 XCHG AX, SI ; .
02A9| 97 XCHG AX, DI ; .
02AA| 98 CBW ; .
02AB| 99 CWD ; .
02AC| 9A 00 00 00 00 CALLF 0000:0000 ; .....
02B1| 9B WAIT ; .
02B2| 9C PUSHF ; .
02B3| 9D POPF ; .
02B4| 9E SAHF ; .
02B5| 9F LAHF ; .
02B6| A0 11 11 MOV AL, [1111] ; ...
02B9| A1 22 22 MOV AX, [2222] ; .""
02BC| A2 11 11 MOV [1111], AL ; ...
02BF| A3 22 22 MOV [2222], AX ; .""
02C2| A4 MOVSB ; .
02C3| A5 MOVSW ; .
02C4| A6 CMPSB ; .
02C5| A7 CMPSW ; .
02C6| A8 12 TEST AL, 12 ; ..
02C8| A9 56 34 TEST AX, 3456 ; .V4
02CB| AA STOSB ; .
02CC| AB STOSW ; .
02CD| AC LODSB ; .
02CE| AD LODSW ; .
02CF| AE SCASB ; .
02D0| AF SCASW ; .
02D1| B0 12 MOV AL, 12 ; ..
02D3| B1 12 MOV CL, 12 ; ..
02D5| B2 12 MOV DL, 12 ; ..
02D7| B3 12 MOV BL, 12 ; ..
02D9| B4 12 MOV AH, 12 ; ..
02DB| B5 12 MOV CH, 12 ; ..
02DD| B6 12 MOV DH, 12 ; ..
02DF| B7 12 MOV BH, 12 ; ..
02E1| B8 56 34 MOV AX, 3456 ; .V4
02E4| B9 56 34 MOV CX, 3456 ; .V4
02E7| BA 56 34 MOV DX, 3456 ; .V4
02EA| BB 56 34 MOV BX, 3456 ; .V4
02ED| BC 56 34 MOV SP, 3456 ; .V4
02F0| BD 56 34 MOV BP, 3456 ; .V4
02F3| BE 56 34 MOV SI, 3456 ; .V4
02F6| BF 56 34 MOV DI, 3456 ; .V4
02F9| C0 =?? ; .
02FA| C1 =?? ; .
02FB| C2 56 34 RET 3456 ; .V4

02FE| C3 RET ; .

02FF| C4 06 22 22 LES [2222] ; ..""
0303| C5 06 22 22 LDS [2222] ; ..""
0307| C6 06 11 11 12 MOV BYTE [1111], 12 ; .....
030C| C6 08 11 11 12 --- BYTE [1111], 12 ; .....
0311| C6 10 11 11 12 --- BYTE [1111], 12 ; .....
0316| C6 18 11 11 12 --- BYTE [1111], 12 ; .....
031B| C6 20 11 11 12 --- BYTE [1111], 12 ; . ...
0320| C6 28 11 11 12 --- BYTE [1111], 12 ; .(...
0325| C6 30 11 11 12 --- BYTE [1111], 12 ; .0...
032A| C6 38 11 11 12 --- BYTE [1111], 12 ; .8...
032F| C7 06 22 22 56 34 MOV WORD [2222], 3456 ; ..""V4
0335| C7 08 22 22 56 34 --- WORD [2222], 3456 ; ..""V4
033B| C7 10 22 22 56 34 --- WORD [2222], 3456 ; ..""V4
0341| C7 18 22 22 56 34 --- WORD [2222], 3456 ; ..""V4
0347| C7 20 22 22 56 34 --- WORD [2222], 3456 ; . ""V4
034D| C7 28 22 22 56 34 --- WORD [2222], 3456 ; .(""V4
0353| C7 30 22 22 56 34 --- WORD [2222], 3456 ; .0""V4
0359| C7 38 22 22 56 34 --- WORD [2222], 3456 ; .8""V4
035F| C8 =?? ; .
0360| C9 =?? ; .
0361| CA 56 34 RETF 3456 ; .V4

0364| CB RETF ; .

0365| CC INT 3 ; .
0366| CD 12 INT 12 ; ..
0368| CE INTO ; .
0369| CF IRET ; .

036A| D0 C0 ROL AL, 1 ; ..
036C| D0 C9 ROR CL, 1 ; ..
036E| D0 D2 RCL DL, 1 ; ..
0370| D0 DB RCR BL, 1 ; ..
0372| D0 E4 SHL AH, 1 ; ..
0374| D0 E5 SHL CH, 1 ; ..
0376| D0 EE SHR DH, 1 ; ..
0378| D0 30 --- AL, 1 ; .0
037A| D0 FF SAR BH, 1 ; ..
037C| D1 C0 ROL AX, 1 ; ..
037E| D1 C9 ROR CX, 1 ; ..
0380| D1 D2 RCL DX, 1 ; ..
0382| D1 DB RCR BX, 1 ; ..
0384| D1 E0 SHL AX, 1 ; ..
0386| D1 E1 SHL CX, 1 ; ..
0388| D1 EA SHR DX, 1 ; ..
038A| D1 30 --- AX, 1 ; .0
038C| D1 FB SAR BX, 1 ; ..
038E| D2 C0 ROL AL, CL ; ..
0390| D2 C9 ROR CL, CL ; ..
0392| D2 D2 RCL DL, CL ; ..
0394| D2 DB RCR BL, CL ; ..
0396| D2 E4 SHL AH, CL ; ..
0398| D2 E5 SHL CH, CL ; ..
039A| D2 EE SHR DH, CL ; ..
039C| D2 30 --- AL, CL ; .0
039E| D2 FF SAR BH, CL ; ..
03A0| D3 C0 ROL AX, CL ; ..
03A2| D3 C9 ROR CX, CL ; ..
03A4| D3 D2 RCL DX, CL ; ..
03A6| D3 DB RCR BX, CL ; ..
03A8| D3 E0 SHL AX, CL ; ..
03AA| D3 E1 SHL CX, CL ; ..
03AC| D3 EA SHR DX, CL ; ..
03AE| D3 30 --- AX, CL ; .0
03B0| D3 FB SAR BX, CL ; ..
03B2| D4 0A AAM ; ..
03B4| D5 0A AAD ; ..
03B6| D6 =?? ; .
03B7| D7 XLAT ; .
03B8| D8 C0 ESC 0, AL ; ..
03BA| D9 C1 ESC 8, CL ; ..
03BC| DA C2 ESC 16, DL ; ..
03BE| DB C3 ESC 24, BL ; ..
03C0| DC C4 ESC 32, AH ; ..
03C2| DD C5 ESC 40, CH ; ..
03C4| DE C6 ESC 48, DH ; ..
03C6| DF C7 ESC 56, BH ; ..
03C8| E0 FE LOOPNE 03C8 ; ..
03CA| E0 FC LOOPNE 03C8 ; ..
03CC| E1 FA LOOPE 03C8 ; ..
03CE| E1 F8 LOOPE 03C8 ; ..
03D0| E2 F6 LOOP 03C8 ; ..
03D2| E3 F4 JCXZ 03C8 ; ..
03D4| E4 12 IN AL, 12 ; ..
03D6| E5 12 IN AX, 12 ; ..
03D8| E6 12 OUT 12, AL ; ..
03DA| E7 12 OUT 12, AX ; ..
03DC| E8 A1 FC CALL FCA1 ; ...
03DF| E9 9E FC JMP FC9E ; ...

03E2| EA 00 00 00 00 JMPF 0000:0000 ; .....

03E7| EB DF JMPS 03C8 ; ..

03E9| EC IN AL, DX ; .
03EA| ED IN AX, DX ; .
03EB| EE OUT DX, AL ; .
03EC| EF OUT DX, AX ; .
03ED| F0 90 LOCK 90 ; ..
03EF| F1 =?? ; .
03F0| F2 90 REPNE 90 ; ..
03F2| F2 90 REPNE 90 ; ..
03F4| F3 90 REP 90 ; ..
03F6| F3 90 REP 90 ; ..
03F8| F3 90 REP 90 ; ..
03FA| F4 HLT ; .
03FB| F5 CMC ; .
03FC| F6 06 11 11 12 TEST BYTE [1111], 12 ; ....
0401| F6 08 11 11 --- BYTE [1111] ; ....
0405| F6 16 11 11 NOT BYTE [1111] ; ....
0409| F6 1E 11 11 NEG BYTE [1111] ; ....
040D| F6 26 11 11 MUL BYTE [1111] ; .&..
0411| F6 2E 11 11 IMUL BYTE [1111] ; ....
0415| F6 36 11 11 DIV BYTE [1111] ; .6..
0419| F6 3E 11 11 IDIV BYTE [1111] ; .>..
041D| F7 06 22 22 56 34 TEST WORD [2222], 3456 ; ..""
0423| F7 08 22 22 --- WORD [2222] ; ..""
0427| F7 16 22 22 NOT WORD [2222] ; ..""
042B| F7 1E 22 22 NEG WORD [2222] ; ..""
042F| F7 26 22 22 MUL WORD [2222] ; .&""
0433| F7 2E 22 22 IMUL WORD [2222] ; ..""
0437| F7 36 22 22 DIV WORD [2222] ; .6""
043B| F7 3E 22 22 IDIV WORD [2222] ; .>""
043F| F8 CLC ; .
0440| F9 STC ; .
0441| FA CLI ; .
0442| FB STI ; .
0443| FC CLD ; .
0444| FD STD ; .
0445| FE 06 11 11 INC BYTE [1111] ; ....
0449| FE 0E 11 11 DEC BYTE [1111] ; ....
044D| FE 10 11 11 --- BYTE [1111] ; ....
0451| FE 18 11 11 --- BYTE [1111] ; ....
0455| FE 20 11 11 --- BYTE [1111] ; . ..
0459| FE 28 11 11 --- BYTE [1111] ; .(..
045D| FE 30 11 11 --- BYTE [1111] ; .0..
0461| FE 38 11 11 --- BYTE [1111] ; .8..
0465| FF 06 22 22 INC WORD [2222] ; ..""
0469| FF 0E 22 22 DEC WORD [2222] ; ..""
046D| FF D0 22 22 CALL WORD [2222] ; ..""
0471| FF 16 22 22 CALL WORD [2222] ; ..""
0475| FF E0 22 22 JMP WORD [2222] ; ..""
0479| FF 26 22 22 JMP WORD [2222] ; .&""
047D| FF 36 22 22 PUSH WORD [2222] ; .6""
0481| FF 38 22 22 --- WORD [2222] ; .8""


EOF


Axel Berger

unread,
Sep 17, 2007, 9:15:00 AM9/17/07
to
*roche182* wrote on Mon, 07-09-17 10:54:

>(I never had so much trouble understanding the opcodes of a
>computer. Intel really goofed mightily when they designed the 8086
>CPU instruction set.)

Intel x86 was never known to be particularly good but still:

How many processors do you know, really? There is one in which you are
incredibly experienced for decades and one that is new to you, while
you are, like most here, rather elderly now and don't find learning new
stuff as easy as it used to be (or as you remeber it now, which need
not be the same thing).

I notice much the same problems myself.

roch...@laposte.net

unread,
Sep 18, 2007, 4:47:24 AM9/18/07
to
- "The 8086 CPU Instruction Set: The FF Opcode"

Ok. We have tested all the opcodes of the 8086 CPU instruction
set. The
biggest problem happens with the last one: FF. So, let us spend one
article
discussing it specifically.

Back home, I re-(etc.)read everything that I have on the 8086. Could
not find
anything special about the FF opcode.

The author of the 8086 CPU, thinking in binary, lists the
"Unconditional
Transfer Instructions":

+-----------------+ +----------+ +-----------+
| 1 1 1 0 1 0 0 1 | | diff-low | | diff-high |
+-----------------+ +----------+ +-----------+
JMP: jump direct intrasegment

+-----------------+ +------+
| 1 1 1 0 1 0 1 1 | | diff |
+-----------------+ +------+
JMP: jump direct intrasegment (short)

+-----------------+ +-----+-------+-----+
| 1 1 1 1 1 1 1 1 | | mod | 1 0 0 | r/m |
+-----------------+ +-----+-------+-----+
JMP: jump indirect intrasegment

+-----------------+ +---------+ +----------+ +---------+
+----------+
| 1 1 1 0 1 0 1 0 | | off-low | | off-high | | seg-low | |
seg-high |
+-----------------+ +---------+ +----------+ +---------+
+----------+
JMP: jump direct intersegment

+-----------------+ +-----+-------+-----+
| 1 1 1 1 1 1 1 1 | | mod | 1 0 1 | r/m |
+-----------------+ +-----+-------+-----+
JMP: jump indirect intersegment

+-----------------+ +----------+ +-----------+
| 1 1 1 0 1 0 0 0 | | diff-low | | diff-high |
+-----------------+ +----------+ +-----------+
CALL: call direct intrasegment

+-----------------+ +-----+-------+-----+
| 1 1 1 1 1 1 1 1 | | mod | 0 1 0 | r/m |
+-----------------+ +-----+-------+-----+
CALL: call indirect intrasegment

+-----------------+ +---------+ +----------+ +---------+
+----------+
| 1 0 0 1 1 0 1 0 | | off-low | | off-high | | seg-low | |
seg-high |
+-----------------+ +---------+ +----------+ +---------+
+----------+
CALL: call direct intersegment

+-----------------+ +-----+-------+-----+
| 1 1 1 1 1 1 1 1 | | mod | 0 1 1 | r/m |
+-----------------+ +-----+-------+-----+
CALL: call indirect intersegment

+-----------------+
| 1 1 0 0 0 0 1 1 |
+-----------------+
RET: return intrasegment

+-----------------+ +----------+ +-----------+
| 1 1 0 0 0 0 1 0 | | data-low | | data-high |
+-----------------+ +----------+ +-----------+
RET: return intrasegment, adding immediate to SP

+-----------------+
| 1 1 0 0 1 0 1 1 |
+-----------------+
RET: return intersegment

+-----------------+ +----------+ +-----------+
| 1 1 0 0 1 0 1 0 | | data-low | | data-high |
+-----------------+ +----------+ +-----------+
RET: return intersegment, adding immediate to SP

Figure 3.40 Formats of unconditional jump, calls, and returns

Today, we are just interested in the CALL and JMP instructions.
Since I
usually think in hexadecimal when programming (remember, I used to
program IBM
Mainframes, for which IBM created the hexadecimal notation for
its S/360
line. Before, everybody was using octal.) (As some old Unix freaks
still do.),
I have added them in front of the "boxes":

+-----------------+ +----------+ +-----------+
E9 | 1 1 1 0 1 0 0 1 | | diff-low | | diff-high |
+-----------------+ +----------+ +-----------+
JMP: jump direct intrasegment

+-----------------+ +------+
EB | 1 1 1 0 1 0 1 1 | | diff |
+-----------------+ +------+
JMP: jump direct intrasegment (short)

+-----------------+ +-----+-------+-----+
FF | 1 1 1 1 1 1 1 1 | | mod | 1 0 0 | r/m |
+-----------------+ +-----+-------+-----+
JMP: jump indirect intrasegment

+-----------------+ +---------+ +----------+ +---------+
+----------+
EA | 1 1 1 0 1 0 1 0 | | off-low | | off-high | | seg-low | |
seg-high |
+-----------------+ +---------+ +----------+ +---------+
+----------+
JMP: jump direct intersegment

+-----------------+ +-----+-------+-----+
FF | 1 1 1 1 1 1 1 1 | | mod | 1 0 1 | r/m |
+-----------------+ +-----+-------+-----+
JMP: jump indirect intersegment

+-----------------+ +----------+ +-----------+
E8 | 1 1 1 0 1 0 0 0 | | diff-low | | diff-high |
+-----------------+ +----------+ +-----------+
CALL: call direct intrasegment

+-----------------+ +-----+-------+-----+
FF | 1 1 1 1 1 1 1 1 | | mod | 0 1 0 | r/m |
+-----------------+ +-----+-------+-----+
CALL: call indirect intrasegment

+-----------------+ +---------+ +----------+ +---------+
+----------+
9A | 1 0 0 1 1 0 1 0 | | off-low | | off-high | | seg-low | |
seg-high |
+-----------------+ +---------+ +----------+ +---------+
+----------+
CALL: call direct intersegment

+-----------------+ +-----+-------+-----+
FF | 1 1 1 1 1 1 1 1 | | mod | 0 1 1 | r/m |
+-----------------+ +-----+-------+-----+
CALL: call indirect intersegment

So, since today we are only interested in the FF opcodes, let us
concentrate
upon them:

+-----------------+ +-----+-------+-----+
FF | 1 1 1 1 1 1 1 1 | | mod | 1 0 0 | r/m |
+-----------------+ +-----+-------+-----+
JMP: jump indirect intrasegment

+-----------------+ +-----+-------+-----+
FF | 1 1 1 1 1 1 1 1 | | mod | 1 0 1 | r/m |
+-----------------+ +-----+-------+-----+
JMP: jump indirect intersegment

+-----------------+ +-----+-------+-----+
FF | 1 1 1 1 1 1 1 1 | | mod | 0 1 0 | r/m |
+-----------------+ +-----+-------+-----+
CALL: call indirect intrasegment

+-----------------+ +-----+-------+-----+
FF | 1 1 1 1 1 1 1 1 | | mod | 0 1 1 | r/m |
+-----------------+ +-----+-------+-----+
CALL: call indirect intersegment

First thing to notice: according to its author, those opcodes are
2 bytes
long, while the Intel doc says that they are 4 bytes long...

Second, the un-named field between the MOD and R/M fields
(sometimes named
"REG(ister)", sometimes "OPC(ode)". Visibly, Intel could not decide to
call it
"R/O" for "Register/Opcode"... Since I am too kind, I will solve
Intel's
problem. The problem was that Intel did not remember that this field
is not
inside the opcode, BUT INSIDE THE SECONDARY OPCODE... And one
acronym for
Secondary Opcode could be "SO", in which case R/SO could be shortened
to RSO
(or "R/S"). That it to say: another 3-letter acronym, fitting nicely
in tables
and programs dealing with the 8086 CPU instruction set...) has
the values
corresponding to the one in the "Grp 2" "Secondary Opcode Space"
table. No
problem, here.

Third, all of them have "indirect" in their description.

Time to do a little programming. I created a file to test what
would SID-86
says. The MOD field, as you should know by now, only has 2 bits, so
4 lines
will contain all its possible values. The R/M (Register/Memory)
field has 3
bits, so 8 lines will contain all its possibles values. Total: 4 *
8 = 32
lines will be enough! (When you are lucky enough to have so few
cases to
check, it woud be totally crazy not to test them systematically.) For
safety,
each line will be padded to 4 bytes with NOPs.

I first typed a line, then used WordStar to copy it 8 times, then
changed all
the R/M fields, then used WS4 to copy another 3 times the result,
then used
WS4 to patch all the MOD fields. Ha, the joy of word-processing!

Back to SID-86. Here is what it displays:

18E8:0080 CALL [BX+SI]
18E8:0082 NOP
18E8:0083 NOP
18E8:0084 CALL [BX+DI]
18E8:0086 NOP
18E8:0087 NOP
18E8:0088 CALL [BP+SI]
18E8:008A NOP
18E8:008B NOP
18E8:008C CALL [BP+DI]
18E8:008E NOP
18E8:008F NOP
18E8:0090 CALL [SI]
18E8:0092 NOP
18E8:0093 NOP
18E8:0094 CALL [DI]
18E8:0096 NOP
18E8:0097 NOP
18E8:0098 CALL [9090]
18E8:009C CALL [BX]
18E8:009E NOP
18E8:009F NOP
18E8:00A0 CALLF [BX+SI]
18E8:00A2 NOP
18E8:00A3 NOP
18E8:00A4 CALLF [BX+DI]
18E8:00A6 NOP
18E8:00A7 NOP
18E8:00A8 CALLF [BP+SI]
18E8:00AA NOP
18E8:00AB NOP
18E8:00AC CALLF [BP+DI]
18E8:00AE NOP
18E8:00AF NOP
18E8:00B0 CALLF [SI]
18E8:00B2 NOP
18E8:00B3 NOP
18E8:00B4 CALLF [DI]
18E8:00B6 NOP
18E8:00B7 NOP
18E8:00B8 CALLF [9090]
18E8:00BC CALLF [BX]
18E8:00BE NOP
18E8:00BF NOP
18E8:00C0 JMP [BX+SI]
18E8:00C2 NOP
18E8:00C3 NOP
18E8:00C4 JMP [BX+DI]
18E8:00C6 NOP
18E8:00C7 NOP
18E8:00C8 JMP [BP+SI]
18E8:00CA NOP
18E8:00CB NOP
18E8:00CC JMP [BP+DI]
18E8:00CE NOP
18E8:00CF NOP
18E8:00D0 JMP [SI]
18E8:00D2 NOP
18E8:00D3 NOP
18E8:00D4 JMP [DI]
18E8:00D6 NOP
18E8:00D7 NOP
18E8:00D8 JMP [9090]
18E8:00DC JMP [BX]
18E8:00DE NOP
18E8:00DF NOP
18E8:00E0 JMPF [BX+SI]
18E8:00E2 NOP
18E8:00E3 NOP
18E8:00E4 JMPF [BX+DI]
18E8:00E6 NOP
18E8:00E7 NOP
18E8:00E8 JMPF [BP+SI]
18E8:00EA NOP
18E8:00EB NOP
18E8:00EC JMPF [BP+DI]
18E8:00EE NOP
18E8:00EF NOP
18E8:00F0 JMPF [SI]
18E8:00F2 NOP
18E8:00F3 NOP
18E8:00F4 JMPF [DI]
18E8:00F6 NOP
18E8:00F7 NOP
18E8:00F8 JMPF [9090]
18E8:00FC JMPF [BX]
18E8:00FE NOP
18E8:00FF NOP
18E8:0100 ADD [BX+SI],AL

(The last ADD is a 00h byte, as you probably know. For some unknown
reason,
the newbies who designed the 8086 CPU decided not to use 00h for NOP.)

Removing the NOPs, we get (thanks to WS4 "column mode"):

18E8:0080 FF109090 CALL [BX+SI]
18E8:0084 FF119090 CALL [BX+DI]
18E8:0088 FF129090 CALL [BP+SI]
18E8:008C FF139090 CALL [BP+DI]
18E8:0090 FF149090 CALL [SI]
18E8:0094 FF159090 CALL [DI]
18E8:0098 FF169090 CALL [9090]
18E8:009C FF179090 CALL [BX]

18E8:00A0 FF189090 CALLF [BX+SI]
18E8:00A4 FF199090 CALLF [BX+DI]
18E8:00A8 FF1A9090 CALLF [BP+SI]
18E8:00AC FF1B9090 CALLF [BP+DI]
18E8:00B0 FF1C9090 CALLF [SI]
18E8:00B4 FF1D9090 CALLF [DI]
18E8:00B8 FF1E9090 CALLF [9090]
18E8:00BC FF1F9090 CALLF [BX]

18E8:00C0 FF209090 JMP [BX+SI]
18E8:00C4 FF219090 JMP [BX+DI]
18E8:00C8 FF229090 JMP [BP+SI]
18E8:00CC FF239090 JMP [BP+DI]
18E8:00D0 FF249090 JMP [SI]
18E8:00D4 FF259090 JMP [DI]
18E8:00D8 FF269090 JMP [9090]
18E8:00DC FF279090 JMP [BX]

18E8:00E0 FF289090 JMPF [BX+SI]
18E8:00E4 FF299090 JMPF [BX+DI]
18E8:00E8 FF2A9090 JMPF [BP+SI]
18E8:00EC FF2B9090 JMPF [BP+DI]
18E8:00F0 FF2C9090 JMPF [SI]
18E8:00F4 FF2D9090 JMPF [DI]
18E8:00F8 FF2E9090 JMPF [9090]
18E8:00FC FF2F9090 JMPF [BX]

First thing to notice: following all the available 8086
documentation, SID-86
displays CALLF and JMPF for "indirect intersegment" opcodes. At
least, there
is no contradiction with the name of the mnemonics. The problem is
that the
official Intel doc for Grp 2 is:

RSO | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111
-----+-----+-----+-----+-----+-----+-----+-----+-----
Grp2 | INC | DEC | CALL| CALL| JMP | JMP | PUSH| ---
| | | id | L,id| id | L,id| |
-----+-----+-----+-----+-----+-----+-----+-----+-----

However, upon reading the little characters, we learn that
"id" means
"indirect", and "L" means "intersegment". In Digital Research
syntax, that
means CALL, CALLF, JMP, and JMPF. One thing to patch in my program.

Second, all opcodes are 2 bytes long, except the 7th line of each
group, which
is 4 bytes long. Now, the problem is that, as explained, each group
start with
one of the 4 values possible for the MOD field and, according to the
official
Intel doc, only MOD=00 (that is to say: the first group) commands the
8086 CPU
to use "Memory Mode". Here, we have four times the MOD=00 column, as
found in
Table 4-10, "R/M Field Encoding". This is obviously what Intel had
in mind
when talking about "indirect" instructions.

Searching for a "coding sample", I had the idea to have a look to
my sample
file. For this discussion, I erased everything not CALL or JMP.

022C 9A00000000 R callf label

035C E8A1FC 0000 call label
035F E99EFC 0000 jmp label
0362 EA00000000 R jmpf label
0367 EBDF 0348 jmps short_label2

03ED FFD02222 call ax! db 22h, 22h
03F1 FF162222 R call mem_16
03F5 FFE02222 jmp ax! db 22h, 22h
03F9 FF262222 R jmp mem_16

There is no obvious problem with the first CALLs and JMPs, so let us
turn our
attention to the last 4 lines.

According to "The 8086 Family User's Manual", Page 4-35,

RSO=2 CALL reg16/mem16
RSO=3 CALL FAR mem16
RSO=4 JMP reg16/mem16
RSO=5 JMP FAR mem16

Now, what does it means by "reg16"? When writing my sample file, I
used "AX"
since, for me, it is a 16-bit register. However, according to
SID-86, it is
more appropriately designed as the various indirect addressing modes
found in
the MOD=00 column of Table 4-10, "R/M Field Encoding".

For instance,

03ED FFD02222 call ax! db 22h, 22h

happens to be totally outside the "legal" values for the RSO (shown to
be 10h
to 2Fh by SID-86). So, is it another bug inside ASM-86?

However, the second line from my sample file,

03F1 FF162222 R call mem_16

clearly fit inside

18E8:0094 FF159090 CALL [DI]
18E8:0098 FF169090 CALL [9090]
18E8:009C FF179090 CALL [BX]

so is a leg... Wait! How is it possible that ASM-86 generated this
value?

Re-examining the above portion, we notice that

035C E8A1FC 0000 call label

03F1 FF162222 R call mem_16

That is to say: in the first case, ASM-86 generates an E8 opcode,
and an FF
opcode in the second! How is it possible?

Using WS4, I jumped to the place where "label" and "mem_16" are
defined:

;--------------------------------
CSEG $
;--------------------------------
label:

;--------------------------------
DSEG
;--------------------------------
ORG 2222h
mem_16 dw 6789h

Haaaaa! ASM-86 generate a different call opcode whether the called
label is
defined in a Code Segment (E8) or inside a Data Segment (FF 16)! That
was the
trick! That is what the Intel doc calls "mem16"... (In truth, the
other label
is named "near_label". Since ASM-86 does not use NEAR blah-
blah, I had
disregarded this... How tricky this instruction set is! There are
so many
cases that the mnemonics are not able to cover all of them (at
least 17
MOVs!), hence the assembler is obliged to keep track of all the
details of the
variables, just to generate the appropriate code.)

Ok, so this explains clearly what a "CALLF mem_16"
instruction should
generate. For the "CALL reg16", I will follow SID-86. So, 2 things
to check
inside ASM-86.

(For the JMP instructions, the 8086 CPU instruction set being so
regular, I
have no doubt that it follows the CALL FF opcodes. Or, this
instruction set
would be really damned!)

So, The FF opcode should be decoded like this:

FF MOD 000 R/M INC WORD [2222]
FF MOD 001 R/M DEC WORD [2222]
FF MOD 010 R/M CALL reg16
FF MOD 011 R/M CALLF mem16
FF MOD 100 R/M JMP reg16
FF MOD 101 R/M JMPF mem16
FF MOD 110 R/M PUSH [2222]
FF MOD 111 R/M --- [2222]

That is to say: 4 cases are 2 bytes long (but 4 bytes long when R/
M=110), and
4 cases are 4 bytes long... This opcode is really not easy to decode!
I will
have to write a subroutine specially for it.

Haaaaa! After a few hours, here is what I get:

0080| FF 06 22 22 INC WORD [2222] ; ..""
0084| FF 0E 22 22 DEC WORD [2222] ; ..""
0088| FF 10 CALL [BX+SI] ; ..
008A| FF 11 CALL [BX+DI] ; ..
008C| FF 12 CALL [BP+SI] ; ..
008E| FF 13 CALL [BP+DI] ; ..
0090| FF 14 CALL [SI] ; ..
0092| FF 15 CALL [DI] ; ..
0094| FF 16 22 22 CALL [2222] ; ..""
0098| FF 17 CALL [BX] ; ..
009A| FF 18 CALLF [BX+SI] ; ..
009C| FF 19 CALLF [BX+DI] ; ..
009E| FF 1A CALLF [BP+SI] ; ..
00A0| FF 1B CALLF [BP+DI] ; ..
00A2| FF 1C CALLF [SI] ; ..
00A4| FF 1D CALLF [DI] ; ..
00A6| FF 1E 22 22 CALLF [2222] ; ..""
00AA| FF 1F CALLF [BX] ; ..
00AC| FF 20 JMP [BX+SI] ; .
00AE| FF 21 JMP [BX+DI] ; .!
00B0| FF 22 JMP [BP+SI] ; ."
00B2| FF 23 JMP [BP+DI] ; .#
00B4| FF 24 JMP [SI] ; .$
00B6| FF 25 JMP [DI] ; .%
00B8| FF 26 22 22 JMP [2222] ; .&""
00BC| FF 27 JMP [BX] ; .'
00BE| FF 28 JMPF [BX+SI] ; .(
00C0| FF 29 JMPF [BX+DI] ; .)
00C2| FF 2A JMPF [BP+SI] ; .*
00C4| FF 2B JMPF [BP+DI] ; .+
00C6| FF 2C JMPF [SI] ; .,
00C8| FF 2D JMPF [DI] ; .-
00CA| FF 2E 22 22 JMPF [2222] ; ..""
00CE| FF 2F JMPF [BX] ; ./
00D0| FF 36 22 22 PUSH [2222] ; .6""
00D4| FF 38 22 22 --- [2222] ; .8""

Trivial, isn't it?


Yours Sincerely,
Mr Emmanuel Roche


EOF


Herb Johnson

unread,
Sep 18, 2007, 12:14:15 PM9/18/07
to
On Sep 13, 9:29 am, roche...@laposte.net wrote:

> My first feeling was to remove the "signed byte" distinction, and to
> replace it with "byte".
>
> But, then, of course, the sign bit would not be "extended"...
>
> Damned! All that for 5 bytes out of 40 K! As I said, I could not find
> any instance of a "signed byte" anywhere else in the Intel doc. (It
> would be funny to ask this question to some "gurus"...)
>
> Opinions welcomed.
>
> Yours Sincerely,
> Mr Emmanuel Roche

Here's an opinion: Roche is not acting in good faith, he's posting to
show off. Why support that with a reply? If you read this and already
agree with me, you don't need to read further. If you disagree, read
on, I'll make the case. - Herb Johnson

Actually, Roche did NOT welcome an opinion on this subject. Namely, MY
opinion which I sent him privately. I read the manual in question
myself, I have a copy. After some hours of work (it's been years since
I programmed the 8086) I sent a number of detailed notes to explain
where this instruction mode is described IN THAT MANUAL. His brief
response: "I don't think you should try to be a programmer; stick to
your S-100 work".

While I don't claim to be a programming "guru", I think that a BSEE
degree from the 70's and years of professionally programming Intel
processors in that period, qualify me as being able to AT LEAST read
the same Intel manual that Roche has so much trouble reading.

My reply to him, showed him places in that Intel "8086 Family Guide",
where the signed byte instruction is discussed. Not at length and not
transparently, but it's there. Many of his issues about the manual are
about a pair of SUMMARY tables ON ONE PAGE. They are only that, a
summary, of about 18 pages of two instruction charts which are more
complete, supported further by several pages of text and other small
tables. While I no longer follow his posts in detail, I guess he is
rediscovering that text over time.

The fact that Intel's manuals of the 70's are not easy reading is well
known. As for the difficulties of dealing with BYTE vs WORD
references, I had simply forgotten all those irregularities until I
reviewed the manual. But that's why manuals are written, to be read a
few times, not once; and if one manual is insufficient, one reads
another. This is called a "learning curve"; watching Roche's is to me
rather tedious, seperate from his insult to me.

I also suggested to Roche that he use a debugger to check these op
codes. Then he did, no thanks given. I did not think it was necessary
to explain HOW to use it. Mostly he's used it as an assembler, or to
poke a few op codes in, or a list of op codes, to see how they
assembled. He's not used it to actually EXECUTE some code, to see what
operands actually make it into registers. I did not think I had to
explain that - "here's how you run code". But I simply can't keep
track of whether he's actually TRIED to poke in, in hex, an
appropriate ADD instruction with a negative byte-sized value! He rants
about this instruction feature, but doesn't really exercise it fully.

And, even when assembling or disassembing, he simply MISCOUNTS the
number of bytes used! Or posts partial results, so I had to guess that
byte count. When that's your argument, miscounting is just sloppy
work, and not showing the hex with the assembly listing is poor work.
I have no time to correct flawed work, does anyone else?

In short, Roche's posts are inaccurate, incomplete, and are only
impressive from the sheer volume he is able to generate. He's on a
learning curve - why does the world have to watch it? As for content
posted: throw enough mud, something sticks - there is some fallout
worth some discussion by those who actually KNOW 8086 operation. Those
who reply have informative things to say. But why support THIS means
of generating such discussion?

I am reluctantly posting this as I don't care to post personal
comments about others. But the alternatives are either to say nothing
and let the thread die - which probably won't happen for weeks. Or, to
post corrections to Roche's posts - but at his posting rate I simply
lack time to do so. Also, it "feeds" his desire to post more. Finally,
as he's insulted and offended me personally AND professionally, I have
no inclination to reply to him.

And all THAT is why I decided to post this warning. In my opinion,
this thread is not about someone who is trying to learn 8086 assembly
language or processor operations, and asking for help. It's about
someone who sees a way to use other's good intentions to run a long
LONG thread for his own VANITY. That defines a TROLL.

If you don't agree, I won't argue about it - I'm no troll looking for
a fight. But if Roche can post TWENTY ONE TIMES in three weeks on a
vanity thread, maybe I'm allowed one post in protest.

Herb Johnson

Herbert R. Johnson, New Jersey USA
http://www.retrotechnology.com/herbs_stuff/ web site
http://www.retrotechnology.net/herbs_stuff/ domain mirror
my email address: hjohnson AAT retrotechnology DOTT com
if no reply, try in a few days: herbjohnson ATT comcast DOTT net
"Herb's Stuff": old Mac, SGI, 8-inch floppy drives
S-100 IMSAI Altair computers, docs, by "Dr. S-100"

roch...@laposte.net

unread,
Sep 19, 2007, 3:36:35 AM9/19/07
to
Hello, Herb!

> (...)Finally,


> as he's insulted and offended me personally AND professionally, I have
> no inclination to reply to him.

I am terribly sorry to learn indirectly, publicly via the comp.os.cpm
Newsgroup, that you felt insulted by my one-line reply. You had sent
me 3 long messages about the difference between the 82 and 83 opcodes,
and my last message (at that time) listed the hex opcodes, along with
an explanation of them. (The problem was not what was written in the
Intel doc, but how to generate them with ASM-86).

> And all THAT is why I decided to post this warning. In my opinion,
> this thread is not about someone who is trying to learn 8086 assembly
> language or processor operations, and asking for help. It's about
> someone who sees a way to use other's good intentions to run a long
> LONG thread for his own VANITY. That defines a TROLL.

I don't know if I am trying to learn 8086 assembly language. All I
know is that I have disassembled ASM-86 Version 1.1, am now checking
all the "legal" 8086 opcodes, and will (hopefully) disassemble SID-86,
so as to have a complete 8086 assembly language development system
running under CP/M-86 Plus. Once it will be done, I will see if I make
a 386 version (only the tables inside ASM-86 would need to be updated,
since it is a table-driven assembler).

I am sorry if you felt that they were long posts, but I made them
along the way, as I discovered bugs. The last listings (all the
opcodes, then only the FF opcodes) are now my basis for further work.
I have now understood the purposes of some groupings of instructions,
and discovered some "secondary opcodes" used only once. I guess that
they were probably used in later Intel processors. I would need a
table listing all the additions to the 8086 instruction set (mnemonics
and opcodes) for each newer CPUs. If someone knows if such a table
exists, this would help me fill the unused secondary opcodes, thus
helping me to make a 386 assembler running under CP/M (-86 Plus).

Message has been deleted

glen herrmannsfeldt

unread,
Sep 19, 2007, 2:58:22 PM9/19/07
to
Herb Johnson wrote:

(snip)

> Here's an opinion: Roche is not acting in good faith, he's posting to
> show off. Why support that with a reply? If you read this and already
> agree with me, you don't need to read further. If you disagree, read
> on, I'll make the case. - Herb Johnson

That is possible.

It might also be true for 90% of the posts to newsgroups.

It does seem that he really wants the answer, though it might
be that he could use a different posting style. Also, that he
is a little slower at understanding than some of us.

I don't know how much demand there is for a good 8086 disassembler,
for example. (Note that the DOS DEBUG command has one.)

-- glen

roch...@laposte.net

unread,
Sep 22, 2007, 8:18:35 AM9/22/07
to
Since nobody answered my question, I had the idea to have a look to
Wikipedia.

Somewhere there (I have been unable to refind it, to note the
reference), I finally found the following:

'''Added with [[80186]]/[[80188]]'''

BOUND, ENTER, INS, LEAVE, OUTS, POPA, PUSHA

'''Added with [[80286]]'''

ARPL, CLTS, LAR, LGDT, LIDT, LLDT, LMSW,
[[LOADALL]], LSL, [[Load Task Register|LTR]]
, SGDT, SIDT, SLDT, SMSW, STR, VERR, VERW

'''Added with [[80386]]'''

BSF, BSR, BT, BTC, BTR, BTS, CDQ, CMPSD, CWDE,
INSD, IRETD, IRETDF, IRETF, JECXZ, LFS, LGS,
LSS, LODSD, LOOPD, LOOPED, LOOPNED, LOOPNZD,
LOOPZD, MOVSD, MOVSX, MOVZX, OUTSD, POPAD,
POPFD, PUSHAD, PUSHD, PUSHFD, SCASD, SETA,
SETAE, SETB, SETBE, SETC, SETE, SETG, SETGE,
SETL, SETLE, SETNA, SETNAE, SETNB, SETNBE,
SETNC, SETNE, SETNG, SETNGE, SETNL, SETNLE,
SETNO, SETNP, SETNS, SETNZ, SETO, SETP,
SETPE, SETPO, SETS, SETZ, SHLD, SHRD, STOSD

So, there seems to have been a big jump in the number of opcodes when
they switched to 32-bit mode.

Now that I have an idea of what to search for, I will

1) rewrite my LIST8086
2) write a LIST186
3) write a LIST286
4) check all the opcodes of ASM-86
5) add the 186 instructions
6) add the 286 instructions

This programme should keep me working for some time.

(I also need to disassemble SID-86.)

Only then will I decide if I update the tables to generate 80386
opcodes. At least, I know from the outset that it is possible. Just a
question of time and money (as usual).

0 new messages