Changeset 220 for branches/CpuSingleSize/UMachine.pas
- Timestamp:
- Oct 20, 2020, 1:10:09 AM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/CpuSingleSize/UMachine.pas
r216 r220 6 6 7 7 uses 8 Classes, SysUtils, UCpu, Syncobjs, UMemory, Generics.Collections ;8 Classes, SysUtils, UCpu, Syncobjs, UMemory, Generics.Collections, Forms; 9 9 10 10 type 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 } 15 29 16 30 TDevice = class 31 Index: Integer; 32 Name: string; 33 DeviceClass: TDeviceClass; 17 34 Cpu: TCpu; 18 35 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); 20 65 21 66 { TConsole } … … 27 72 constructor Create; 28 73 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); 30 80 31 81 { TScreen } … … 37 87 public 38 88 Address: Integer; 39 Data: array of Byte;89 VideoMem: array of Byte; 40 90 Modified: Boolean; 41 91 constructor Create; 92 procedure OutputHandler(Port, Data: TInteger); override; 93 function InputHandler(Port: TInteger): TInteger; override; 42 94 property Size: TPoint read FSize write SetSize; 43 95 end; 44 96 97 TKeyboardInputPort = (ipKeyboardRead); 98 45 99 { TKeyboard } 46 100 47 101 TKeyboard = class(TDevice) 102 constructor Create; 48 103 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 } 50 111 51 112 TStorage = class(TDevice) … … 53 114 F: TFileStream; 54 115 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; 55 125 end; 56 126 … … 59 129 TMachine = class 60 130 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; 63 133 public 64 134 Memory: TMemory; 65 135 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; 70 139 procedure PowerOn; 71 140 procedure PowerOff; … … 74 143 end; 75 144 145 const 146 DeviceClassText: array[TDeviceClass] of string = ('None', 'Keyboard', 'Mouse', 'Storage', 'Screen', 'Console'); 147 76 148 77 149 implementation 78 150 151 { TDeviceManager } 152 153 constructor TDeviceManager.Create; 154 begin 155 DeviceClass := dcNone; 156 end; 157 158 procedure TDeviceManager.OutputHandler(Port, Data: TInteger); 159 begin 160 case TDeviceManagerOutputPort(Port) of 161 opDeviceManagerClass: DeviceClassFilter := TDeviceClass(Data); 162 opDeviceManagerFirst: Index := 0; 163 opDeviceManagerNext: Inc(Index); 164 end; 165 end; 166 167 function TDeviceManager.InputHandler(Port: TInteger): TInteger; 168 var 169 ClassDevices: TDevices; 170 begin 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; 181 end; 182 183 { TFormDevice } 184 185 function TFormDevice.GetDevice: TDevice; 186 begin 187 Result := nil; 188 end; 189 190 procedure TFormDevice.SetDevice(AValue: TDevice); 191 begin 192 end; 193 194 195 { TDevices } 196 197 function TDevices.GetDevicesCountByClass(DeviceClass: TDeviceClass): Integer; 198 var 199 I: Integer; 200 begin 201 Result := 0; 202 for I := 0 to Count - 1 do 203 if Items[I].DeviceClass = DeviceClass then Inc(Result); 204 end; 205 206 function TDevices.GetDevicesByClass(DeviceClass: TDeviceClass): TDevices; 207 var 208 I: Integer; 209 begin 210 Result := TDevices.Create(False); 211 for I := 0 to Count - 1 do 212 if Items[I].DeviceClass = DeviceClass then Result.Add(Items[I]) 213 end; 214 215 function TDevices.GetClasses: TDeviceClassSet; 216 var 217 I: Integer; 218 begin 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]; 223 end; 224 225 { TDevice } 226 227 procedure TDevice.OutputHandler(Port, Data: TInteger); 228 begin 229 end; 230 231 function TDevice.InputHandler(Port: TInteger): TInteger; 232 begin 233 Result := 0; 234 end; 235 236 { TMouse } 237 238 constructor TMouse.Create; 239 begin 240 DeviceClass := dcMouse; 241 end; 242 243 { TStorage } 244 245 constructor TStorage.Create; 246 begin 247 DeviceClass := dcStorage; 248 end; 249 250 procedure TStorage.OutputHandler(Port, Data: TInteger); 251 begin 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; 258 end; 259 260 function TStorage.InputHandler(Port: TInteger): TInteger; 261 begin 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; 268 end; 269 79 270 { TConsole } 80 271 81 272 constructor TConsole.Create; 82 273 begin 274 DeviceClass := dcConsole; 83 275 Lock := TCriticalSection.Create; 84 276 InputBuffer := TQueue<TInteger>.Create; … … 94 286 end; 95 287 288 procedure TConsole.OutputHandler(Port, Data: TInteger); 289 begin 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; 300 end; 301 302 function TConsole.InputHandler(Port: TInteger): TInteger; 303 begin 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; 324 end; 325 96 326 { TScreen } 97 327 … … 100 330 if FSize = AValue then Exit; 101 331 FSize := AValue; 102 SetLength( Data, FSize.X * FSize.Y);332 SetLength(VideoMem, FSize.X * FSize.Y); 103 333 end; 104 334 105 335 constructor TScreen.Create; 106 336 begin 337 DeviceClass := dcScreen; 107 338 Size := Point(640, 480); 108 339 end; 109 340 341 procedure TScreen.OutputHandler(Port, Data: TInteger); 342 begin 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; 351 end; 352 353 function TScreen.InputHandler(Port: TInteger): TInteger; 354 begin 355 case TScreenInputPort(Port) of 356 ipScreenGetWidth: Result := Size.X; 357 ipScreenGetHeight: Result := Size.Y; 358 end; 359 end; 360 110 361 { TKeyboard } 111 362 … … 115 366 end; 116 367 368 function TKeyboard.InputHandler(Port: TInteger): TInteger; 369 begin 370 case TKeyboardInputPort(Port) of 371 ipKeyboardRead: Result := ReadKey; 372 end; 373 end; 374 375 constructor TKeyboard.Create; 376 begin 377 DeviceClass := dcKeyboard; 378 end; 379 117 380 { TMachine } 118 381 119 procedure TMachine.OutputHandler( Port, Data: TInteger);120 begin 121 case TOutputPort(Port) of122 opConsoleWriteChar: begin123 Console.Lock.Acquire;124 try 125 Console.OutputBuffer.Enqueue(Data);126 finally 127 Console.Lock.Release;128 end;129 e nd;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: begin138 Storage.F.WriteBuffer(Data, SizeOf(TInteger));139 140 end; 141 end;142 143 function TMachine.InputHandler(Port: TInteger): TInteger;144 begin 145 case TInputPort(Port) of146 ipConsoleReadChar: begin147 Console.Lock.Acquire;148 try149 if Console.InputBuffer.Count > 0 thenbegin150 Result := Console.InputBuffer.Dequeue;151 end else Result := 0;152 finally153 Console.Lock.Release; 154 end;155 end;156 ipConsoleInputCount: begin157 Console.Lock.Acquire; 158 try159 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: begin169 Storage.F.ReadBuffer(Result, SizeOf(TInteger)); 170 end;171 end;382 procedure TMachine.OutputHandler(Device, Port, Data: TInteger); 383 begin 384 if (Device > 0) and (Device < Devices.Count) then 385 Devices[Device].OutputHandler(Port, Data); 386 end; 387 388 function TMachine.InputHandler(Device, Port: TInteger): TInteger; 389 begin 390 if (Device > 0) and (Device < Devices.Count) then 391 Result := Devices[Device].InputHandler(Port) 392 else Result := 0; 393 end; 394 395 procedure TMachine.RegisterDevice(Device: TDevice); 396 begin 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); 402 end; 403 404 procedure TMachine.InitDevices; 405 var 406 Screen: TScreen; 407 Keyboard: TKeyboard; 408 Console: TConsole; 409 Storage: TStorage; 410 Mouse: TMouse; 411 DeviceManager: TDeviceManager; 412 begin 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); 172 435 end; 173 436 … … 185 448 constructor TMachine.Create; 186 449 begin 450 Devices := TDevices.Create; 187 451 Memory := TMemory.Create; 188 452 Memory.Size := 10000; … … 190 454 Cpu.OnInput := InputHandler; 191 455 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; 201 457 end; 202 458 … … 204 460 begin 205 461 PowerOff; 206 FreeAndNil(Storage); 207 FreeAndNil(Console); 208 FreeAndNil(Screen); 209 FreeAndNil(Keyboard); 210 FreeAndNil(Cpu); 211 FreeAndNil(Memory); 462 FreeAndNil(Devices); 212 463 inherited; 213 464 end;
Note:
See TracChangeset
for help on using the changeset viewer.