source: branches/CpuSingleSize/Machine.pas

Last change on this file was 240, checked in by chronos, 16 months ago
File size: 11.1 KB
Line 
1unit Machine;
2
3interface
4
5uses
6 Classes, SysUtils, Cpu, Syncobjs, Memory, Generics.Collections, Forms;
7
8type
9 TDeviceClass = (dcNone, dcKeyboard, dcMouse, dcStorage, dcScreen, dcConsole,
10 dcTimer);
11 TDeviceClassSet = set of TDeviceClass;
12
13 TDevice = class;
14
15 { TFormDevice }
16
17 TFormDevice = class(TForm)
18 protected
19 function GetDevice: TDevice; virtual;
20 procedure SetDevice(AValue: TDevice); virtual;
21 public
22 property Device: TDevice read GetDevice write SetDevice;
23 end;
24
25 TFormDeviceClass = class of TFormDevice;
26
27 { TDevice }
28
29 TDevice = class
30 Index: Integer;
31 Name: string;
32 DeviceClass: TDeviceClass;
33 Cpu: TCpu;
34 InterruptVector: Integer;
35 Form: TFormDevice;
36 destructor Destroy; override;
37 procedure PulseInterrupt;
38 procedure OutputHandler(Port, Data: TInteger); virtual;
39 function InputHandler(Port: TInteger): TInteger; virtual;
40 end;
41
42 { TDevices }
43
44 TDevices = class(TObjectList<TDevice>)
45 function GetDevicesCountByClass(DeviceClass: TDeviceClass): Integer;
46 function GetDevicesByClass(DeviceClass: TDeviceClass): TDevices;
47 function GetClasses: TDeviceClassSet;
48 end;
49
50 TDeviceManagerOutputPort = (opDeviceManagerClass, opDeviceManagerFirst, opDeviceManagerNext);
51 TDeviceManagerInputPort = (ipDeviceManagerCount, ipDeviceManagerGet);
52
53 { TDeviceManager }
54
55 TDeviceManager = class(TDevice)
56 DeviceClassFilter: TDeviceClass;
57 Index: Integer;
58 Devices: TDevices;
59 constructor Create;
60 procedure OutputHandler(Port, Data: TInteger); override;
61 function InputHandler(Port: TInteger): TInteger; override;
62 end;
63
64 TConsoleInputPort = (ipConsoleReadChar, ipConsoleInputCount);
65 TConsoleOutputPort = (opConsoleWriteChar);
66
67 { TDeviceConsole }
68
69 TDeviceConsole = class(TDevice)
70 Lock: TCriticalSection;
71 InputBuffer: TQueue<TInteger>;
72 OutputBuffer: TQueue<TInteger>;
73 constructor Create;
74 destructor Destroy; override;
75 procedure OutputHandler(Port, Data: TInteger); override;
76 function InputHandler(Port: TInteger): TInteger; override;
77 end;
78
79 TScreenInputPort = (ipScreenGetWidth, ipScreenGetHeight);
80 TScreenOutputPort = (opScreenSetAddr, opScreenWrite);
81
82 { TDeviceScreen }
83
84 TDeviceScreen = class(TDevice)
85 private
86 FSize: TPoint;
87 procedure SetSize(AValue: TPoint);
88 public
89 Address: Integer;
90 VideoMem: array of Byte;
91 Modified: Boolean;
92 constructor Create;
93 procedure OutputHandler(Port, Data: TInteger); override;
94 function InputHandler(Port: TInteger): TInteger; override;
95 property Size: TPoint read FSize write SetSize;
96 end;
97
98 TKeyboardInputPort = (ipKeyboardRead);
99
100 { TDeviceKeyboard }
101
102 TDeviceKeyboard = class(TDevice)
103 constructor Create;
104 function ReadKey: TInteger;
105 function InputHandler(Port: TInteger): TInteger; override;
106 end;
107
108 TStorageInputPort = (ipStorageGetSize, ipStorageRead);
109 TStorageOutputPort = (opStorageSetAddr, opStorageWrite);
110
111 { TDeviceStorage }
112
113 TDeviceStorage = class(TDevice)
114 public
115 F: TFileStream;
116 FileName: string;
117 constructor Create;
118 procedure OutputHandler(Port, Data: TInteger); override;
119 function InputHandler(Port: TInteger): TInteger; override;
120 end;
121
122 { TDeviceMouse }
123
124 TDeviceMouse = class(TDevice)
125 constructor Create;
126 end;
127
128 TTimerOutputPort = (opTimerSetInterval, opTimerSetEnabled);
129 { TDeviceTimer }
130
131 TDeviceTimer = class(TDevice)
132 Interval: Integer;
133 Enabled: Boolean;
134 constructor Create;
135 procedure OutputHandler(Port, Data: TInteger); override;
136 end;
137
138 { TMachine }
139
140 TMachine = class
141 private
142 procedure OutputHandler(Device, Port, Data: TInteger);
143 function InputHandler(Device, Port: TInteger): TInteger;
144 public
145 Memory: TMemory;
146 Cpu: TCpu;
147 Devices: TDevices;
148 procedure RegisterDevice(Device: TDevice);
149 procedure InitDevices;
150 procedure PowerOn;
151 procedure PowerOff;
152 constructor Create;
153 destructor Destroy; override;
154 end;
155
156const
157 DeviceClassText: array[TDeviceClass] of string = ('None', 'Keyboard', 'Mouse', 'Storage', 'Screen', 'Console', 'Timer');
158
159
160implementation
161
162{ TDeviceTimer }
163
164constructor TDeviceTimer.Create;
165begin
166 DeviceClass := dcTimer;
167end;
168
169procedure TDeviceTimer.OutputHandler(Port, Data: TInteger);
170begin
171 case TTimerOutputPort(Port) of
172 opTimerSetInterval: Interval := Data;
173 opTimerSetEnabled: Enabled := Data > 0;
174 end;
175end;
176
177{ TDeviceManager }
178
179constructor TDeviceManager.Create;
180begin
181 DeviceClass := dcNone;
182end;
183
184procedure TDeviceManager.OutputHandler(Port, Data: TInteger);
185begin
186 case TDeviceManagerOutputPort(Port) of
187 opDeviceManagerClass: DeviceClassFilter := TDeviceClass(Data);
188 opDeviceManagerFirst: Index := 0;
189 opDeviceManagerNext: Inc(Index);
190 end;
191end;
192
193function TDeviceManager.InputHandler(Port: TInteger): TInteger;
194var
195 ClassDevices: TDevices;
196begin
197 case TDeviceManagerInputPort(Port) of
198 ipDeviceManagerCount: Result := Devices.Count;
199 ipDeviceManagerGet: begin
200 ClassDevices := Devices.GetDevicesByClass(DeviceClassFilter);
201 if (Index >= 0) and (Index < ClassDevices.Count) then
202 Result := ClassDevices[Index].Index
203 else Result := 0;
204 ClassDevices.Free;
205 end;
206 end;
207end;
208
209{ TFormDevice }
210
211function TFormDevice.GetDevice: TDevice;
212begin
213 Result := nil;
214end;
215
216procedure TFormDevice.SetDevice(AValue: TDevice);
217begin
218end;
219
220{ TDevices }
221
222function TDevices.GetDevicesCountByClass(DeviceClass: TDeviceClass): Integer;
223var
224 I: Integer;
225begin
226 Result := 0;
227 for I := 0 to Count - 1 do
228 if Items[I].DeviceClass = DeviceClass then Inc(Result);
229end;
230
231function TDevices.GetDevicesByClass(DeviceClass: TDeviceClass): TDevices;
232var
233 I: Integer;
234begin
235 Result := TDevices.Create(False);
236 for I := 0 to Count - 1 do
237 if Items[I].DeviceClass = DeviceClass then Result.Add(Items[I])
238end;
239
240function TDevices.GetClasses: TDeviceClassSet;
241var
242 I: Integer;
243begin
244 Result := [];
245 for I := 0 to Count - 1 do
246 if not (Items[I].DeviceClass in Result) then
247 Result := Result + [Items[I].DeviceClass];
248end;
249
250{ TDevice }
251
252destructor TDevice.Destroy;
253begin
254 if Assigned(Form) then FreeAndNil(Form);
255 inherited;
256end;
257
258procedure TDevice.PulseInterrupt;
259begin
260 Cpu.Interrupt(InterruptVector);
261end;
262
263procedure TDevice.OutputHandler(Port, Data: TInteger);
264begin
265end;
266
267function TDevice.InputHandler(Port: TInteger): TInteger;
268begin
269 Result := 0;
270end;
271
272{ TDeviceMouse }
273
274constructor TDeviceMouse.Create;
275begin
276 DeviceClass := dcMouse;
277end;
278
279{ TDeviceStorage }
280
281constructor TDeviceStorage.Create;
282begin
283 DeviceClass := dcStorage;
284end;
285
286procedure TDeviceStorage.OutputHandler(Port, Data: TInteger);
287begin
288 case TStorageOutputPort(Port) of
289 opStorageSetAddr: F.Position := Data * SizeOf(TInteger);
290 opStorageWrite: begin
291 F.WriteBuffer(Data, SizeOf(TInteger));
292 end;
293 end;
294end;
295
296function TDeviceStorage.InputHandler(Port: TInteger): TInteger;
297begin
298 case TStorageInputPort(Port) of
299 ipStorageGetSize: Result := F.Size div 4;
300 ipStorageRead: begin
301 F.ReadBuffer(Result, SizeOf(TInteger));
302 end;
303 end;
304end;
305
306{ TDeviceConsole }
307
308constructor TDeviceConsole.Create;
309begin
310 DeviceClass := dcConsole;
311 Lock := TCriticalSection.Create;
312 InputBuffer := TQueue<TInteger>.Create;
313 OutputBuffer := TQueue<TInteger>.Create;
314end;
315
316destructor TDeviceConsole.Destroy;
317begin
318 InputBuffer.Free;
319 OutputBuffer.Free;
320 Lock.Free;
321 inherited;
322end;
323
324procedure TDeviceConsole.OutputHandler(Port, Data: TInteger);
325begin
326 case TConsoleOutputPort(Port) of
327 opConsoleWriteChar: begin
328 Lock.Acquire;
329 try
330 OutputBuffer.Enqueue(Data);
331 finally
332 Lock.Release;
333 end;
334 end;
335 end;
336end;
337
338function TDeviceConsole.InputHandler(Port: TInteger): TInteger;
339begin
340 case TConsoleInputPort(Port) of
341 ipConsoleReadChar: begin
342 Lock.Acquire;
343 try
344 if InputBuffer.Count > 0 then begin
345 Result := InputBuffer.Dequeue;
346 end else Result := 0;
347 finally
348 Lock.Release;
349 end;
350 end;
351 ipConsoleInputCount: begin
352 Lock.Acquire;
353 try
354 Result := InputBuffer.Count;
355 finally
356 Lock.Release;
357 end;
358 end;
359 end;
360end;
361
362{ TDeviceScreen }
363
364procedure TDeviceScreen.SetSize(AValue: TPoint);
365begin
366 if FSize = AValue then Exit;
367 FSize := AValue;
368 SetLength(VideoMem, FSize.X * FSize.Y);
369end;
370
371constructor TDeviceScreen.Create;
372begin
373 DeviceClass := dcScreen;
374 Size := Point(640, 480);
375end;
376
377procedure TDeviceScreen.OutputHandler(Port, Data: TInteger);
378begin
379 case TScreenOutputPort(Port) of
380 opScreenSetAddr: Address := Data;
381 opScreenWrite: if (Address >= 0) and (Address < Length(VideoMem)) then begin
382 VideoMem[Address] := Data;
383 Inc(Address);
384 Modified := True;
385 end;
386 end;
387end;
388
389function TDeviceScreen.InputHandler(Port: TInteger): TInteger;
390begin
391 case TScreenInputPort(Port) of
392 ipScreenGetWidth: Result := Size.X;
393 ipScreenGetHeight: Result := Size.Y;
394 end;
395end;
396
397{ TDeviceKeyboard }
398
399function TDeviceKeyboard.ReadKey: TInteger;
400begin
401 Result := 0;
402end;
403
404function TDeviceKeyboard.InputHandler(Port: TInteger): TInteger;
405begin
406 case TKeyboardInputPort(Port) of
407 ipKeyboardRead: Result := ReadKey;
408 end;
409end;
410
411constructor TDeviceKeyboard.Create;
412begin
413 DeviceClass := dcKeyboard;
414end;
415
416{ TMachine }
417
418procedure TMachine.OutputHandler(Device, Port, Data: TInteger);
419begin
420 if (Device > 0) and (Device < Devices.Count) then
421 Devices[Device].OutputHandler(Port, Data);
422end;
423
424function TMachine.InputHandler(Device, Port: TInteger): TInteger;
425begin
426 if (Device > 0) and (Device < Devices.Count) then
427 Result := Devices[Device].InputHandler(Port)
428 else Result := 0;
429end;
430
431procedure TMachine.RegisterDevice(Device: TDevice);
432begin
433 Device.Index := Devices.Count;
434 Device.Cpu := Cpu;
435 Device.Name := DeviceClassText[Device.DeviceClass] + ' ' +
436 IntToStr(Devices.GetDevicesCountByClass(Device.DeviceClass) + 1);
437 Devices.Add(Device);
438end;
439
440procedure TMachine.InitDevices;
441var
442 Screen: TDeviceScreen;
443 Keyboard: TDeviceKeyboard;
444 Console: TDeviceConsole;
445 Storage: TDeviceStorage;
446 Mouse: TDeviceMouse;
447 DeviceManager: TDeviceManager;
448 Timer: TDeviceTimer;
449begin
450 DeviceManager := TDeviceManager.Create;
451 DeviceManager.Devices := Devices;
452 RegisterDevice(DeviceManager);
453
454 Console := TDeviceConsole.Create;
455 RegisterDevice(Console);
456 Console.InterruptVector := 1;
457
458 Keyboard := TDeviceKeyboard.Create;
459 Keyboard.InterruptVector := 4;
460 RegisterDevice(Keyboard);
461
462 Screen := TDeviceScreen.Create;
463 RegisterDevice(Screen);
464
465 Storage := TDeviceStorage.Create;
466 RegisterDevice(Storage);
467
468 Storage := TDeviceStorage.Create;
469 RegisterDevice(Storage);
470
471 Mouse := TDeviceMouse.Create;
472 Mouse.InterruptVector := 3;
473 RegisterDevice(Mouse);
474
475 Timer := TDeviceTimer.Create;
476 Timer.InterruptVector := 2;
477 RegisterDevice(Timer);
478end;
479
480procedure TMachine.PowerOn;
481begin
482 Cpu.Memory := Memory.Data;
483 Cpu.Start;
484end;
485
486procedure TMachine.PowerOff;
487begin
488 Cpu.Stop;
489end;
490
491constructor TMachine.Create;
492begin
493 Devices := TDevices.Create;
494 Memory := TMemory.Create;
495 Memory.Size := 10000;
496 Cpu := TCpu.Create;
497 Cpu.OnInput := InputHandler;
498 Cpu.OnOutput := OutputHandler;
499 InitDevices;
500end;
501
502destructor TMachine.Destroy;
503begin
504 PowerOff;
505 FreeAndNil(Cpu);
506 FreeAndNil(Memory);
507 FreeAndNil(Devices);
508 inherited;
509end;
510
511end.
512
Note: See TracBrowser for help on using the repository browser.