Ignore:
Timestamp:
Jul 12, 2022, 10:43:40 PM (23 months ago)
Author:
chronos
Message:
  • Modified: More instructions.
  • Modified: Optimized instruction execution with procedure array instead case.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/CpuSingleSize/UCpu.pas

    r220 r223  
    11unit UCpu;
    2 
    3 {$mode delphi}
    42
    53interface
     
    1210    inAdd, inSub, inIn, inOut, inJump, inJumpZero, inJumpNotZero, inPush, inPop,
    1311    inCall, inRet, inAnd, inOr, inXor, inShl, inShr, inMul, inDiv, inMod,
    14     inJumpRel, inLoadIndex, inStoreIndex);
     12    inJumpRel, inLoadIndex, inStoreIndex, inLoadCpu, inStoreCpu, inEi, inDi);
    1513
    1614  TInteger = Integer;
     
    2018  TInputEvent = function (Device, Port: TInteger): TInteger of object;
    2119
     20  { TCpuStatus }
     21
     22  TCpuStatus = packed record
     23    InterruptEnabled: Boolean;
     24    UserMode: Boolean;
     25    UserModeWasActive: Boolean;
     26    function GetInteger: TInteger;
     27    procedure SetInteger(Value: TInteger);
     28  end;
     29
     30  TIntegerArray = array of TInteger;
     31
     32  TMemoryBlock = record
     33    Base: TIntegerArray;
     34    Size: TInteger;
     35  end;
     36
     37  TMemoryBlockIndex = (mbCode, mbData, mbStack, mbInterrupt);
     38  TInstructionHandler = procedure of object;
     39  TSystemInterrupt = (siReset, siUserIn, siUserOut, siUserInvalidMemory,
     40    siPrivilegedInstruction);
     41  TCpuRegister = (crIP, crSP, crStatusRegister, crUserMemoryBase, crUserMemorySize);
     42
    2243  { TCpu }
    2344
    2445  TCpu = class
    2546  private
     47    FBaseMemory: TMemoryBlock;
     48    FUserMemory: TMemoryBlock;
     49    FMemory: TMemoryBlock;
    2650    FRunning: Boolean;
    2751    FThread: TCpuThread;
     
    3054    FNextInterupt: TInteger;
    3155    FHalted: Boolean;
     56    FTicks: Integer;
     57    FInstructionHandlers: array[TInstruction] of TInstructionHandler;
     58    function GetMemory: TIntegerArray;
     59    procedure InstructionNop;
     60    procedure InstructionHalt;
     61    procedure InstructionSet;
     62    procedure InstructionCopy;
     63    procedure InstructionLoad;
     64    procedure InstructionStore;
     65    procedure InstructionInc;
     66    procedure InstructionDec;
     67    procedure InstructionAdd;
     68    procedure InstructionSub;
     69    procedure InstructionIn;
     70    procedure InstructionOut;
     71    procedure InstructionJump;
     72    procedure InstructionJumpRel;
     73    procedure InstructionJumpZero;
     74    procedure InstructionJumpNotZero;
     75    procedure InstructionPush;
     76    procedure InstructionPop;
     77    procedure InstructionCall;
     78    procedure InstructionRet;
     79    procedure InstructionReti;
     80    procedure InstructionAnd;
     81    procedure InstructionOr;
     82    procedure InstructionXor;
     83    procedure InstructionShl;
     84    procedure InstructionShr;
     85    procedure InstructionMod;
     86    procedure InstructionDiv;
     87    procedure InstructionMul;
     88    procedure InstructionLoadIndex;
     89    procedure InstructionStoreIndex;
     90    procedure InstructionLoadCpu;
     91    procedure InstructionStoreCpu;
     92    procedure InstructionEi;
     93    procedure InstructionDi;
     94    procedure SetMemory(AValue: TIntegerArray);
    3295    procedure SetRunning(AValue: Boolean);
    3396    procedure CheckInterreupts;
     97    procedure Push(Value: TInteger);
     98    function Pop: TInteger;
     99    procedure StoreContext;
     100    procedure LoadContext;
     101    procedure InitInstructions;
     102    procedure ActivateUserMode;
     103    procedure DeactivateUserMode;
    34104  public
    35     Ticks: Integer;
    36     IP: TInteger;
    37     SP: TInteger;
    38     Data: array of TInteger;
     105    InstructionPointer: TInteger; // Instruction Pointer
     106    StackPointer: TInteger; // Stack Pointer
     107    StatusRegister: TCpuStatus; // Status Register
    39108    R: array of TInteger;
    40109    function ReadNext: TInteger;
     
    44113    procedure Stop;
    45114    procedure Reset;
    46     procedure Interrupt(Index: TInteger);
     115    procedure Interrupt(Index: TSystemInterrupt); overload;
     116    procedure Interrupt(Index: TInteger); overload;
    47117    constructor Create;
    48118    destructor Destroy; override;
     119    property Ticks: Integer read FTicks;
     120    property Memory: TIntegerArray read GetMemory write SetMemory;
    49121    property OnInput: TInputEvent read FOnInput write FOnInput;
    50122    property OnOutput: TOutputEvent read FOnOutput write FOnOutput;
     
    62134
    63135implementation
     136
     137{ TCpuStatus }
     138
     139function TCpuStatus.GetInteger: TInteger;
     140begin
     141
     142end;
     143
     144procedure TCpuStatus.SetInteger(Value: TInteger);
     145begin
     146
     147end;
    64148
    65149{ TCpuThread }
     
    83167end;
    84168
     169procedure TCpu.InstructionNop;
     170begin
     171  // No operation
     172end;
     173
     174function TCpu.GetMemory: TIntegerArray;
     175begin
     176  Result := FBaseMemory.Base;
     177end;
     178
     179procedure TCpu.InstructionHalt;
     180begin
     181  FHalted := True;
     182end;
     183
     184procedure TCpu.InstructionSet;
     185begin
     186  R[ReadNext] := ReadNext;
     187end;
     188
     189procedure TCpu.InstructionCopy;
     190begin
     191  R[ReadNext] := R[ReadNext];
     192end;
     193
     194procedure TCpu.InstructionLoad;
     195begin
     196  R[ReadNext] := FMemory.Base[R[ReadNext]];
     197end;
     198
     199procedure TCpu.InstructionStore;
     200begin
     201  FMemory.Base[R[ReadNext]] := R[ReadNext];
     202end;
     203
     204procedure TCpu.InstructionInc;
     205begin
     206  Inc(R[ReadNext]);
     207end;
     208
     209procedure TCpu.InstructionDec;
     210begin
     211  Dec(R[ReadNext]);
     212end;
     213
     214procedure TCpu.InstructionAdd;
     215var
     216  Index: TInteger;
     217begin
     218  Index := ReadNext;
     219  R[Index] := R[Index] + R[ReadNext];
     220end;
     221
     222procedure TCpu.InstructionSub;
     223var
     224  Index: TInteger;
     225begin
     226  Index := ReadNext;
     227  R[Index] := R[Index] - R[ReadNext];
     228end;
     229
     230procedure TCpu.InstructionIn;
     231var
     232  Index: TInteger;
     233  Device: TInteger;
     234  Port: TInteger;
     235begin
     236  Index := ReadNext;
     237  Device := R[ReadNext];
     238  Port := R[ReadNext];
     239  if StatusRegister.UserMode then begin
     240    Interrupt(siUserIn);
     241  end else begin
     242    if Assigned(FOnInput) then R[Index] := FOnInput(Device, Port);
     243  end;
     244end;
     245
     246procedure TCpu.InstructionOut;
     247var
     248  Device: TInteger;
     249  Port: TInteger;
     250  Index: TInteger;
     251begin
     252  Device := R[ReadNext];
     253  Port := R[ReadNext];
     254  Index := ReadNext;
     255  if StatusRegister.UserMode then begin
     256    Interrupt(siUserOut);
     257  end else begin
     258    if Assigned(FOnOutput) then FOnOutput(Device, Port, R[Index]);
     259  end;
     260end;
     261
     262procedure TCpu.InstructionJump;
     263begin
     264  InstructionPointer := ReadNext;
     265end;
     266
     267procedure TCpu.InstructionJumpRel;
     268begin
     269  InstructionPointer := InstructionPointer + ReadNext;
     270end;
     271
     272procedure TCpu.InstructionJumpZero;
     273var
     274  Index: TInteger;
     275  Address: TInteger;
     276begin
     277  Index := ReadNext;
     278  Address := ReadNext;
     279  if R[Index] = 0 then InstructionPointer := Address;
     280end;
     281
     282procedure TCpu.InstructionJumpNotZero;
     283var
     284  Index: TInteger;
     285  Address: TInteger;
     286begin
     287  Index := ReadNext;
     288  Address := ReadNext;
     289  if R[Index] <> 0 then InstructionPointer := Address;
     290end;
     291
     292procedure TCpu.InstructionPush;
     293begin
     294  Push(R[ReadNext]);
     295end;
     296
     297procedure TCpu.InstructionPop;
     298begin
     299  R[ReadNext] := Pop;
     300end;
     301
     302procedure TCpu.InstructionCall;
     303var
     304  Address: TInteger;
     305begin
     306  Address := ReadNext;
     307  Push(InstructionPointer);
     308  InstructionPointer := Address;
     309end;
     310
     311procedure TCpu.InstructionRet;
     312begin
     313  InstructionPointer := Pop;
     314end;
     315
     316procedure TCpu.InstructionReti;
     317begin
     318  if StatusRegister.UserMode then begin
     319    Interrupt(siPrivilegedInstruction);
     320    Exit;
     321  end;
     322  if StatusRegister.UserModeWasActive then ActivateUserMode;
     323  StatusRegister.InterruptEnabled := True;
     324  InstructionPointer := Pop;
     325end;
     326
     327procedure TCpu.InstructionAnd;
     328var
     329  Index: TInteger;
     330begin
     331  Index := ReadNext;
     332  R[Index] := R[Index] and R[ReadNext];
     333end;
     334
     335procedure TCpu.InstructionOr;
     336var
     337  Index: TInteger;
     338begin
     339  Index := ReadNext;
     340  R[Index] := R[Index] or R[ReadNext];
     341end;
     342
     343procedure TCpu.InstructionXor;
     344var
     345  Index: TInteger;
     346begin
     347  Index := ReadNext;
     348  R[Index] := R[Index] xor R[ReadNext];
     349end;
     350
     351procedure TCpu.InstructionShl;
     352var
     353  Index: TInteger;
     354begin
     355  Index := ReadNext;
     356  R[Index] := R[Index] shl R[ReadNext];
     357end;
     358
     359procedure TCpu.InstructionShr;
     360var
     361  Index: TInteger;
     362begin
     363  Index := ReadNext;
     364  R[Index] := R[Index] shr R[ReadNext];
     365end;
     366
     367procedure TCpu.InstructionMod;
     368var
     369  Index: TInteger;
     370begin
     371  Index := ReadNext;
     372  R[Index] := R[Index] mod R[ReadNext];
     373end;
     374
     375procedure TCpu.InstructionDiv;
     376var
     377  Index: TInteger;
     378begin
     379  Index := ReadNext;
     380  R[Index] := R[Index] div R[ReadNext];
     381end;
     382
     383procedure TCpu.InstructionMul;
     384var
     385  Index: TInteger;
     386begin
     387  Index := ReadNext;
     388  R[Index] := R[Index] * R[ReadNext];
     389end;
     390
     391procedure TCpu.InstructionLoadIndex;
     392begin
     393  R[ReadNext] := FMemory.Base[R[ReadNext] + ReadNext];
     394end;
     395
     396procedure TCpu.InstructionStoreIndex;
     397begin
     398  FMemory.Base[R[ReadNext] + ReadNext] := R[ReadNext];
     399end;
     400
     401procedure TCpu.InstructionLoadCpu;
     402var
     403  Index: TInteger;
     404  I: TInteger;
     405begin
     406  R[ReadNext] := FMemory.Base[R[ReadNext]];
     407  Index := ReadNext;
     408  I := ReadNext;
     409  case TCpuRegister(I) of
     410    crIP: R[Index] := InstructionPointer;
     411    crSP: R[Index] := StackPointer;
     412    crStatusRegister: R[Index] := StatusRegister.GetInteger;
     413    crUserMemoryBase: R[Index] := Pointer(FUserMemory.Base) - Pointer(FBaseMemory.Base);
     414    crUserMemorySize: R[Index] := FUserMemory.Size;
     415  end;
     416end;
     417
     418procedure TCpu.InstructionStoreCpu;
     419var
     420  Index: TInteger;
     421  I: TInteger;
     422begin
     423  if StatusRegister.UserMode then begin
     424    Interrupt(siPrivilegedInstruction);
     425    Exit;
     426  end;
     427  R[ReadNext] := FMemory.Base[R[ReadNext]];
     428  Index := ReadNext;
     429  I := ReadNext;
     430  case TCpuRegister(I) of
     431    crIP: InstructionPointer := R[Index];
     432    crSP: StackPointer := R[Index];
     433    crStatusRegister: StatusRegister.SetInteger(R[Index]);
     434    crUserMemoryBase: FUserMemory.Base := Pointer(FBaseMemory.Base) + R[Index];
     435    crUserMemorySize: FUserMemory.Size := R[Index];
     436  end;
     437end;
     438
     439procedure TCpu.InstructionEi;
     440begin
     441  if StatusRegister.UserMode then begin
     442    Interrupt(siPrivilegedInstruction);
     443    Exit;
     444  end;
     445  StatusRegister.InterruptEnabled := True;
     446end;
     447
     448procedure TCpu.InstructionDi;
     449begin
     450  if StatusRegister.UserMode then begin
     451    Interrupt(siPrivilegedInstruction);
     452    Exit;
     453  end;
     454  StatusRegister.InterruptEnabled := False;
     455end;
     456
     457procedure TCpu.SetMemory(AValue: TIntegerArray);
     458begin
     459  if (FBaseMemory.Base = AValue) and (FBaseMemory.Size = Length(AValue)) then Exit;
     460  FBaseMemory.Base := AValue;
     461  FBaseMemory.Size := Length(AValue);
     462end;
     463
    85464procedure TCpu.CheckInterreupts;
    86465begin
    87   if FNextInterupt <> -1 then begin
    88     Dec(SP);
    89     Data[SP] := IP;
    90     IP := Data[FNextInterupt];
     466  if StatusRegister.InterruptEnabled and (FNextInterupt <> -1) then begin
     467    Push(InstructionPointer);
     468    if StatusRegister.UserMode then DeactivateUserMode;
     469    InstructionPointer := FMemory.Base[FNextInterupt];
     470    StatusRegister.InterruptEnabled := False;
    91471    FNextInterupt := -1;
    92472    FHalted := False;
     
    94474end;
    95475
     476procedure TCpu.Push(Value: TInteger);
     477begin
     478  Dec(StackPointer);
     479  FMemory.Base[StackPointer] := Value;
     480end;
     481
     482function TCpu.Pop: TInteger;
     483begin
     484  Result := FMemory.Base[StackPointer];
     485  Inc(StackPointer);
     486end;
     487
     488procedure TCpu.StoreContext;
     489var
     490  I: Integer;
     491begin
     492  for I := 0 to Length(R) - 1 do
     493    Push(R[I]);
     494end;
     495
     496procedure TCpu.LoadContext;
     497var
     498  I: Integer;
     499begin
     500  for I := Length(R) - 1 downto 0 do
     501    R[I] := Pop;
     502end;
     503
     504procedure TCpu.InitInstructions;
     505begin
     506  FInstructionHandlers[inNop] := InstructionNop;
     507  FInstructionHandlers[inHalt] := InstructionHalt;
     508  FInstructionHandlers[inSet] := InstructionSet;
     509  FInstructionHandlers[inCopy] := InstructionCopy;
     510  FInstructionHandlers[inLoad] := InstructionLoad;
     511  FInstructionHandlers[inStore] := InstructionStore;
     512  FInstructionHandlers[inInc] := InstructionInc;
     513  FInstructionHandlers[inDec] := InstructionDec;
     514  FInstructionHandlers[inAdd] := InstructionAdd;
     515  FInstructionHandlers[inSub] := InstructionSub;
     516  FInstructionHandlers[inIn] := InstructionIn;
     517  FInstructionHandlers[inOut] := InstructionOut;
     518  FInstructionHandlers[inJump] := InstructionJump;
     519  FInstructionHandlers[inJumpRel] := InstructionJumpRel;
     520  FInstructionHandlers[inJumpZero] := InstructionJumpZero;
     521  FInstructionHandlers[inJumpNotZero] := InstructionJumpNotZero;
     522  FInstructionHandlers[inPush] := InstructionPush;
     523  FInstructionHandlers[inPop] := InstructionPop;
     524  FInstructionHandlers[inCall] := InstructionCall;
     525  FInstructionHandlers[inRet] := InstructionRet;
     526  FInstructionHandlers[inAnd] := InstructionAnd;
     527  FInstructionHandlers[inOr] := InstructionOr;
     528  FInstructionHandlers[inXor] := InstructionXor;
     529  FInstructionHandlers[inShl] := InstructionShl;
     530  FInstructionHandlers[inShr] := InstructionShr;
     531  FInstructionHandlers[inMul] := InstructionMul;
     532  FInstructionHandlers[inDiv] := InstructionDiv;
     533  FInstructionHandlers[inMod] := InstructionMod;
     534  FInstructionHandlers[inLoadIndex] := InstructionLoadIndex;
     535  FInstructionHandlers[inStoreIndex] := InstructionStoreIndex;
     536  FInstructionHandlers[inLoadCpu] := InstructionLoadCpu;
     537  FInstructionHandlers[inStoreCpu] := InstructionStoreCpu;
     538  FInstructionHandlers[inEi] := InstructionEi;
     539  FInstructionHandlers[inDi] := InstructionDi;
     540end;
     541
     542procedure TCpu.ActivateUserMode;
     543begin
     544  StatusRegister.UserMode := True;
     545  FMemory := FUserMemory;
     546end;
     547
     548procedure TCpu.DeactivateUserMode;
     549begin
     550  FMemory := FBaseMemory;
     551  StatusRegister.UserModeWasActive := StatusRegister.UserMode;
     552  StatusRegister.UserMode := False;
     553end;
     554
    96555function TCpu.ReadNext: TInteger;
    97556begin
    98   if IP >= Length(Data) then IP := 0;
    99   Result := Data[IP];
    100   Inc(IP);
     557  if InstructionPointer >= FMemory.Size then InstructionPointer := 0;
     558  Result := FMemory.Base[InstructionPointer];
     559  Inc(InstructionPointer);
    101560end;
    102561
    103562procedure TCpu.WriteNext(Value: TInteger);
    104563begin
    105   if IP >= Length(Data) then IP := 0;
    106   Data[IP] := Value;
    107   Inc(IP);
     564  if InstructionPointer >= FMemory.Size then InstructionPointer := 0;
     565  FMemory.Base[InstructionPointer] := Value;
     566  Inc(InstructionPointer);
    108567end;
    109568
     
    111570var
    112571  Instruction: TInstruction;
    113   Address: TInteger;
    114   Index: TInteger;
    115   Port: TInteger;
    116   Dest: TInteger;
    117   Device: TInteger;
    118572begin
    119573  Instruction := TInstruction(ReadNext);
    120   case Instruction of
    121     inNop: ;
    122     inHalt: FHalted := True;
    123     inSet: R[ReadNext] := ReadNext;
    124     inCopy: R[ReadNext] := R[ReadNext];
    125     inLoad: R[ReadNext] := Data[R[ReadNext]];
    126     inStore: Data[R[ReadNext]] := R[ReadNext];
    127     inInc: Inc(R[ReadNext]);
    128     inDec: Dec(R[ReadNext]);
    129     inAdd: begin
    130       Index := ReadNext;
    131       R[Index] := R[Index] + R[ReadNext];
    132     end;
    133     inSub: begin
    134       Index := ReadNext;
    135       R[Index] := R[Index] - R[ReadNext];
    136     end;
    137     inIn: begin
    138       Index := ReadNext;
    139       Device := R[ReadNext];
    140       Port := R[ReadNext];
    141       if Assigned(FOnInput) then R[Index] := FOnInput(Device, Port);
    142     end;
    143     inOut: begin
    144       Device := R[ReadNext];
    145       Port := R[ReadNext];
    146       if Assigned(FOnOutput) then FOnOutput(Device, Port, R[ReadNext]);
    147     end;
    148     inJump: IP := ReadNext;
    149     inJumpRel: begin
    150       Address := ReadNext;
    151       IP := IP + Address;
    152     end;
    153     inJumpZero: begin
    154       Index := ReadNext;
    155       Address := ReadNext;
    156       if R[Index] = 0 then IP := Address;
    157     end;
    158     inJumpNotZero: begin
    159       Index := ReadNext;
    160       Address := ReadNext;
    161       if R[Index] <> 0 then IP := Address;
    162     end;
    163     inPush: begin
    164       Dec(SP);
    165       Data[SP] := R[ReadNext];
    166     end;
    167     inPop: begin
    168       R[ReadNext] := Data[SP];
    169       Inc(SP);
    170     end;
    171     inCall: begin
    172       Address := ReadNext;
    173       Dec(SP);
    174       Data[SP] := IP;
    175       IP := Address;
    176     end;
    177     inRet: begin
    178       IP := Data[SP];
    179       Inc(SP);
    180     end;
    181     inAnd: begin
    182       Index := ReadNext;
    183       R[Index] := R[Index] and R[ReadNext];
    184     end;
    185     inOr: begin
    186       Index := ReadNext;
    187       R[Index] := R[Index] or R[ReadNext];
    188     end;
    189     inXor: begin
    190       Index := ReadNext;
    191       R[Index] := R[Index] xor R[ReadNext];
    192     end;
    193     inShl: begin
    194       Index := ReadNext;
    195       R[Index] := R[Index] shl R[ReadNext];
    196     end;
    197     inShr: begin
    198       Index := ReadNext;
    199       R[Index] := R[Index] shr R[ReadNext];
    200     end;
    201     inMul: begin
    202       Index := ReadNext;
    203       R[Index] := R[Index] * R[ReadNext];
    204     end;
    205     inDiv: begin
    206       Index := ReadNext;
    207       R[Index] := R[Index] div R[ReadNext];
    208     end;
    209     inMod: begin
    210       Index := ReadNext;
    211       R[Index] := R[Index] mod R[ReadNext];
    212     end;
    213     inLoadIndex: R[ReadNext] := Data[R[ReadNext] + ReadNext];
    214     inStoreIndex: Data[R[ReadNext] + ReadNext] := R[ReadNext];
    215   end;
    216   Inc(Ticks);
     574  if Assigned(FInstructionHandlers[Instruction]) then
     575    FInstructionHandlers[Instruction]
     576    else raise Exception.Create('Missing handler for instruction ' + IntToStr(Integer(Instruction)));
     577  Inc(FTicks);
    217578end;
    218579
     
    243604  I: Integer;
    244605begin
     606  FMemory := FBaseMemory;
    245607  FNextInterupt := -1;
    246608  FHalted := False;
    247   Ticks := 0;
    248   IP := Data[0]; // Reset interrupt vector
    249   SP := Length(Data);
     609  FTicks := 0;
     610  InstructionPointer := FMemory.Base[Integer(siReset)];
     611  StackPointer := FMemory.Size;
    250612  for I := 0 to Length(R) - 1 do
    251613    R[I] := 0;
    252614end;
    253615
     616procedure TCpu.Interrupt(Index: TSystemInterrupt);
     617begin
     618  Interrupt(TInteger(Index));
     619end;
     620
    254621procedure TCpu.Interrupt(Index: TInteger);
    255622begin
     
    260627begin
    261628  SetLength(R, 16);
    262   SetLength(Data, 0);
     629  Memory := nil;
     630  InitInstructions;
    263631end;
    264632
Note: See TracChangeset for help on using the changeset viewer.