Ignore:
Timestamp:
Oct 20, 2020, 1:10:09 AM (4 years ago)
Author:
chronos
Message:
  • Added: Devices form with tree view of connected devices. Device control form can be opened by double click.
  • Modifid: IN/OUT instructions now use also device group index to directly specify which device should be read/written.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/CpuSingleSize/UMachine.pas

    r216 r220  
    66
    77uses
    8   Classes, SysUtils, UCpu, Syncobjs, UMemory, Generics.Collections;
     8  Classes, SysUtils, UCpu, Syncobjs, UMemory, Generics.Collections, Forms;
    99
    1010type
    11   TInputPort = (ipConsoleReadChar, ipConsoleInputCount, ipKeyboardRead,
    12     ipScreenGetWidth, ipScreenGetHeight, ipStorageGetSize, ipStorageRead);
    13   TOutputPort = (opConsoleWriteChar, opScreenSetAddr, opScreenWrite,
    14     opStorageSetAddr, opStorageWrite);
     11  TDeviceClass = (dcNone, dcKeyboard, dcMouse, dcStorage, dcScreen, dcConsole);
     12  TDeviceClassSet = set of TDeviceClass;
     13
     14  TDevice = class;
     15
     16  { TFormDevice }
     17
     18  TFormDevice = class(TForm)
     19  protected
     20    function GetDevice: TDevice; virtual;
     21    procedure SetDevice(AValue: TDevice); virtual;
     22  public
     23    property Device: TDevice read GetDevice write SetDevice;
     24  end;
     25
     26  TFormDeviceClass = class of TFormDevice;
     27
     28  { TDevice }
    1529
    1630  TDevice = class
     31    Index: Integer;
     32    Name: string;
     33    DeviceClass: TDeviceClass;
    1734    Cpu: TCpu;
    1835    InterruptVector: Integer;
    19   end;
     36    Form: TFormDevice;
     37    procedure OutputHandler(Port, Data: TInteger); virtual;
     38    function InputHandler(Port: TInteger): TInteger; virtual;
     39  end;
     40
     41  { TDevices }
     42
     43  TDevices = class(TObjectList<TDevice>)
     44    function GetDevicesCountByClass(DeviceClass: TDeviceClass): Integer;
     45    function GetDevicesByClass(DeviceClass: TDeviceClass): TDevices;
     46    function GetClasses: TDeviceClassSet;
     47  end;
     48
     49  TDeviceManagerOutputPort = (opDeviceManagerClass, opDeviceManagerFirst, opDeviceManagerNext);
     50  TDeviceManagerInputPort = (ipDeviceManagerCount, ipDeviceManagerGet);
     51
     52  { TDeviceManager }
     53
     54  TDeviceManager = class(TDevice)
     55    DeviceClassFilter: TDeviceClass;
     56    Index: Integer;
     57    Devices: TDevices;
     58    constructor Create;
     59    procedure OutputHandler(Port, Data: TInteger); override;
     60    function InputHandler(Port: TInteger): TInteger; override;
     61  end;
     62
     63  TConsoleInputPort = (ipConsoleReadChar, ipConsoleInputCount);
     64  TConsoleOutputPort = (opConsoleWriteChar);
    2065
    2166  { TConsole }
     
    2772    constructor Create;
    2873    destructor Destroy; override;
    29   end;
     74    procedure OutputHandler(Port, Data: TInteger); override;
     75    function InputHandler(Port: TInteger): TInteger; override;
     76  end;
     77
     78  TScreenInputPort = (ipScreenGetWidth, ipScreenGetHeight);
     79  TScreenOutputPort = (opScreenSetAddr, opScreenWrite);
    3080
    3181  { TScreen }
     
    3787  public
    3888    Address: Integer;
    39     Data: array of Byte;
     89    VideoMem: array of Byte;
    4090    Modified: Boolean;
    4191    constructor Create;
     92    procedure OutputHandler(Port, Data: TInteger); override;
     93    function InputHandler(Port: TInteger): TInteger; override;
    4294    property Size: TPoint read FSize write SetSize;
    4395  end;
    4496
     97  TKeyboardInputPort = (ipKeyboardRead);
     98
    4599  { TKeyboard }
    46100
    47101  TKeyboard = class(TDevice)
     102    constructor Create;
    48103    function ReadKey: TInteger;
    49   end;
     104    function InputHandler(Port: TInteger): TInteger; override;
     105  end;
     106
     107  TStorageInputPort = (ipStorageGetSize, ipStorageRead);
     108  TStorageOutputPort = (opStorageSetAddr, opStorageWrite);
     109
     110  { TStorage }
    50111
    51112  TStorage = class(TDevice)
     
    53114    F: TFileStream;
    54115    FileName: string;
     116    constructor Create;
     117    procedure OutputHandler(Port, Data: TInteger); override;
     118    function InputHandler(Port: TInteger): TInteger; override;
     119  end;
     120
     121  { TMouse }
     122
     123  TMouse = class(TDevice)
     124    constructor Create;
    55125  end;
    56126
     
    59129  TMachine = class
    60130  private
    61     procedure OutputHandler(Port, Data: TInteger);
    62     function InputHandler(Port: TInteger): TInteger;
     131    procedure OutputHandler(Device, Port, Data: TInteger);
     132    function InputHandler(Device, Port: TInteger): TInteger;
    63133  public
    64134    Memory: TMemory;
    65135    Cpu: TCpu;
    66     Screen: TScreen;
    67     Keyboard: TKeyboard;
    68     Console: TConsole;
    69     Storage: TStorage;
     136    Devices: TDevices;
     137    procedure RegisterDevice(Device: TDevice);
     138    procedure InitDevices;
    70139    procedure PowerOn;
    71140    procedure PowerOff;
     
    74143  end;
    75144
     145const
     146  DeviceClassText: array[TDeviceClass] of string = ('None', 'Keyboard', 'Mouse', 'Storage', 'Screen', 'Console');
     147
    76148
    77149implementation
    78150
     151{ TDeviceManager }
     152
     153constructor TDeviceManager.Create;
     154begin
     155  DeviceClass := dcNone;
     156end;
     157
     158procedure TDeviceManager.OutputHandler(Port, Data: TInteger);
     159begin
     160  case TDeviceManagerOutputPort(Port) of
     161    opDeviceManagerClass: DeviceClassFilter := TDeviceClass(Data);
     162    opDeviceManagerFirst: Index := 0;
     163    opDeviceManagerNext: Inc(Index);
     164  end;
     165end;
     166
     167function TDeviceManager.InputHandler(Port: TInteger): TInteger;
     168var
     169  ClassDevices: TDevices;
     170begin
     171  case TDeviceManagerInputPort(Port) of
     172    ipDeviceManagerCount: Result := Devices.Count;
     173    ipDeviceManagerGet: begin
     174      ClassDevices := Devices.GetDevicesByClass(DeviceClassFilter);
     175      if (Index >= 0) and (Index < ClassDevices.Count) then
     176        Result := ClassDevices[Index].Index
     177        else Result := 0;
     178      ClassDevices.Free;
     179    end;
     180  end;
     181end;
     182
     183{ TFormDevice }
     184
     185function TFormDevice.GetDevice: TDevice;
     186begin
     187  Result := nil;
     188end;
     189
     190procedure TFormDevice.SetDevice(AValue: TDevice);
     191begin
     192end;
     193
     194
     195{ TDevices }
     196
     197function TDevices.GetDevicesCountByClass(DeviceClass: TDeviceClass): Integer;
     198var
     199  I: Integer;
     200begin
     201  Result := 0;
     202  for I := 0 to Count - 1 do
     203    if Items[I].DeviceClass = DeviceClass then Inc(Result);
     204end;
     205
     206function TDevices.GetDevicesByClass(DeviceClass: TDeviceClass): TDevices;
     207var
     208  I: Integer;
     209begin
     210  Result := TDevices.Create(False);
     211  for I := 0 to Count - 1 do
     212    if Items[I].DeviceClass = DeviceClass then Result.Add(Items[I])
     213end;
     214
     215function TDevices.GetClasses: TDeviceClassSet;
     216var
     217  I: Integer;
     218begin
     219  Result := [];
     220  for I := 0 to Count - 1 do
     221    if not (Items[I].DeviceClass in Result) then
     222      Result := Result + [Items[I].DeviceClass];
     223end;
     224
     225{ TDevice }
     226
     227procedure TDevice.OutputHandler(Port, Data: TInteger);
     228begin
     229end;
     230
     231function TDevice.InputHandler(Port: TInteger): TInteger;
     232begin
     233  Result := 0;
     234end;
     235
     236{ TMouse }
     237
     238constructor TMouse.Create;
     239begin
     240  DeviceClass := dcMouse;
     241end;
     242
     243{ TStorage }
     244
     245constructor TStorage.Create;
     246begin
     247  DeviceClass := dcStorage;
     248end;
     249
     250procedure TStorage.OutputHandler(Port, Data: TInteger);
     251begin
     252  case TStorageOutputPort(Port) of
     253    opStorageSetAddr: F.Position := Data * SizeOf(TInteger);
     254    opStorageWrite: begin
     255      F.WriteBuffer(Data, SizeOf(TInteger));
     256    end;
     257  end;
     258end;
     259
     260function TStorage.InputHandler(Port: TInteger): TInteger;
     261begin
     262  case TStorageInputPort(Port) of
     263    ipStorageGetSize: Result := F.Size div 4;
     264    ipStorageRead: begin
     265      F.ReadBuffer(Result, SizeOf(TInteger));
     266    end;
     267  end;
     268end;
     269
    79270{ TConsole }
    80271
    81272constructor TConsole.Create;
    82273begin
     274  DeviceClass := dcConsole;
    83275  Lock := TCriticalSection.Create;
    84276  InputBuffer := TQueue<TInteger>.Create;
     
    94286end;
    95287
     288procedure TConsole.OutputHandler(Port, Data: TInteger);
     289begin
     290  case TConsoleOutputPort(Port) of
     291    opConsoleWriteChar: begin
     292      Lock.Acquire;
     293      try
     294        OutputBuffer.Enqueue(Data);
     295      finally
     296        Lock.Release;
     297      end;
     298    end;
     299  end;
     300end;
     301
     302function TConsole.InputHandler(Port: TInteger): TInteger;
     303begin
     304  case TConsoleInputPort(Port) of
     305    ipConsoleReadChar: begin
     306      Lock.Acquire;
     307      try
     308        if InputBuffer.Count > 0 then begin
     309          Result := InputBuffer.Dequeue;
     310        end else Result := 0;
     311      finally
     312        Lock.Release;
     313      end;
     314    end;
     315    ipConsoleInputCount: begin
     316      Lock.Acquire;
     317      try
     318        Result := InputBuffer.Count;
     319      finally
     320        Lock.Release;
     321      end;
     322    end;
     323  end;
     324end;
     325
    96326{ TScreen }
    97327
     
    100330  if FSize = AValue then Exit;
    101331  FSize := AValue;
    102   SetLength(Data, FSize.X * FSize.Y);
     332  SetLength(VideoMem, FSize.X * FSize.Y);
    103333end;
    104334
    105335constructor TScreen.Create;
    106336begin
     337  DeviceClass := dcScreen;
    107338  Size := Point(640, 480);
    108339end;
    109340
     341procedure TScreen.OutputHandler(Port, Data: TInteger);
     342begin
     343  case TScreenOutputPort(Port) of
     344    opScreenSetAddr: Address := Data;
     345    opScreenWrite: if (Address >= 0) and (Address < Length(VideoMem)) then begin
     346      VideoMem[Address] := Data;
     347      Inc(Address);
     348      Modified := True;
     349    end;
     350  end;
     351end;
     352
     353function TScreen.InputHandler(Port: TInteger): TInteger;
     354begin
     355  case TScreenInputPort(Port) of
     356    ipScreenGetWidth: Result := Size.X;
     357    ipScreenGetHeight: Result := Size.Y;
     358  end;
     359end;
     360
    110361{ TKeyboard }
    111362
     
    115366end;
    116367
     368function TKeyboard.InputHandler(Port: TInteger): TInteger;
     369begin
     370  case TKeyboardInputPort(Port) of
     371    ipKeyboardRead: Result := ReadKey;
     372  end;
     373end;
     374
     375constructor TKeyboard.Create;
     376begin
     377  DeviceClass := dcKeyboard;
     378end;
     379
    117380{ TMachine }
    118381
    119 procedure TMachine.OutputHandler(Port, Data: TInteger);
    120 begin
    121   case TOutputPort(Port) of
    122     opConsoleWriteChar: begin
    123       Console.Lock.Acquire;
    124       try
    125         Console.OutputBuffer.Enqueue(Data);
    126       finally
    127         Console.Lock.Release;
    128       end;
    129     end;
    130     opScreenSetAddr: Screen.Address := Data;
    131     opScreenWrite: if (Screen.Address >= 0) and (Screen.Address < Length(Screen.Data)) then begin
    132       Screen.Data[Screen.Address] := Data;
    133       Inc(Screen.Address);
    134       Screen.Modified := True;
    135     end;
    136     opStorageSetAddr: Storage.F.Position := Data * SizeOf(TInteger);
    137     opStorageWrite: begin
    138       Storage.F.WriteBuffer(Data, SizeOf(TInteger));
    139     end;
    140   end;
    141 end;
    142 
    143 function TMachine.InputHandler(Port: TInteger): TInteger;
    144 begin
    145   case TInputPort(Port) of
    146     ipConsoleReadChar: begin
    147       Console.Lock.Acquire;
    148       try
    149         if Console.InputBuffer.Count > 0 then begin
    150           Result := Console.InputBuffer.Dequeue;
    151         end else Result := 0;
    152       finally
    153         Console.Lock.Release;
    154       end;
    155     end;
    156     ipConsoleInputCount: begin
    157       Console.Lock.Acquire;
    158       try
    159         Result := Console.InputBuffer.Count;
    160       finally
    161         Console.Lock.Release;
    162       end;
    163     end;
    164     ipKeyboardRead: Result := Keyboard.ReadKey;
    165     ipScreenGetWidth: Result := Screen.Size.X;
    166     ipScreenGetHeight: Result := Screen.Size.Y;
    167     ipStorageGetSize: Result := Storage.F.Size div 4;
    168     ipStorageRead: begin
    169       Storage.F.ReadBuffer(Result, SizeOf(TInteger));
    170     end;
    171   end;
     382procedure TMachine.OutputHandler(Device, Port, Data: TInteger);
     383begin
     384  if (Device > 0) and (Device < Devices.Count) then
     385    Devices[Device].OutputHandler(Port, Data);
     386end;
     387
     388function TMachine.InputHandler(Device, Port: TInteger): TInteger;
     389begin
     390  if (Device > 0) and (Device < Devices.Count) then
     391    Result := Devices[Device].InputHandler(Port)
     392    else Result := 0;
     393end;
     394
     395procedure TMachine.RegisterDevice(Device: TDevice);
     396begin
     397  Device.Index := Devices.Count;
     398  Device.Cpu := Cpu;
     399  Device.Name := DeviceClassText[Device.DeviceClass] + ' ' +
     400    IntToStr(Devices.GetDevicesCountByClass(Device.DeviceClass) + 1);
     401  Devices.Add(Device);
     402end;
     403
     404procedure TMachine.InitDevices;
     405var
     406  Screen: TScreen;
     407  Keyboard: TKeyboard;
     408  Console: TConsole;
     409  Storage: TStorage;
     410  Mouse: TMouse;
     411  DeviceManager: TDeviceManager;
     412begin
     413  DeviceManager := TDeviceManager.Create;
     414  DeviceManager.Devices := Devices;
     415  RegisterDevice(DeviceManager);
     416
     417  Console := TConsole.Create;
     418  RegisterDevice(Console);
     419  Console.InterruptVector := 1;
     420
     421  Keyboard := TKeyboard.Create;
     422  RegisterDevice(Keyboard);
     423
     424  Screen := TScreen.Create;
     425  RegisterDevice(Screen);
     426
     427  Storage := TStorage.Create;
     428  RegisterDevice(Storage);
     429
     430  Storage := TStorage.Create;
     431  RegisterDevice(Storage);
     432
     433  Mouse := TMouse.Create;
     434  RegisterDevice(Mouse);
    172435end;
    173436
     
    185448constructor TMachine.Create;
    186449begin
     450  Devices := TDevices.Create;
    187451  Memory := TMemory.Create;
    188452  Memory.Size := 10000;
     
    190454  Cpu.OnInput := InputHandler;
    191455  Cpu.OnOutput := OutputHandler;
    192   Keyboard := TKeyboard.Create;
    193   Keyboard.Cpu := Cpu;
    194   Screen := TScreen.Create;
    195   Screen.Cpu := Cpu;
    196   Console := TConsole.Create;
    197   Console.Cpu := Cpu;
    198   Console.InterruptVector := 1;
    199   Storage := TStorage.Create;
    200   Storage.Cpu := Cpu;
     456  InitDevices;
    201457end;
    202458
     
    204460begin
    205461  PowerOff;
    206   FreeAndNil(Storage);
    207   FreeAndNil(Console);
    208   FreeAndNil(Screen);
    209   FreeAndNil(Keyboard);
    210   FreeAndNil(Cpu);
    211   FreeAndNil(Memory);
     462  FreeAndNil(Devices);
    212463  inherited;
    213464end;
Note: See TracChangeset for help on using the changeset viewer.