Disassemble

I wrote a small function that dissembles the machine code instructions into mnemonics. The table has some examples:

Opcode Mnemonic
0xB561 POP W, DB[SP]
0x7845 MUL A,W
0x2043 LD A, *(IP)
0x7003 INC IP

Here is the code:

def disassemble(self, opcode):
    n3 = (opcode & 0xF000) >> 12
    n2 = (opcode & 0x0F00) >>  8
    n1 = (opcode & 0x00F0) >>  4
    n0 = (opcode & 0x000F) >>  0

    mnemonic = "?"

    # Special section
    if   opcode == 0x0000: mnemonic = "NOP"
    elif opcode == 0x0001: mnemonic = "HALT"
    elif opcode == 0x0002: mnemonic = "PYTHON"
    elif opcode == 0x0003: mnemonic = "SAVE"
    elif opcode == 0x0004: mnemonic = "LOAD"
    elif (n3 == 0x0 and n2 == 0x0 and n1 == 0x1):     # EMIT reg
      mnemonic = "EMIT " + regname[n0]
    # Data transfer
    elif (n3 == 0x1):                 # LDI reg, val
      val = (n1 << 4) + n0
      mnemonic = "LDI " + regname[n2] + ", " + str(val)
    elif (n3 == 0x2 and n2 == 0x0):           # LD reg0, *(reg1)
      mnemonic = "LD " + regname[n1] + ", *(" + regname[n0] + ")"
    elif (n3 == 0x2 and n2 == 0x1):           # LD reg0, reg1
      mnemonic = "LD " + regname[n1] + ", " + str(n0)
    # Arithmetic
    elif (n3 == 0x7 and n2 == 0x0 and n1 == 0x0):     # INC reg
      mnemonic = "INC " + regname[n0]
    elif (n3 == 0x7 and n2 == 0x8):           # MUL reg0, reg1
      mnemonic = "MUL " + regname[n1] + ", " + regname[n0]
    # Combinations
    elif (n3 == 0x8):                   # PUSH reg0[reg1], reg2
      mnemonic = "PUSH " + regname[n2] + "[" + regname[n1] + "], " + regname[n0]
    elif (n3 == 0x9):                   # PUSH reg0[reg1], *(reg2)
      mnemonic = "PUSH " + regname[n2] + "[" + regname[n1] + "], *(" + regname[n0] + ")"
    elif (n3 == 0xB):                   # POP reg0, reg1[reg2]
      mnemonic = "POP " + regname[n2] + ", " + regname[n1] + "[" + regname[n0] + "]"
    else:
      mnemonix = hex(opcode)

    return mnemonic

Is there a way to write this more elegantly?