source: branches/UltimatOS/UCpu.pas

Last change on this file was 35, checked in by chronos, 23 months ago
  • Added: Cpu state window.
File size: 10.9 KB
Line 
1unit UCpu;
2
3interface
4
5uses
6 Classes, SysUtils, UMemory;
7
8type
9 TInstruction = (inNop, inHalt, inSet, inInput, inOutput, inInc, inDec, inJp,
10 inJpz, inJpnz, inAdd, inSub, inCall, inRet, inPush, inPop, inCopy,
11 inShl, inShr, inLoad, inLoadi, inStore, inMul, inAnd, inAndi, inOr, inXor,
12 inInt, inReti, inEnableInt, inDisableInt);
13 TAddress = Integer;
14 PAddress = ^TAddress;
15 TData = Integer;
16 PData = ^TData;
17 TRegister = Integer;
18
19 TOnInput = function (Address: Integer): TData of object;
20 TOnOutput = procedure (Address: Integer; Value: TData) of object;
21
22 TCpu = class;
23 TInstructionHandler = procedure of object;
24
25 { TCpuThread }
26
27 TCpuThread = class(TThread)
28 Cpu: TCpu;
29 procedure Execute; override;
30 destructor Destroy; override;
31 end;
32
33 { TCpu }
34
35 TCpu = class
36 private
37 FCpuThread: TCpuThread;
38 FOnInput: TOnInput;
39 FOnOutput: TOnOutput;
40 InterruptPending: Boolean;
41 InterruptVector: Integer;
42 InterruptEnabled: Boolean;
43 FInstructionHandlers: array[TInstruction] of TInstructionHandler;
44 function GetRunning: Boolean;
45 function ReadByte: Byte; inline;
46 function ReadAddress: TAddress; inline;
47 function ReadData: TData; inline;
48 procedure Push(Value: Integer); inline;
49 function Pop: Integer; inline;
50 procedure SetRunning(AValue: Boolean);
51 procedure InitInstructions;
52 procedure InstructionNop;
53 procedure InstructionHalt;
54 procedure InstructionSet;
55 procedure InstructionInput;
56 procedure InstructionOutput;
57 procedure InstructionInc;
58 procedure InstructionDec;
59 procedure InstructionJp;
60 procedure InstructionJpnz;
61 procedure InstructionJpz;
62 procedure InstructionAdd;
63 procedure InstructionSub;
64 procedure InstructionCall;
65 procedure InstructionRet;
66 procedure InstructionPush;
67 procedure InstructionPop;
68 procedure InstructionCopy;
69 procedure InstructionShl;
70 procedure InstructionShr;
71 procedure InstructionLoad;
72 procedure InstructionLoadi;
73 procedure InstructionStore;
74 procedure InstructionMul;
75 procedure InstructionAnd;
76 procedure InstructionAndi;
77 procedure InstructionOr;
78 procedure InstructionXor;
79 procedure InstructionInt;
80 procedure InstructionReti;
81 procedure InstructionEnableInt;
82 procedure InstructionDisableInt;
83 public
84 Ticks: Int64;
85 InterruptCount: Integer;
86 Terminated: Boolean;
87 Memory: TMemory;
88 R: array[0..15] of TRegister;
89 IP: TAddress;
90 SP: TAddress;
91 procedure Run;
92 procedure Start;
93 procedure Stop;
94 procedure Step;
95 procedure Reset;
96 procedure Interrupt(Vector: Integer);
97 constructor Create;
98 destructor Destroy; override;
99 property OnInput: TOnInput read FOnInput write FOnInput;
100 property OnOutput: TOnOutput read FOnOutput write FOnOutput;
101 property Running: Boolean read GetRunning write SetRunning;
102 end;
103
104
105implementation
106
107{ TCpuThread }
108
109procedure TCpuThread.Execute;
110begin
111 Cpu.Run;
112end;
113
114destructor TCpuThread.Destroy;
115begin
116 Cpu.FCpuThread := nil;
117 inherited;
118end;
119
120{ TCpu }
121
122function TCpu.ReadByte: Byte;
123begin
124 Result := Memory.Data[IP];
125 IP := (IP + 1) mod Memory.Size;
126end;
127
128function TCpu.GetRunning: Boolean;
129begin
130 Result := Assigned(FCpuThread);
131end;
132
133function TCpu.ReadAddress: TAddress;
134begin
135 Result := PAddress(@Memory.Data[IP])^;
136 IP := (IP + SizeOf(TAddress)) mod Memory.Size;
137end;
138
139function TCpu.ReadData: TData;
140begin
141 Result := PData(@Memory.Data[IP])^;
142 IP := (IP + SizeOf(TData)) mod Memory.Size;
143end;
144
145procedure TCpu.Push(Value: Integer);
146begin
147 SP := (SP - SizeOf(TAddress) + Memory.Size) mod Memory.Size;
148 PAddress(@Memory.Data[SP])^ := Value;
149end;
150
151function TCpu.Pop: Integer;
152begin
153 Result := PAddress(@Memory.Data[SP])^;
154 SP := (SP + SizeOf(TAddress)) mod Memory.Size;
155end;
156
157procedure TCpu.SetRunning(AValue: Boolean);
158begin
159 if AValue and not Assigned(FCpuThread) then begin
160 FCpuThread := TCpuThread.Create(True);
161 FCpuThread.FreeOnTerminate := False;
162 FCpuThread.Cpu := Self;
163 FCpuThread.Start;
164 end else
165 if not AValue and Assigned(FCpuThread) then begin
166 Terminated := True;
167 FreeAndNil(FCpuThread);
168 end;
169end;
170
171procedure TCpu.InitInstructions;
172begin
173 FInstructionHandlers[inNop] := InstructionNop;
174 FInstructionHandlers[inHalt] := InstructionHalt;
175 FInstructionHandlers[inSet] := InstructionSet;
176 FInstructionHandlers[inInput] := InstructionInput;
177 FInstructionHandlers[inOutput] := InstructionOutput;
178 FInstructionHandlers[inInc] := InstructionInc;
179 FInstructionHandlers[inDec] := InstructionDec;
180 FInstructionHandlers[inJp] := InstructionJp;
181 FInstructionHandlers[inJpz] := InstructionJpz;
182 FInstructionHandlers[inJpnz] := InstructionJpnz;
183 FInstructionHandlers[inAdd] := InstructionAdd;
184 FInstructionHandlers[inSub] := InstructionSub;
185 FInstructionHandlers[inCall] := InstructionCall;
186 FInstructionHandlers[inRet] := InstructionRet;
187 FInstructionHandlers[inPush] := InstructionPush;
188 FInstructionHandlers[inPop] := InstructionPop;
189 FInstructionHandlers[inCopy] := InstructionCopy;
190 FInstructionHandlers[inShl] := InstructionShl;
191 FInstructionHandlers[inShr] := InstructionShr;
192 FInstructionHandlers[inLoad] := InstructionLoad;
193 FInstructionHandlers[inLoadi] := InstructionLoadi;
194 FInstructionHandlers[inStore] := InstructionStore;
195 FInstructionHandlers[inMul] := InstructionMul;
196 FInstructionHandlers[inAnd] := InstructionAnd;
197 FInstructionHandlers[inAndi] := InstructionAndi;
198 FInstructionHandlers[inOr] := InstructionOr;
199 FInstructionHandlers[inXor] := InstructionXor;
200 FInstructionHandlers[inInt] := InstructionInt;
201 FInstructionHandlers[inReti] := InstructionReti;
202 FInstructionHandlers[inEnableInt] := InstructionEnableInt;
203 FInstructionHandlers[inDisableInt] := InstructionDisableInt;
204end;
205
206procedure TCpu.InstructionNop;
207begin
208 // No operation
209end;
210
211procedure TCpu.InstructionHalt;
212begin
213 Terminated := True;
214end;
215
216procedure TCpu.InstructionSet;
217var
218 RegIndex: Byte;
219begin
220 RegIndex := ReadByte;
221 R[RegIndex] := ReadData;
222end;
223
224procedure TCpu.InstructionInput;
225var
226 RegIndex: Byte;
227 Address: TAddress;
228begin
229 RegIndex := ReadByte;
230 Address := ReadAddress;
231 if Assigned(FOnInput) then R[RegIndex] := FOnInput(Address)
232 else R[RegIndex] := 0;
233end;
234
235procedure TCpu.InstructionOutput;
236var
237 RegIndex: Byte;
238 Address: TAddress;
239begin
240 Address := ReadAddress;
241 RegIndex := ReadByte;
242 if Assigned(FOnOutput) then FOnOutput(Address, R[RegIndex]);
243end;
244
245procedure TCpu.InstructionInc;
246var
247 RegIndex: Byte;
248begin
249 RegIndex := ReadByte;
250 R[RegIndex] := R[RegIndex] + 1;
251end;
252
253procedure TCpu.InstructionDec;
254var
255 RegIndex: Byte;
256begin
257 RegIndex := ReadByte;
258 R[RegIndex] := R[RegIndex] - 1;
259end;
260
261procedure TCpu.InstructionJp;
262begin
263 IP := ReadAddress;
264end;
265
266procedure TCpu.InstructionJpnz;
267var
268 RegIndex: Byte;
269 Address: TAddress;
270begin
271 RegIndex := ReadByte;
272 Address := ReadAddress;
273 if R[RegIndex] <> 0 then IP := Address;
274end;
275
276procedure TCpu.InstructionJpz;
277var
278 RegIndex: Byte;
279 Address: TAddress;
280begin
281 RegIndex := ReadByte;
282 Address := ReadAddress;
283 if R[RegIndex] = 0 then IP := Address;
284end;
285
286procedure TCpu.InstructionAdd;
287var
288 RegIndex: Byte;
289 RegIndex2: Byte;
290begin
291 RegIndex := ReadByte;
292 RegIndex2 := ReadByte;
293 R[RegIndex] := R[RegIndex] + R[RegIndex2];
294end;
295
296procedure TCpu.InstructionSub;
297var
298 RegIndex: Byte;
299 RegIndex2: Byte;
300begin
301 RegIndex := ReadByte;
302 RegIndex2 := ReadByte;
303 R[RegIndex] := R[RegIndex] - R[RegIndex2];
304end;
305
306procedure TCpu.InstructionCall;
307var
308 Address: TAddress;
309begin
310 Address := ReadAddress;
311 Push(IP);
312 IP := Address;
313end;
314
315procedure TCpu.InstructionRet;
316begin
317 IP := Pop;
318end;
319
320procedure TCpu.InstructionPush;
321begin
322 Push(R[ReadByte]);
323end;
324
325procedure TCpu.InstructionPop;
326begin
327 R[ReadByte] := Pop;
328end;
329
330procedure TCpu.InstructionCopy;
331var
332 RegIndex: Byte;
333 RegIndex2: Byte;
334begin
335 RegIndex := ReadByte;
336 RegIndex2 := ReadByte;
337 R[RegIndex] := R[RegIndex2];
338end;
339
340procedure TCpu.InstructionShl;
341var
342 RegIndex: Byte;
343 Num: Byte;
344begin
345 RegIndex := ReadByte;
346 Num := ReadByte;
347 R[RegIndex] := R[RegIndex] shl Num;
348end;
349
350procedure TCpu.InstructionShr;
351var
352 RegIndex: Byte;
353 Num: Byte;
354begin
355 RegIndex := ReadByte;
356 Num := ReadByte;
357 R[RegIndex] := R[RegIndex] shr Num;
358end;
359
360procedure TCpu.InstructionLoad;
361var
362 RegIndex: Byte;
363 RegIndex2: Byte;
364begin
365 RegIndex := ReadByte;
366 RegIndex2 := ReadByte;
367 R[RegIndex] := PData(@Memory.Data[R[RegIndex2]])^;
368end;
369
370procedure TCpu.InstructionLoadi;
371var
372 RegIndex: Byte;
373 Address: TAddress;
374begin
375 RegIndex := ReadByte;
376 Address := ReadAddress;
377 R[RegIndex] := PData(@Memory.Data[Address])^;
378end;
379
380procedure TCpu.InstructionStore;
381var
382 RegIndex: Byte;
383 RegIndex2: Byte;
384begin
385 RegIndex := ReadByte;
386 RegIndex2 := ReadByte;
387 PData(@Memory.Data[R[RegIndex2]])^ := R[RegIndex];
388end;
389
390procedure TCpu.InstructionMul;
391var
392 RegIndex: Byte;
393 RegIndex2: Byte;
394begin
395 RegIndex := ReadByte;
396 RegIndex2 := ReadByte;
397 R[RegIndex] := R[RegIndex] * R[RegIndex2];
398end;
399
400procedure TCpu.InstructionAnd;
401var
402 RegIndex: Byte;
403 RegIndex2: Byte;
404begin
405 RegIndex := ReadByte;
406 RegIndex2 := ReadByte;
407 R[RegIndex] := R[RegIndex] and R[RegIndex2];
408end;
409
410procedure TCpu.InstructionAndi;
411var
412 RegIndex: Byte;
413begin
414 RegIndex := ReadByte;
415 R[RegIndex] := R[RegIndex] and ReadData;
416end;
417
418procedure TCpu.InstructionOr;
419var
420 RegIndex: Byte;
421 RegIndex2: Byte;
422begin
423 RegIndex := ReadByte;
424 RegIndex2 := ReadByte;
425 R[RegIndex] := R[RegIndex] or R[RegIndex2];
426end;
427
428procedure TCpu.InstructionXor;
429var
430 RegIndex: Byte;
431 RegIndex2: Byte;
432begin
433 RegIndex := ReadByte;
434 RegIndex2 := ReadByte;
435 R[RegIndex] := R[RegIndex] xor R[RegIndex2];
436end;
437
438procedure TCpu.InstructionInt;
439begin
440 Interrupt(ReadByte);
441end;
442
443procedure TCpu.InstructionReti;
444begin
445 IP := Pop;
446 InterruptEnabled := True;
447end;
448
449procedure TCpu.InstructionEnableInt;
450begin
451 InterruptEnabled := True;
452end;
453
454procedure TCpu.InstructionDisableInt;
455begin
456 InterruptEnabled := False;
457end;
458
459procedure TCpu.Run;
460begin
461 while not Terminated do begin
462 if InterruptEnabled and InterruptPending then begin
463 InterruptEnabled := False;
464 InterruptPending := False;
465 Push(IP);
466 IP := PAddress(@Memory.Data[InterruptVector * SizeOf(TAddress)])^;
467 end;
468 Step;
469 end;
470end;
471
472procedure TCpu.Start;
473begin
474 Running := True;
475end;
476
477procedure TCpu.Stop;
478begin
479 Running := False;
480end;
481
482procedure TCpu.Step;
483var
484 Instruction: TInstruction;
485begin
486 Instruction := TInstruction(ReadByte);
487 if Assigned(FInstructionHandlers[Instruction]) then
488 FInstructionHandlers[Instruction]
489 else raise Exception.Create('Missing handler for instruction ' + IntToStr(Integer(Instruction)));
490 Inc(Ticks);
491end;
492
493procedure TCpu.Reset;
494begin
495 Terminated := False;
496 IP := 0;
497 SP := 0;
498 Ticks := 0;
499 InterruptEnabled := True;
500 InterruptPending := False;
501 InterruptCount := 0;
502end;
503
504procedure TCpu.Interrupt(Vector: Integer);
505begin
506 InterruptPending := True;
507 InterruptVector := Vector;
508 Inc(InterruptCount);
509end;
510
511constructor TCpu.Create;
512begin
513 InitInstructions;
514end;
515
516destructor TCpu.Destroy;
517begin
518 Running := False;
519 inherited;
520end;
521
522end.
523
Note: See TracBrowser for help on using the repository browser.