source: branches/UltimatOS/UMachine.pas

Last change on this file was 34, checked in by chronos, 23 months ago
  • Modified: Execute instructions as array of instruction handlers.
  • Modified: Optimized some methods call with inline directive.
File size: 7.1 KB
Line 
1unit UMachine;
2
3interface
4
5uses
6 Classes, SysUtils, UCpu, UMemory, ExtCtrls;
7
8type
9 TMachine = class;
10
11 { TDevice }
12
13 TDevice = class
14 Machine: TMachine;
15 procedure Reset; virtual;
16 procedure OutputHandler(Port: TAddress; Data: TData); virtual; abstract;
17 function InputHandler(Port: TAddress): TData; virtual; abstract;
18 end;
19
20 { TMouse }
21
22 TMouse = class(TDevice)
23 Position: TPoint;
24 InterruptVector: Integer;
25 procedure Move(X, Y: Integer);
26 end;
27
28 { TScreen }
29
30 TScreen = class(TDevice)
31 private
32 FWidth: Integer;
33 FHeight: Integer;
34 Pointer: Integer;
35 function GetSize: TPoint;
36 procedure SetSize(AValue: TPoint);
37 public
38 Memory: TMemory;
39 PendingRefresh: Boolean;
40 procedure Reset; override;
41 procedure SetPointer(Value: Integer);
42 procedure WriteData(Value: Integer);
43 property Size: TPoint read GetSize write SetSize;
44 property Width: Integer read FWidth;
45 property Height: Integer read FHeight;
46 constructor Create;
47 destructor Destroy; override;
48 end;
49
50 { TFifo }
51
52 TFifo = class
53 Data: array of Integer;
54 procedure Put(Value: Integer);
55 function Get: Integer;
56 function Size: Integer;
57 procedure Clear;
58 end;
59
60 { TKeyboard }
61
62 TKeyboard = class(TDevice)
63 Buffer: TFifo;
64 InterruptVector: Integer;
65 function ReadKey: Integer;
66 function KeyReady: Integer;
67 constructor Create;
68 destructor Destroy; override;
69 procedure Reset; override;
70 procedure Press(KeyCode: Integer);
71 end;
72
73 { TCounter }
74
75 TCounter = class(TDevice)
76 private
77 Timer: TTimer;
78 function GetEnabled: Boolean;
79 function GetInterval: Integer;
80 procedure SetEnabled(AValue: Boolean);
81 procedure SetInterval(AValue: Integer);
82 procedure DoTimer(Sender: TObject);
83 public
84 InterruptVector: Integer;
85 constructor Create;
86 destructor Destroy; override;
87 property Enabled: Boolean read GetEnabled write SetEnabled;
88 property Interval: Integer read GetInterval write SetInterval;
89 end;
90
91 { TStorage }
92
93 TStorage = class(TDevice)
94 public
95 F: TFileStream;
96 FileName: string;
97 constructor Create;
98 procedure OutputHandler(Port: TAddress; Data: TData); override;
99 function InputHandler(Port: TAddress): TData; override;
100 end;
101
102 { TMachine }
103
104 TMachine = class
105 private
106 function CpuInput(Address: TAddress): TData;
107 procedure CpuOutput(Address: TAddress; Value: TData);
108 function GetRunning: Boolean;
109 procedure SetRunning(AValue: Boolean);
110 public
111 Cpu: TCpu;
112 Memory: TMemory;
113 Keyboard: TKeyboard;
114 Mouse: TMouse;
115 Screen: TScreen;
116 Counter: TCounter;
117 procedure Reset;
118 constructor Create;
119 destructor Destroy; override;
120 property Running: Boolean read GetRunning write SetRunning;
121 end;
122
123
124implementation
125
126{ TStorage }
127
128constructor TStorage.Create;
129begin
130
131end;
132
133procedure TStorage.OutputHandler(Port: TAddress; Data: TData);
134begin
135
136end;
137
138function TStorage.InputHandler(Port: TAddress): TData;
139begin
140
141end;
142
143{ TMouse }
144
145procedure TMouse.Move(X, Y: Integer);
146begin
147 Position := Point(X, Y);
148 Machine.Cpu.Interrupt(InterruptVector);
149end;
150
151{ TCounter }
152
153function TCounter.GetEnabled: Boolean;
154begin
155 Result := Timer.Enabled;
156end;
157
158function TCounter.GetInterval: Integer;
159begin
160 Result := Timer.Interval;
161end;
162
163procedure TCounter.SetEnabled(AValue: Boolean);
164begin
165 Timer.Enabled := AValue;
166end;
167
168procedure TCounter.SetInterval(AValue: Integer);
169begin
170 Timer.Interval := AValue;
171end;
172
173procedure TCounter.DoTimer(Sender: TObject);
174begin
175 Machine.Cpu.Interrupt(InterruptVector);
176end;
177
178constructor TCounter.Create;
179begin
180 Timer := TTimer.Create(nil);
181 Timer.OnTimer := DoTimer;
182 Enabled := False;
183end;
184
185destructor TCounter.Destroy;
186begin
187 FreeAndNil(Timer);
188 inherited;
189end;
190
191{ TDevice }
192
193procedure TDevice.Reset;
194begin
195end;
196
197{ TScreen }
198
199function TScreen.GetSize: TPoint;
200begin
201 Result := Point(FWidth, FHeight);
202end;
203
204procedure TScreen.SetSize(AValue: TPoint);
205begin
206 FWidth := AValue.X;
207 FHeight := AValue.Y;
208 Memory.Size := FWidth * FHeight * SizeOf(Integer);
209end;
210
211procedure TScreen.Reset;
212begin
213 Pointer := 0;
214end;
215
216procedure TScreen.SetPointer(Value: Integer);
217begin
218 Pointer := Value;
219end;
220
221procedure TScreen.WriteData(Value: Integer);
222begin
223 PInteger(@Memory.Data[Pointer])^ := Value;
224 Pointer := (Pointer + SizeOf(Integer)) mod Memory.Size;
225 PendingRefresh := True;
226end;
227
228constructor TScreen.Create;
229begin
230 Memory := TMemory.Create;
231end;
232
233destructor TScreen.Destroy;
234begin
235 FreeAndNil(Memory);
236 inherited;
237end;
238
239{ TFifo }
240
241procedure TFifo.Put(Value: Integer);
242begin
243 SetLength(Data, Length(Data) + 1);
244 Data[Length(Data) - 1] := Value;
245end;
246
247function TFifo.Get: Integer;
248begin
249 if Size > 0 then begin
250 Result := Data[0];
251 Move(Data[1], Data[0], (Size - 1) * SizeOf(Integer));
252 SetLength(Data, Length(Data) - 1);
253 end else raise Exception.Create('Read from empty FIFO buffer');
254end;
255
256function TFifo.Size: Integer;
257begin
258 Result := Length(Data);
259end;
260
261procedure TFifo.Clear;
262begin
263 SetLength(Data, 0);
264end;
265
266{ TKeyboard }
267
268function TKeyboard.ReadKey: Integer;
269begin
270 Result := Buffer.Get;
271end;
272
273function TKeyboard.KeyReady: Integer;
274begin
275 if Buffer.Size > 0 then Result := 1
276 else Result := 0;
277end;
278
279constructor TKeyboard.Create;
280begin
281 Buffer := TFifo.Create;
282end;
283
284destructor TKeyboard.Destroy;
285begin
286 FreeAndNil(Buffer);
287 inherited;
288end;
289
290procedure TKeyboard.Reset;
291begin
292 Buffer.Clear;
293end;
294
295procedure TKeyboard.Press(KeyCode: Integer);
296begin
297 Buffer.Put(KeyCode);
298 Machine.Cpu.Interrupt(InterruptVector);
299end;
300
301{ TMachine }
302
303function TMachine.CpuInput(Address: TAddress): TData;
304begin
305 if Address = 0 then Result := Keyboard.ReadKey
306 else if Address = 1 then Result := Mouse.Position.X
307 else if Address = 2 then Result := Mouse.Position.Y
308 else if Address = 3 then Result := Screen.Size.X
309 else if Address = 4 then Result := Screen.Size.Y
310 else if Address = 5 then Result := Keyboard.KeyReady
311 else Result := 0;
312end;
313
314procedure TMachine.CpuOutput(Address: TAddress; Value: TData);
315begin
316 if Address = 0 then Screen.SetPointer(Value)
317 else if Address = 1 then Screen.WriteData(Value)
318 else if Address = 2 then Counter.Interval := Value
319 else if Address = 3 then Counter.Enabled := Value = 1;
320end;
321
322function TMachine.GetRunning: Boolean;
323begin
324 Result := Cpu.Running;
325end;
326
327procedure TMachine.SetRunning(AValue: Boolean);
328begin
329 Cpu.Running := AValue;
330end;
331
332procedure TMachine.Reset;
333begin
334 Screen.Reset;
335 Cpu.Reset;
336 FillChar(Memory.Data^, Memory.Size, 0);
337end;
338
339constructor TMachine.Create;
340begin
341 Counter := TCounter.Create;
342 Counter.Machine := Self;
343 Counter.InterruptVector := 2;
344 Memory := TMemory.Create;
345 Memory.Size := 200000;
346 Keyboard := TKeyboard.Create;
347 Keyboard.Machine := Self;
348 Keyboard.InterruptVector := 4;
349 Mouse := TMouse.Create;
350 Mouse.Machine := Self;
351 Mouse.InterruptVector := 3;
352 Screen := TScreen.Create;
353 Screen.Size := Point(640, 480);
354 Cpu := TCpu.Create;
355 Cpu.Memory := Memory;
356 Cpu.OnInput := CpuInput;
357 Cpu.OnOutput := CpuOutput;
358end;
359
360destructor TMachine.Destroy;
361begin
362 FreeAndNil(Cpu);
363 FreeAndNil(Mouse);
364 FreeAndNil(Keyboard);
365 FreeAndNil(Screen);
366 FreeAndNil(Memory);
367 FreeAndNil(Counter);
368 inherited;
369end;
370
371end.
372
Note: See TracBrowser for help on using the repository browser.