Changeset 152


Ignore:
Timestamp:
Apr 20, 2018, 5:42:48 PM (6 years ago)
Author:
chronos
Message:
  • Added: Definition and implementation for more instructions.
  • Modified: Data size should not be part of opcode but rather internal state.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/virtualcpu2/UMachine.pas

    r151 r152  
    2222  TRegSize = Int8;
    2323
    24   TOpcode = (opNop, opHalt, opCopy, opCopy8, opCopy16, opCopy32, opCopy64,
    25     opCopyFromMem, opCopyToMem, opCopyConst,
    26     opGetDataSize, opInc, opInc8, opInc16, opInc32, opInc64, opDec,
    27     opJumpRelNotZero);
     24  TOpcode = (
     25    // Data move
     26    opCopy,
     27    opCopyFromMem,
     28    opCopyToMem,
     29    opCopyConst,
     30    opXchg,
     31    // Arithmetic
     32    opInc,
     33    opDec,
     34    opAdd,
     35    opSub,
     36    opMul,
     37    opDiv,
     38    // Stack
     39    opPush,
     40    opPop,
     41    // Skip
     42    opSkipZero,
     43    opSkipNotZero,
     44    opSkipCarry,
     45    opSkipNotCarray,
     46    // Subroutine
     47    opCallRel,
     48    opCallAbs,
     49    opRet,
     50    // Jump
     51    opJumpRel,
     52    opJumpAbs,
     53    // Logical operations
     54    opAnd,
     55    opOr,
     56    opXor,
     57    // Bit shift
     58    opShr,
     59    opShl,
     60    // I/O access
     61    opIn,
     62    opOut,
     63    // Block operations
     64    opLdir,
     65    opLddr,
     66    // Special
     67    opNop,
     68    opHalt,
     69    opGetSize,
     70    opSetSize, opSetSize8, opSetSize16, opSetSize32, opSetSize64
     71  );
    2872
    2973  TOpcodeHandler = procedure of object;
     74  TDataSize = (dsNative, ds8, ds16, ds32, ds64);
    3075
    3176  { TMachine }
     
    3378  TMachine = class
    3479  private
    35     OpcodeTable: array[TOpcode] of TOpcodeHandler;
     80    OpcodeTable: array[TOpcode, TDataSize] of TOpcodeHandler;
     81    procedure CheckIP;
    3682    procedure OpcodeNop;
    3783    procedure OpcodeHalt;
     
    4490    procedure OpcodeCopyToMem;
    4591    procedure OpcodeCopyConst;
     92    procedure OpcodeCopyConst8;
     93    procedure OpcodeCopyConst16;
     94    procedure OpcodeCopyConst32;
     95    procedure OpcodeCopyConst64;
    4696    procedure OpcodeGetDataSize;
     97    procedure OpcodeXchg;
     98    procedure OpcodeAdd;
     99    procedure OpcodeSub;
     100    procedure OpcodeAnd;
     101    procedure OpcodeOr;
     102    procedure OpcodeXor;
     103    procedure OpcodePop;
     104    procedure OpcodePush;
     105    procedure OpcodeLdir;
    47106    procedure OpcodeInc;
    48107    procedure OpcodeInc8;
     
    51110    procedure OpcodeInc64;
    52111    procedure OpcodeDec;
    53     procedure OpcodeJumpRelNotZero;
     112    procedure OpcodeSkipNotZero;
     113    procedure OpcodeSkipZero;
     114    procedure OpcodeJumpRel;
     115    procedure OpcodeJumpAbs;
    54116    procedure OpcodeUnsupported;
    55117    function ReadNext: TDataInt;
     
    59121    function ReadNext32: Cardinal;
    60122    function ReadNext64: QWord;
     123    procedure SetOpcode(Opcode: TOpcode; Handler: TOpcodeHandler; DataSize: TDataSize = dsNative);
     124    procedure InitOpcode;
     125    procedure Step;
    61126  public
    62127    Registers: array of TDataInt;
     
    64129    Memory: array of Byte;
    65130    IP: TAddrInt;
     131    SP: TAddrInt;
     132    DataSize: TDataSize;
    66133    Terminated: Boolean;
     134    SkipNext: Boolean;
    67135    procedure Run;
    68136    constructor Create;
     
    88156  end;
    89157
     158const
     159  DataSizeValue: array[TDataSize] of Byte = (SizeOf(TDataInt), SizeOf(Byte),
     160    SizeOf(Word), SizeOf(Cardinal), SizeOf(QWord));
     161
    90162implementation
    91163
     
    93165
    94166procedure TMachine.Run;
    95 var
    96   Opcode: TOpcode;
    97167begin
    98168  IP := 0;
    99169  Terminated := False;
    100170  while not Terminated do begin
    101     if IP >= Length(Memory) then IP := 0;
    102     Opcode := TOpcode(ReadNext8);
    103     if (Opcode <= High(Opcode)) and Assigned(OpcodeTable[Opcode]) then
    104       OpcodeTable[Opcode]
    105       else raise Exception.Create('Unknown opcode: ' + IntToHex(Integer(Opcode), 2));
     171    Step;
    106172  end;
    107173end;
    108174
     175procedure TMachine.SetOpcode(Opcode: TOpcode; Handler: TOpcodeHandler; DataSize: TDataSize);
     176begin
     177  if SizeOf(TDataInt) >= DataSizeValue[DataSize] then OpcodeTable[Opcode, DataSize] := Handler
     178    else OpcodeTable[Opcode, DataSize] := OpcodeUnsupported;
     179end;
     180
     181procedure TMachine.InitOpcode;
     182begin
     183  SetOpcode(opNop, OpcodeNop);
     184  SetOpcode(opHalt, OpcodeHalt);
     185  SetOpcode(opCopy, OpcodeCopy);
     186  SetOpcode(opCopy, OpcodeCopy8, ds8);
     187  SetOpcode(opCopy, OpcodeCopy16, ds16);
     188  SetOpcode(opCopy, OpcodeCopy32, ds32);
     189  SetOpcode(opCopy, OpcodeCopy64, ds64);
     190  SetOpcode(opCopyFromMem, OpcodeCopyFromMem);
     191  SetOpcode(opCopyToMem, OpcodeCopyToMem);
     192  SetOpcode(opCopyConst, OpcodeCopyConst);
     193  SetOpcode(opCopyConst, OpcodeCopyConst8, ds8);
     194  SetOpcode(opCopyConst, OpcodeCopyConst16, ds16);
     195  SetOpcode(opCopyConst, OpcodeCopyConst32, ds32);
     196  SetOpcode(opCopyConst, OpcodeCopyConst64, ds64);
     197  SetOpcode(opXchg, OpcodeXchg);
     198  SetOpcode(opGetSize, OpcodeGetDataSize);
     199  SetOpcode(opInc, OpcodeInc);
     200  SetOpcode(opInc, OpcodeInc8, ds8);
     201  SetOpcode(opInc, OpcodeInc16, ds16);
     202  SetOpcode(opInc, OpcodeInc32, ds32);
     203  SetOpcode(opInc, OpcodeInc64, ds64);
     204  SetOpcode(opDec, OpcodeDec);
     205  SetOpcode(opSkipZero, OpcodeSkipZero);
     206  SetOpcode(opSkipNotZero, OpcodeSkipNotZero);
     207  SetOpcode(opJumpRel, OpcodeJumpRel);
     208  SetOpcode(opJumpAbs, OpcodeJumpAbs);
     209  SetOpcode(opAdd, OpcodeAdd);
     210  SetOpcode(opSub, OpcodeSub);
     211  SetOpcode(opLdir, OpcodeLdir);
     212  SetOpcode(opAnd, OpcodeAnd);
     213  SetOpcode(opOr, OpcodeOr);
     214  SetOpcode(opXor, OpcodeXor);
     215  SetOpcode(opPush, OpcodePush);
     216  SetOpcode(opPop, OpcodePop);
     217end;
     218
     219procedure TMachine.Step;
     220var
     221  Opcode: TOpcode;
     222  OpcodeHandler: TOpcodeHandler;
     223begin
     224  if IP >= Length(Memory) then IP := 0;
     225  Opcode := TOpcode(ReadNext8);
     226  if (Opcode <= High(Opcode)) then begin
     227    OpcodeHandler := OpcodeTable[Opcode, DataSize];
     228    if not Assigned(OpcodeHandler) then OpcodeHandler
     229    else raise Exception.Create('Opcode without handler: ' + IntToHex(Integer(Opcode), 2));
     230  end else raise Exception.Create('Unknown opcode: ' + IntToHex(Integer(Opcode), 2));
     231end;
     232
    109233constructor TMachine.Create;
    110234begin
    111235  SetLength(Registers, 16);
    112 
    113   // Opcode table initialization
    114   OpcodeTable[opNop] := OpcodeNop;
    115   OpcodeTable[opHalt] := OpcodeHalt;
    116   OpcodeTable[opCopy] := OpcodeCopy;
    117   OpcodeTable[opCopy8] := OpcodeCopy8;
    118   if SizeOf(TDataInt) >= SizeOf(Word) then
    119     OpcodeTable[opCopy16] := OpcodeCopy16
    120     else OpcodeTable[opCopy16] := OpcodeUnsupported;
    121   if SizeOf(TDataInt) >= SizeOf(Cardinal) then
    122     OpcodeTable[opCopy32] := OpcodeCopy32
    123     else OpcodeTable[opCopy32] := OpcodeUnsupported;
    124   if SizeOf(TDataInt) >= SizeOf(QWord) then
    125     OpcodeTable[opCopy64] := OpcodeCopy64
    126     else OpcodeTable[opCopy64] := OpcodeUnsupported;
    127   OpcodeTable[opCopyFromMem] := OpcodeCopyFromMem;
    128   OpcodeTable[opCopyToMem] := OpcodeCopyToMem;
    129   OpcodeTable[opCopyConst] := OpcodeCopyConst;
    130   OpcodeTable[opGetDataSize] := OpcodeGetDataSize;
    131   OpcodeTable[opInc] := OpcodeInc;
    132   OpcodeTable[opInc8] := OpcodeInc8;
    133   if SizeOf(TDataInt) >= SizeOf(Word) then OpcodeTable[opInc16] := OpcodeInc16
    134     else OpcodeTable[opInc16] := OpcodeUnsupported;
    135   if SizeOf(TDataInt) >= SizeOf(Cardinal) then OpcodeTable[opInc32] := OpcodeInc32
    136     else OpcodeTable[opInc32] := OpcodeUnsupported;
    137   if SizeOf(TDataInt) >= SizeOf(QWord) then OpcodeTable[opInc64] := OpcodeInc64
    138     else OpcodeTable[opInc64] := OpcodeUnsupported;
    139   OpcodeTable[opDec] := OpcodeDec;
    140   OpcodeTable[opJumpRelNotZero] := OpcodeJumpRelNotZero;
     236  InitOpcode;
    141237end;
    142238
    143239procedure TMachine.OpcodeNop;
    144240begin
    145 
    146241end;
    147242
     
    231326end;
    232327
     328procedure TMachine.OpcodeCopyConst8;
     329var
     330  Source: Byte;
     331  Dest: TRegIndex;
     332begin
     333  Dest := ReadNext8;
     334  Source := ReadNext8;
     335  PByte(@Registers[Dest])^ := Source;
     336end;
     337
     338procedure TMachine.OpcodeCopyConst16;
     339var
     340  Source: Word;
     341  Dest: TRegIndex;
     342begin
     343  Dest := ReadNext8;
     344  Source := ReadNext16;
     345  PWord(@Registers[Dest])^ := Source;
     346end;
     347
     348procedure TMachine.OpcodeCopyConst32;
     349var
     350  Source: Cardinal;
     351  Dest: TRegIndex;
     352begin
     353  Dest := ReadNext8;
     354  Source := ReadNext32;
     355  PCardinal(@Registers[Dest])^ := Source;
     356end;
     357
     358procedure TMachine.OpcodeCopyConst64;
     359var
     360  Source: QWord;
     361  Dest: TRegIndex;
     362begin
     363  Dest := ReadNext8;
     364  Source := ReadNext64;
     365  PQWord(@Registers[Dest])^ := Source;
     366end;
     367
    233368procedure TMachine.OpcodeGetDataSize;
    234369var
     
    239374end;
    240375
     376procedure TMachine.OpcodeXchg;
     377var
     378  Source: TRegIndex;
     379  Dest: TRegIndex;
     380  Temp: TDataInt;
     381begin
     382  Dest := ReadNext8;
     383  Source := ReadNext8;
     384  Temp := PDataInt(@Registers[Dest])^;
     385  PDataInt(@Registers[Dest])^ := PDataInt(@Registers[Source])^;
     386  PDataInt(@Registers[Source])^ := Temp;
     387end;
     388
     389procedure TMachine.OpcodeAdd;
     390var
     391  Op1: TRegIndex;
     392  Op2: TRegIndex;
     393begin
     394  Op1 := ReadNext8;
     395  Op2 := ReadNext8;
     396  PDataInt(@Registers[Op1])^ := PDataInt(@Registers[Op1])^ + PDataInt(@Registers[Op2])^;
     397end;
     398
     399procedure TMachine.OpcodeSub;
     400var
     401  Op1: TRegIndex;
     402  Op2: TRegIndex;
     403begin
     404  Op1 := ReadNext8;
     405  Op2 := ReadNext8;
     406  PDataInt(@Registers[Op1])^ := PDataInt(@Registers[Op1])^ - PDataInt(@Registers[Op2])^;
     407end;
     408
     409procedure TMachine.OpcodeAnd;
     410var
     411  Op1: TRegIndex;
     412  Op2: TRegIndex;
     413begin
     414  Op1 := ReadNext8;
     415  Op2 := ReadNext8;
     416  PDataInt(@Registers[Op1])^ := PDataInt(@Registers[Op1])^ and PDataInt(@Registers[Op2])^;
     417end;
     418
     419procedure TMachine.OpcodeOr;
     420var
     421  Op1: TRegIndex;
     422  Op2: TRegIndex;
     423begin
     424  Op1 := ReadNext8;
     425  Op2 := ReadNext8;
     426  PDataInt(@Registers[Op1])^ := PDataInt(@Registers[Op1])^ or PDataInt(@Registers[Op2])^;
     427end;
     428
     429procedure TMachine.OpcodeXor;
     430var
     431  Op1: TRegIndex;
     432  Op2: TRegIndex;
     433begin
     434  Op1 := ReadNext8;
     435  Op2 := ReadNext8;
     436  PDataInt(@Registers[Op1])^ := PDataInt(@Registers[Op1])^ xor PDataInt(@Registers[Op2])^;
     437end;
     438
     439procedure TMachine.OpcodePop;
     440var
     441  Dest: TRegIndex;
     442begin
     443  Dest := ReadNext8;
     444  PDataInt(@Registers[Dest])^ := PDataInt(@Memory[SP])^;
     445  Inc(SP, SizeOf(TDataInt));
     446end;
     447
     448procedure TMachine.OpcodePush;
     449var
     450  Source: TRegIndex;
     451begin
     452  Source := ReadNext8;
     453  Dec(SP, SizeOf(TDataInt));
     454  PDataInt(@Memory[SP])^ := PDataInt(@Registers[Source])^;
     455end;
     456
     457procedure TMachine.OpcodeLdir;
     458var
     459  Src: TRegIndex;
     460  Dst: TRegIndex;
     461  Count: TRegIndex;
     462begin
     463  Src := ReadNext8;
     464  Dst := ReadNext8;
     465  Count := ReadNext8;
     466  while Count > 0 do begin
     467    PDataInt(@Registers[Dst])^ := PDataInt(@Registers[Src])^;
     468    Inc(Src);
     469    Inc(Dst);
     470    Dec(Count);
     471  end;
     472end;
     473
    241474procedure TMachine.OpcodeInc;
    242475var
     
    287520end;
    288521
    289 procedure TMachine.OpcodeJumpRelNotZero;
     522procedure TMachine.OpcodeSkipNotZero;
     523var
     524  Reg: TRegIndex;
     525begin
     526  Reg := ReadNext8;
     527  SkipNext := Registers[Reg] <> 0;
     528end;
     529
     530procedure TMachine.OpcodeSkipZero;
     531var
     532  Reg: TRegIndex;
     533begin
     534  Reg := ReadNext8;
     535  SkipNext := Registers[Reg] = 0;
     536end;
     537
     538procedure TMachine.OpcodeJumpRel;
    290539var
    291540  RelAddr: TAddrInt;
    292   Reg: TRegIndex;
    293 begin
    294   Reg := ReadNext8;
     541begin
     542  OpcodeSkipNotZero;
    295543  RelAddr := ReadNextS8;
    296   if Registers[Reg] <> 0 then
    297     IP := IP + RelAddr;
     544  if not SkipNext then IP := IP + RelAddr;
     545end;
     546
     547procedure TMachine.OpcodeJumpAbs;
     548var
     549  Addr: TAddrInt;
     550begin
     551  OpcodeSkipNotZero;
     552  Addr := ReadNext;
     553  if not SkipNext then IP := Addr;
    298554end;
    299555
     
    303559end;
    304560
     561procedure TMachine.CheckIP;
     562begin
     563  if (IP < 0) and (IP >= Length(Memory)) then
     564    raise Exception.Create('Memory access out of range ' + IntToHex(IP, 8));
     565end;
     566
    305567function TMachine.ReadNext: TDataInt;
    306568begin
    307   if (IP >= 0) and (IP < Length(Memory)) then Result := PDataInt(@Memory[IP])^
    308     else raise Exception.Create('Memory access out of range ' + IntToHex(IP, 8));
     569  CheckIP;
     570  Result := PDataInt(@Memory[IP])^;
    309571  Inc(IP, SizeOf(TDataInt));
    310572end;
     
    312574function TMachine.ReadNext8: Byte;
    313575begin
    314   if (IP >= 0) and (IP < Length(Memory)) then Result := Memory[IP]
    315     else raise Exception.Create('Memory access out of range ' + IntToHex(IP, 8));
     576  CheckIP;
     577  Result := Memory[IP];
    316578  Inc(IP);
    317579end;
     
    319581function TMachine.ReadNextS8: ShortInt;
    320582begin
    321   if (IP >= 0) and (IP < Length(Memory)) then Result := Memory[IP]
    322     else raise Exception.Create('Memory access out of range ' + IntToHex(IP, 8));
     583  CheckIP;
     584  Result := Memory[IP];
    323585  Inc(IP);
    324586end;
     
    326588function TMachine.ReadNext16: Word;
    327589begin
    328   if (IP >= 0) and (IP < Length(Memory)) then Result := PWord(@Memory[IP])^
    329     else raise Exception.Create('Memory access out of range ' + IntToHex(IP, 8));
     590  CheckIP;
     591  Result := PWord(@Memory[IP])^;
    330592  Inc(IP, SizeOf(Word));
    331593end;
     
    333595function TMachine.ReadNext32: Cardinal;
    334596begin
    335   if (IP >= 0) and (IP < Length(Memory)) then Result := PCardinal(@Memory[IP])^
    336     else raise Exception.Create('Memory access out of range ' + IntToHex(IP, 8));
     597  CheckIP;
     598  Result := PCardinal(@Memory[IP])^;
    337599  Inc(IP, SizeOf(Cardinal));
    338600end;
     
    340602function TMachine.ReadNext64: QWord;
    341603begin
    342   if (IP >= 0) and (IP < Length(Memory)) then Result := PQWord(@Memory[IP])^
    343     else raise Exception.Create('Memory access out of range ' + IntToHex(IP, 8));
     604  CheckIP;
     605  Result := PQWord(@Memory[IP])^;
    344606  Inc(IP, SizeOf(QWord));
    345607end;
     
    374636procedure TInstructionWriter.AddGetDataSize(Reg: TRegIndex);
    375637begin
    376   AddData8(Integer(opGetDataSize));
     638  AddData8(Integer(opGetSize));
    377639  AddData8(Reg);
    378640end;
     
    412674  );
    413675begin
    414   AddData8(Integer(opJumpRelNotZero));
     676  AddData8(Integer(opJumpRel));
    415677  AddData8(Reg);
    416678  AddDataS8(RelAddr - 3);
Note: See TracChangeset for help on using the changeset viewer.