/opcode.pas
unit Opcode;
interface

type
Mnemonic = (
    mADD, mADDB, mADDBI, mADDI,
    mAND, mANDB, mANDBI, mANDI,
    mCALL,
    mCLR,
    mDEC, mDECB,
    mHLT,
    mINC, mINCB,
    mJBT, mJMCE, mJMCNE, mJMP, mJNBT, mJNZ, mJNZB, mJZ, mJZB,
    mLCALL,
    mLJBT, mLJMCE, mLJMCNE, mLJMP, mLJNBT, mLJNZ, mLJNZB, mLJZ, mLJZB,
    mLPD, mLPDI,
    mMOV, mMOVB, mMOVBI, mMOVI, mMOVP,
    mNOP,
    mNOT, mNOTB,
    mOR, mORB, mORBI, mORI,
    mSETB,
    mSINTR,
    mTSL,
    mWID,
    mXFER,
    mInvalid
);

Directive = (
    dEQU,
    dDB, dDW, dDD, dDS,
    dSTRUC,
    dORG,
    dEVEN,
    dNAME,
    dSEGMENT,
    dPUBLIC,
    dEXTRN,
    dENDS,
    dEND
);

EncRRR = (rGA, rGB, rGC, rBC, rTP, rIX, rCC, rMC);
EncBBB = (Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7);
EncPPP = (pGA, pGB, pGC, pReserved, pTP);
EncWB = (
    wReserved, { Instruction has no immediate/displacement data }
    wOne,      { One byte of immediate/displacement data }
    wTwo,      { Two bytes of immediate/displacement data }
    wTSL,      { Special case for TSL: one byte immediate and one byte displacement }
    wLocation  { One or two bytes displacement dependent on the distance to the target }
);
EncAA = (Base, BaseOffset, BaseIndex, BaseIndexIncrement);
EncMM = (mGA, mGB, mGC, mPP);
EncWidth = (widByte, widWord);

OperandType = (OpUnknown, OpRegister, OpPointer, OpImmediate, OpLocation,
               OpMemory, OpBit, OpWidth, OpAbsent);
OperandSet = set of OperandType;
Operand = record
    case Kind: OperandType of
        OpUnknown: ();
        OpRegister: (reg: EncRRR);
        OpPointer: (preg: EncPPP);
        OpImmediate: (immed: Word);
        OpLocation: (loc: Word);
        OpMemory: (
            aa: EncAA;
            mm: EncMM;
            offset: Word;
        );
        OpBit: (bit: EncBBB);
        OpWidth: (width: EncWidth);
end;

InstructionRBP = (
    rbpReg,    { RbP Encodes a register (RRR) }
    rbpBit,    { RbP Encodes a bit position (bbb) }
    rbpPtrReg, { RbP encodes a pointer register (PPP) }
    rbpNone,   { RbP encodes nothing (0b000) }
    rbpHlt,    { RbP encodes 0b001 }
    rbpSintr,  { RbP encodes 0b010 }
    rbpJmp,    { RbP encodes 0b100 }
    rbpWid,    { RbP encodes logical widths }
    rbpXfer    { RbP encodes 0b011 }
);
{ |        low order byte         |        high order byte        | }
{ | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | }
{ |   R/b/P   |  W B  |  A A  | W |        OPCODE         |  MM   | }
{                                                                   }
{ R/b/P = Register, Bit, or Pointer/Register Select                 }
{     RRR         bbb            PPP                                }
{     000 - GA    000 - bit 0    000 - GA                           }
{     001 - GB    001 - bit 1    001 - GB                           }
{     010 - GC    010 - bit 2    010 - GC                           }
{     011 - BC    011 - bit 3    100 - TP                           }
{     100 - TP    100 - bit 4                                       }
{     101 - IX    101 - bit 5                                       }
{     110 - CC    110 - bit 6                                       }
{     111 - MC    111 - bit 7                                       }
{                                                                   }
{ WB = Number of immediate/displacement value bytes  (EncWB)        }
{     00 - Reserved              (wReserved)                        }
{     01 - 1 byte                (wOne)                             }
{     10 - 2 bytes (word)        (wTwo)                             }
{     11 - TSL instruction only  (wTSL)                             }
{                                                                   }
{ AA = Memory Address Mode                                          }
{     00 - Base address only                                        }
{     01 - Base address + 8 bit offset                              }
{     10 - Base address + index register                            }
{     11 - Base address + index register, post-increment            }
{                                                                   }
{ W = Memory Data Width                                             }
{     0 - 1 byte  (widByte)                                         }
{     1 - 2 bytes (widWord)                                         }
{                                                                   }
{ OPCODE = Opcode, see below                                        }
{                                                                   }
{ MM = Base Memory Address Select                                   }
{     00 - GA                                                       }
{     01 - GB                                                       }
{     10 - GC                                                       }
{     11 - PP                                                       }
InstructionEncoding = record
    { these parts are matched against }
    m: Mnemonic;
    o1: OperandType;
    o2: OperandType;
    o3: OperandType;
    { these parts are encoded when the above fields match }
    op: Byte;  { pre-shifted into the high 6-bits }
    w: EncWidth;
    wb: EncWB;
    rbp: InstructionRBP;
end;
PInstructionEncoding = ^InstructionEncoding;

const IEnc: array[0..80] of InstructionEncoding = (
    (m: mADD;   o1: OpRegister; o2: OpMemory;    o3: OpAbsent;
        op: $A0;   w: widWord;     wb: wReserved;   rbp: rbpReg),

    (m: mADD;   o1: OpMemory;   o2: OpRegister;  o3: OpAbsent;
        op: $D0;   w: widWord;     wb: wReserved;   rbp: rbpReg),

    (m: mADDB;  o1: OpRegister; o2: OpMemory;    o3: OpAbsent;
        op: $A0;   w: widWord;     wb: wReserved;   rbp: rbpReg),

    (m: mADDB;  o1: OpMemory;   o2: OpRegister;  o3: OpAbsent;
        op: $D0;   w: widWord;     wb: wReserved;   rbp: rbpReg), {error in width?}

    (m: mADDBI; o1: OpRegister; o2: OpImmediate; o3: OpAbsent;
        op: $20;   w: widByte;     wb: wOne;        rbp: rbpReg),

    (m: mADDBI; o1: OpMemory;   o2: OpImmediate; o3: OpAbsent;
        op: $C0;   w: widByte;     wb: wOne;        rbp: rbpNone),

    (m: mADDI;  o1: OpRegister; o2: OpImmediate; o3: OpAbsent;
        op: $20;   w: widWord;     wb: wTwo;        rbp: rbpReg),

    (m: mADDI;  o1: OpMemory;   o2: OpImmediate; o3: OpAbsent;
        op: $C0;   w: widWord;     wb: wTwo;        rbp: rbpNone),

    (m: mAND;   o1: OpRegister; o2: OpMemory;    o3: OpAbsent;
        op: $A8;   w: widWord;     wb: wReserved;   rbp: rbpReg),

    (m: mAND;   o1: OpMemory;   o2: OpRegister;  o3: OpAbsent;
        op: $D8;   w: widWord;     wb: wReserved;   rbp: rbpReg),

    (m: mANDB;  o1: OpRegister; o2: OpMemory;    o3: OpAbsent;
        op: $A8;   w: widByte;     wb: wReserved;   rbp: rbpReg),

    (m: mANDB;  o1: OpMemory;   o2: OpRegister;  o3: OpAbsent;
        op: $D8;   w: widWord;     wb: wReserved;   rbp: rbpReg),

    (m: mANDBI; o1: OpRegister; o2: OpImmediate; o3: OpAbsent;
        op: $28;   w: widByte;     wb: wOne;        rbp: rbpReg),

    (m: mANDBI; o1: OpMemory;   o2: OpImmediate; o3: OpAbsent;
        op: $C8;   w: widByte;     wb: wOne;        rbp: rbpNone),

    (m: mANDI;  o1: OpRegister; o2: OpImmediate; o3: OpAbsent;
        op: $28;   w: widWord;     wb: wTwo;        rbp: rbpReg),

    (m: mANDI;  o1: OpMemory;   o2: OpImmediate; o3: OpAbsent;
        op: $C8;   w: widWord;     wb: wTwo;        rbp: rbpNone),

    (m: mCALL;  o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $9C;   w: widWord;     wb: wLocation;   rbp: rbpJmp),

    (m: mCLR;   o1: OpMemory;   o2: OpBit;       o3: OpAbsent;
        op: $F8;   w: widByte;   wb: wReserved;   rbp: rbpBit),

    (m: mDEC;   o1: OpRegister; o2: OpAbsent;    o3: OpAbsent;
        op: $3C;   w: widByte;   wb: wReserved;   rbp: rbpReg),

    (m: mDEC;   o1: OpMemory;   o2: OpAbsent;    o3: OpAbsent;
        op: $EC;   w: widWord;   wb: wReserved;   rbp: rbpNone),

    (m: mDECB;  o1: OpMemory;   o2: OpAbsent;    o3: OpAbsent;
        op: $EC;   w: widByte;   wb: wReserved;   rbp: rbpNone),

    (m: mHLT;   o1: OpAbsent;   o2: OpAbsent;    o3: OpAbsent;
        op: $48;   w: widByte;     wb: wReserved;   rbp: rbpHlt),

    (m: mINC;   o1: OpRegister; o2: OpAbsent;    o3: OpAbsent;
        op: $38;   w: widByte;     wb: wReserved;   rbp: rbpReg),

    (m: mINC;   o1: OpMemory;   o2: OpAbsent;    o3: OpAbsent;
        op: $E8;   w: widWord;     wb: wReserved;   rbp: rbpNone),

    (m: mJBT;   o1: OpMemory;   o2: OpBit;       o3: OpLocation;
        op: $BC;   w: widByte;     wb: wLocation;   rbp: rbpBit),

    (m: mJMCE;  o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $B0;   w: widByte;     wb: wLocation;   rbp: rbpNone),

    (m: mJMCNE; o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $B4;   w: widByte;     wb: wLocation;   rbp: rbpNone),

    (m: mJMP;   o1: OpLocation; o2: OpAbsent;    o3: OpAbsent;
        op: $20;   w: widByte;     wb: wLocation;   rbp: rbpJmp), { AUG shows w changing for 8/16-bit displacement }

    (m: mJNBT;  o1: OpMemory;   o2: OpBit;       o3: OpLocation;
        op: $B8;   w: widByte;     wb: wLocation;   rbp: rbpBit),

    (m: mJNZ;   o1: OpRegister; o2: OpLocation;  o3: OpAbsent;
        op: $40;   w: widByte;     wb: wLocation;   rbp: rbpReg),

    (m: mJNZ;   o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $E0;   w: widWord;     wb: wLocation;   rbp: rbpNone),

    (m: mJNZB;  o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $E0;   w: widByte;     wb: wLocation;   rbp: rbpNone),

    (m: mJZ;    o1: OpRegister; o2: OpLocation;  o3: OpAbsent;
        op: $44;   w: widByte;     wb: wLocation;   rbp: rbpReg),

    (m: mJZ;    o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $E4;   w: widWord;     wb: wLocation;   rbp: rbpNone),

    (m: mJZB;   o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $E4;   w: widByte;     wb: wLocation;   rbp: rbpNone),

    (m: mLCALL; o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $9C;   w: widWord;     wb: wTwo;        rbp: rbpJmp),

    (m: mLJBT;  o1: OpMemory;   o2: OpBit;       o3: OpLocation;
        op: $BC;   w: widByte;     wb: wTwo;        rbp: rbpBit),

    (m: mLJMCE;  o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $B0;   w: widByte;     wb: wTwo;        rbp: rbpNone),

    (m: mLJMCNE; o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $B4;   w: widByte;     wb: wTwo;        rbp: rbpNone),

    (m: mLJMP;   o1: OpLocation; o2: OpAbsent;    o3: OpAbsent;
        op: $20;   w: widWord;     wb: wTwo;        rbp: rbpJmp), { AUG shows w changing for 8/16-bit displacement }

    (m: mLJNBT;  o1: OpMemory;   o2: OpBit;       o3: OpLocation;
        op: $B8;   w: widByte;     wb: wTwo;        rbp: rbpBit),

    (m: mLJNZ;   o1: OpRegister; o2: OpLocation;  o3: OpAbsent;
        op: $40;   w: widByte;     wb: wTwo;        rbp: rbpReg),

    (m: mLJNZ;   o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $E0;   w: widWord;     wb: wTwo;        rbp: rbpNone),

    (m: mLJNZB;  o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $E0;   w: widByte;     wb: wTwo;        rbp: rbpNone),

    (m: mLJZ;    o1: OpRegister; o2: OpLocation;  o3: OpAbsent;
        op: $44;   w: widByte;     wb: wTwo;        rbp: rbpReg),

    (m: mLJZ;    o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $E4;   w: widWord;     wb: wTwo;        rbp: rbpNone),

    (m: mLJZB;   o1: OpMemory;   o2: OpLocation;  o3: OpAbsent;
        op: $E4;   w: widByte;     wb: wTwo;        rbp: rbpNone),

    (m: mLPD;    o1: OpPointer;  o2: OpMemory;    o3: OpAbsent;
        op: $88;   w: widWord;     wb: wReserved;   rbp: rbpPtrReg),

    (m: mLPDI;   o1: OpPointer;  o2: OpImmediate; o3: OpAbsent;
        op: $08;   w: widWord;     wb: wTwo;        rbp: rbpPtrReg),

    (m: mMOV;    o1: OpMemory;   o2: OpRegister;  o3: OpAbsent;
        op: $84;   w: widWord;     wb: wReserved;   rbp: rbpReg),

    (m: mMOV;    o1: OpRegister; o2: OpMemory;    o3: OpAbsent;
        op: $80;   w: widWord;     wb: wReserved;   rbp: rbpReg),

    (m: mMOV;    o1: OpMemory;   o2: OpMemory;    o3: OpAbsent;
        op: $90;   w: widWord;     wb: wReserved;   rbp: rbpNone),
    { MOV M, M is encoded as a pair of instructions. Each one encodes a memory
      register and optional offset. The second opcode is $CC. }

    (m: mMOVB;   o1: OpMemory;   o2: OpRegister;  o3: OpAbsent;
        op: $84;   w: widByte;     wb: wReserved;   rbp: rbpReg),

    (m: mMOVB;   o1: OpRegister; o2: OpMemory;    o3: OpAbsent;
        op: $80;   w: widByte;     wb: wReserved;   rbp: rbpReg),

    (m: mMOVB;    o1: OpMemory;   o2: OpMemory;    o3: OpAbsent;
        op: $90;   w: widByte;     wb: wReserved;   rbp: rbpNone),
    { MOVB M, M works just like MOV with a different W field. }

    (m: mMOVBI;   o1: OpRegister; o2: OpImmediate; o3: OpAbsent;
        op: $30;   w: widByte;     wb: wOne;        rbp: rbpReg),

    (m: mMOVBI;   o1: OpMemory;   o2: OpImmediate; o3: OpAbsent;
        op: $4C;   w: widByte;     wb: wOne;        rbp: rbpNone),

    (m: mMOVI;   o1: OpRegister; o2: OpImmediate; o3: OpAbsent;
        op: $30;   w: widWord;     wb: wTwo;        rbp: rbpReg),
    
    (m: MMOVI;   o1: OpMemory;   o2: OpImmediate; o3: OpAbsent;
        op: $4C;   w: widWord;     wb: wTwo;        rbp: rbpNone),

    (m: mMOVP;   o1: OpMemory;   o2: OpPointer;   o3: OpAbsent;
        op: $98;   w: widWord;     wb: wReserved;   rbp: rbpPtrReg),

    (m: mMOVP;   o1: OpPointer;  o2: OpMemory;    o3: OpAbsent;
        op: $8C;   w: widWord;     wb: wReserved;   rbp: rbpPtrReg),

    (m: mNOP;    o1: OpAbsent;   o2: OpAbsent;    o3: OpAbsent;
        op: $00;   w: widByte;     wb: wReserved;   rbp: rbpNone),

    (m: mNOT;    o1: OpRegister; o2: OpAbsent;    o3: OpAbsent;
        op: $2C;   w: widByte;     wb: wReserved;   rbp: rbpReg),

    (m: mNOT;    o1: OpMemory;   o2: OpAbsent;    o3: OpAbsent;
        op: $DC;   w: widWord;     wb: wReserved;   rbp: rbpNone),

    (m: mNOT;    o1: OpRegister; o2: OpMemory;    o3: OpAbsent;
        op: $AC;   w: widWord;     wb: wReserved;   rbp: rbpReg),

    (m: mNOTB;   o1: OpMemory;   o2: OpAbsent;    o3: OpAbsent;
        op: $DC;   w: widByte;     wb: wReserved;   rbp: rbpNone),

    (m: mNOTB;   o1: OpRegister; o2: OpMemory;    o3: OpAbsent;
        op: $AC;   w: widByte;     wb: wReserved;   rbp: rbpReg),

    (m: mOR;     o1: OpRegister; o2: OpMemory;    o3: OpAbsent;
        op: $A4;   w: widWord;     wb: wReserved;   rbp: rbpReg),

    (m: mOR;     o1: OpMemory;   o2: OpRegister;  o3: OpAbsent;
        op: $D4;   w: widWord;     wb: wReserved;   rbp: rbpReg),

    (m: mORB;    o1: OpRegister; o2: OpMemory;    o3: OpAbsent;
        op: $A4;   w: widByte;     wb: wReserved;   rbp: rbpReg),

    (m: mORB;    o1: OpMemory;   o2: OpRegister;  o3: OpAbsent;
        op: $D4;   w: widByte;     wb: wReserved;   rbp: rbpReg),

    (m: mORBI;   o1: OpRegister; o2: OpImmediate; o3: OpAbsent;
        op: $24;   w: widByte;     wb: wOne;        rbp: rbpReg),

    (m: mORBI;   o1: OpMemory;   o2: OpImmediate; o3: OpAbsent;
        op: $C4;   w: widByte;     wb: wOne;        rbp: rbpNone),

    (m: mORI;    o1: OpRegister; o2: OpImmediate; o3: OpAbsent;
        op: $24;   w: widWord;     wb: wTwo;        rbp: rbpReg),

    (m: mORI;    o1: OpMemory;   o2: OpImmediate; o3: OpAbsent;
        op: $C4;   w: widWord;     wb: wTwo;        rbp: rbpNone),

    (m: mSETB;   o1: OpMemory;   o2: OpBit;       o3: OpAbsent;
        op: $F4;   w: widByte;     wb: wReserved;   rbp: rbpBit),

    (m: mSINTR;  o1: OpAbsent;   o2: OpAbsent;    o3: OpAbsent;
        op: $00;   w: widByte;     wb: wReserved;   rbp: rbpSintr),

    (m: mTSL;    o1: OpMemory;   o2: OpImmediate; o3: OpLocation;
        op: $94;   w: widByte;     wb: wTSL;        rbp: rbpNone),

    (m: mWID;    o1: OpWidth;    o2: OpWidth;     o3: OpAbsent;
        op: $00;   w: widByte;     wb: wReserved;   rbp: rbpWid),

    (m: mXFER;   o1: OpAbsent;   o2: OpAbsent;    o3: OpAbsent;
        op: $00;   w: widByte;     wb: wReserved;   rbp: rbpXfer),

    (m: mInvalid; o1: OpAbsent; o2: OpAbsent; o3: OpAbsent;
        op: $FF;   w: widByte;     wb: wReserved;   rbp: rbpNone)
);

procedure GetMnemonicEncodingBounds(const m: Mnemonic; var i, j: Integer);

implementation

procedure GetMnemonicEncodingBounds(const m: Mnemonic; var i, j: Integer);
var x: Integer;
begin
    for x := Low(IEnc) to High(IEnc) do
        if IEnc[x].m = m then
            Break;
    i := x;
    for x := i + 1 to High(IEnc) do
        If IEnc[x].m <> m then
            Break;
    j := x - 1;
end;

end.