unit Instructions;

interface

uses
  Classes, SysUtils, Generics.Collections, Cpu;

type
  TParamType = (ptNone, ptNumber, ptIndirect, ptIndirect2);
  TParamTypeArray = array of TParamType;

  TInstructionInfo = class
    Instruction: TInstruction;
    Name: string;
    Params: TParamTypeArray;
    Description: string;
  end;

  TInstructionInfos = TObjectList<TInstructionInfo>;

  { TInstructionSet }

  TInstructionSet = class
    Items: TInstructionInfos;
    function SearchName(Name: string): TInstructionInfo;
    function SearchInstruction(Instruction: TInstruction): TInstructionInfo;
    function AddNew(Instruction: TInstruction; Name: string;
      Params: TParamTypeArray; Description: string): TInstructionInfo;
    constructor Create;
    destructor Destroy; override;
  end;


implementation

{ TInstructionSet }

function TInstructionSet.SearchName(Name: string): TInstructionInfo;
var
  I: Integer;
begin
  I := 0;
  while (I < Items.Count) and (Items[I].Name <> Name) do Inc(I);
  if I < Items.Count then Result := Items[I]
    else Result := nil;
end;

function TInstructionSet.SearchInstruction(Instruction: TInstruction
  ): TInstructionInfo;
var
  I: Integer;
begin
  I := 0;
  while (I < Items.Count) and (Items[I].Instruction <> Instruction) do Inc(I);
  if I < Items.Count then Result := Items[I]
    else Result := nil;
end;

function TInstructionSet.AddNew(Instruction: TInstruction; Name: string;
  Params: TParamTypeArray; Description: string): TInstructionInfo;
begin
  Result := TInstructionInfo.Create;
  Result.Instruction := Instruction;
  Result.Name := Name;
  Result.Params := Params;
  Result.Description := Description;
  Items.Add(Result);
end;

constructor TInstructionSet.Create;
begin
  Items := TInstructionInfos.Create;
  AddNew(inNop, 'NOP', [], 'No operation - The instruction doesn''t do anything.');
  AddNew(inHalt, 'HALT', [], 'It terminates program execution and halts processor. Processor can be waked up by interrupt.');
  AddNew(inLoadConst, 'LDC', [ptIndirect, ptNumber], 'Loads constant into address location.');
  AddNew(inLoadIndex, 'LDI', [ptIndirect, ptIndirect, ptNumber], 'Loads value from one memory location with added relative index to another.');
  AddNew(inLoad, 'LD', [ptIndirect, ptIndirect], 'Loads value from one memory location to another.');
  AddNew(inLoadMem, 'LDM', [ptIndirect, ptIndirect2], 'Loads value from one indirect memory location to another.');
  AddNew(inStoreMem, 'STM', [ptIndirect2, ptIndirect], 'Stotes value to indirect memory location from source location.');
  AddNew(inIncrement, 'INC', [ptIndirect], 'Increments value in specified register.');
  AddNew(inDecrement, 'DEC', [ptIndirect], 'Decrements value in specified register.');
  AddNew(inInput, 'IN', [ptIndirect, ptIndirect], 'Reads value from input port to register.');
  AddNew(inOutput, 'OUT', [ptIndirect, ptIndirect], 'Writes value from register to output port.');
  AddNew(inJump, 'JP', [ptNumber], 'Unconditional absolute jump to defined address.');
  AddNew(inJumpZero, 'JPZ', [ptIndirect, ptNumber], 'Jumps to absolute address if value of register is zero');
  AddNew(inJumpNotZero, 'JPNZ', [ptIndirect, ptNumber], 'Jumps to absolute address if value of register is not zero');
  AddNew(inJumpRel, 'JR', [ptNumber], 'Unconditional relative jump to defined address.');
  AddNew(inJumpRelZero, 'JRZ', [ptIndirect, ptNumber], 'Jumps to relative address if value of register is zero');
  AddNew(inJumpRelNotZero, 'JRNZ', [ptIndirect, ptNumber], 'Jumps to relative address if value of register is not zero');
  AddNew(inPush, 'PUSH', [ptIndirect], 'Push memory location onto stack.');
  AddNew(inPop, 'POP', [ptIndirect], 'Pop item from stack and store it into memory location.');
  AddNew(inCall, 'CALL', [ptNumber], 'Call subroutine.');
  AddNew(inReturn, 'RET', [], 'Return from subrotine.');
  AddNew(inAdd, 'ADD', [ptIndirect, ptIndirect, ptIndirect], 'Addition of two numbers.');
  AddNew(inSubtract, 'Sub', [ptIndirect, ptIndirect, ptIndirect], 'Subtraction of two numbers.');
  AddNew(inAnd, 'AND', [ptIndirect, ptIndirect, ptIndirect], 'Logical AND operation.');
  AddNew(inOr, 'OR', [ptIndirect, ptIndirect, ptIndirect], 'Logical OR operation.');
  AddNew(inXor, 'XOR', [ptIndirect, ptIndirect, ptIndirect], 'Logical XOR operation.');
  AddNew(inShiftLeft, 'SHL', [ptIndirect, ptIndirect, ptIndirect], 'Bitwise shift to the left.');
  AddNew(inShiftRight, 'SHR', [ptIndirect, ptIndirect, ptIndirect], 'Bitwise shift to the right.');
  AddNew(inBitSet, 'SET', [ptIndirect, ptIndirect, ptIndirect], 'Set specific bit.');
  AddNew(inBitReset, 'RES', [ptIndirect, ptIndirect, ptIndirect], 'Reset specific bit.');
  AddNew(inBitTest, 'BIT', [ptIndirect, ptIndirect, ptIndirect], 'Test of specific bit.');
end;

destructor TInstructionSet.Destroy;
begin
  FreeAndNil(Items);
  inherited;
end;

end.

