Intel wrote the specification of the 8086 assembly language, a derivative of the earlier 8080, 8008 and 4004 processors. As such, the assembler they wrote followed their own syntax precisely. However, this assembler wasn't used very widely.
Intel defined their opcodes to have either zero, one or two operands. The two-operand instructions were defined to be in the dest
, source
order, which was different from other assemblers at the time. But some instructions used implicit registers as operands - you just had to know what they were. Intel also used the concept of "prefix" opcodes - one opcode would affect the next instruction.
; Zero operand examples
NOP ; No parameters
CBW ; Convert byte in AL into word in AX
MOVSB ; Move byte pointed to by DS:SI to byte pointed to by ES:DI
; SI and DI are incremented or decremented according to D bit
; Prefix examples
REP MOVSB ; Move number of bytes in CX from DS:SI to ES:DI
; SI and DI are incremented or decremented according to D bit
; One operand examples
NOT AX ; Replace AX with its one's complement
MUL CX ; Multiply AX by CX and put 32-bit result in DX:AX
; Two operand examples
MOV AL, [0x1234] ; Copy the contents of memory location DS:0x1234 into AL register
Intel also broke a convention used by other assemblers: for each opcode, a different mnemonic was invented. This required subtly- or distinctly-different names for similar operations: e.g. LDM
for "Load from Memory" and LDI
for "Load Immediate". Intel used the one mnemonic MOV
- and expected the assembler to work out which opcode to use from context. That caused many pitfalls and errors for programmers in the future when the assembler couldn't intuit what the programmer actually wanted...