source: branches/virtcpu varint/UCpu.pas

Last change on this file was 197, checked in by chronos, 5 years ago
  • Modified: All parts of virtual machine have own form in Forms subdirectory.
  • Modified: Main form moved to Forms subdirectory.
  • Modified: TCpu class moved to UCpu unit.
  • Added: Assembler and dissasembler forms.
File size: 11.1 KB
Line 
1unit UCpu;
2
3{$mode delphi}
4
5interface
6
7uses
8 Classes, SysUtils, UVarInt;
9
10type
11 T = TVarInt;
12
13 TOpcode = (opNop, opLoad, opLoadConst, opNeg,
14 opJump, opJumpRel,
15 opInc, opDec,
16 opLoadMem, opStoreMem,
17 opAdd, opSub,
18 opInput, opOutput,
19 opCall, opCallRel, opRet,
20 opExchg,
21 opAnd, opOr, opXor,
22 opShl, opShr,
23 opRor, opRol,
24 opPush, opPop,
25 opJumpRelCond,
26 opLdir, opLddr,
27 opJumpCond, opTestEqual, opTestNotEqual, opTestLess,
28 opTestLessEqual, opTestGreater, opTestGreaterEqual, opTestZero, opTestNotZero,
29 opMul, opDiv, opHalt, opMod,
30 opClear
31 );
32
33 TOpcodeHandler = procedure of object;
34 TInputEvent = function (Port: T): T of object;
35 TOutputEvent = procedure (Port, Value: T) of object;
36
37 { TCPU }
38
39 TCPU = class(TComponent)
40 private
41 FOnInput: TInputEvent;
42 FOnOutput: TOutputEvent;
43 OpcodeHandlers: array[TOpcode] of TOpcodeHandler;
44 function ReadNext: T; inline;
45 procedure OpcodeNop;
46 procedure OpcodeHalt;
47 procedure OpcodeLoad;
48 procedure OpcodeLoadConst;
49 procedure OpcodeJump;
50 procedure OpcodeJumpRel;
51 procedure OpcodeNeg;
52 procedure OpcodeInc;
53 procedure OpcodeDec;
54 procedure OpcodeLoadMem;
55 procedure OpcodeStoreMem;
56 procedure OpcodeExchange;
57 procedure OpcodeTestEqual;
58 procedure OpcodeTestNotEqual;
59 procedure OpcodeTestGreatEqual;
60 procedure OpcodeTestGreat;
61 procedure OpcodeTestLessEqual;
62 procedure OpcodeTestLess;
63 procedure OpcodeTestZero;
64 procedure OpcodeTestNotZero;
65 procedure OpcodeJumpCond;
66 procedure OpcodeJumpRelCond;
67 procedure OpcodeShl;
68 procedure OpcodeShr;
69 procedure OpcodeRor;
70 procedure OpcodeRol;
71 procedure OpcodeAnd;
72 procedure OpcodeOr;
73 procedure OpcodeXor;
74 procedure OpcodePush;
75 procedure OpcodePop;
76 procedure OpcodeCall;
77 procedure OpcodeReturn;
78 procedure OpcodeCallRel;
79 procedure OpcodeOutput;
80 procedure OpcodeInput;
81 procedure OpcodeAdd;
82 procedure OpcodeSub;
83 procedure OpcodeMul;
84 procedure OpcodeDiv;
85 procedure OpcodeMod;
86 procedure OpcodeLdir;
87 procedure OpcodeLddr;
88 procedure OpcodeClear;
89 public
90 Memory: Pointer;
91 Registers: array of T;
92 IP: T;
93 SP: T;
94 Condition: Boolean;
95 Terminated: Boolean;
96 Ticks: Integer;
97 procedure Start;
98 procedure Stop;
99 procedure Step; inline;
100 constructor Create(AOwner: TComponent); override;
101 published
102 property OnInput: TInputEvent read FOnInput write FOnInput;
103 property OnOutput: TOutputEvent read FOnOutput write FOnOutput;
104 end;
105
106
107implementation
108
109{ TCPU }
110
111function TCPU.ReadNext: T;
112begin
113 IP := IP + Result.ReadFromAddr(Pointer(NativeUInt(Memory) + IP));
114end;
115
116procedure TCPU.OpcodeHalt;
117begin
118 Terminated := True;
119end;
120
121procedure TCPU.OpcodeNop;
122begin
123 // Do nothing
124end;
125
126procedure TCPU.OpcodeLoad;
127var
128 P1: T;
129 P2: T;
130begin
131 P1 := ReadNext;
132 P2 := ReadNext;
133 Registers[P1] := Registers[P2];
134end;
135
136procedure TCPU.OpcodeLoadConst;
137var
138 P1: T;
139 P2: T;
140begin
141 P1 := ReadNext;
142 P2 := ReadNext;
143 Registers[P1] := P2;
144end;
145
146procedure TCPU.OpcodeLoadMem;
147var
148 P1: T;
149 P2: T;
150begin
151 P1 := ReadNext;
152 P2 := ReadNext;
153 Registers[P1].ReadFromAddr(Pointer(NativeUInt(Memory) + Integer(Registers[P2])));
154end;
155
156procedure TCPU.OpcodeStoreMem;
157var
158 P1: T;
159 P2: T;
160begin
161 P1 := ReadNext;
162 P2 := ReadNext;
163 Registers[P2].WriteToAddr(Pointer(NativeUInt(Memory) + Registers[P1]));
164end;
165
166procedure TCPU.OpcodeNeg;
167var
168 P1: T;
169begin
170 P1 := ReadNext;
171 Registers[P1] := -Registers[P1];
172end;
173
174procedure TCPU.OpcodeExchange;
175var
176 P1, P2, Temp: T;
177begin
178 P1 := ReadNext;
179 P2 := ReadNext;
180 Temp := Registers[P1];
181 Registers[P1] := Registers[P2];
182 Registers[P2] := Temp;
183end;
184
185procedure TCPU.OpcodeJump;
186begin
187 IP := ReadNext;
188end;
189
190procedure TCPU.OpcodeJumpRel;
191begin
192 IP := IP + ReadNext;
193end;
194
195procedure TCPU.OpcodeTestEqual;
196begin
197 Condition := ReadNext = ReadNext;
198end;
199
200procedure TCPU.OpcodeTestNotEqual;
201begin
202 Condition := ReadNext <> ReadNext;
203end;
204
205procedure TCPU.OpcodeTestGreatEqual;
206begin
207 Condition := ReadNext >= ReadNext;
208end;
209
210procedure TCPU.OpcodeTestGreat;
211begin
212 Condition := ReadNext > ReadNext;
213end;
214
215procedure TCPU.OpcodeTestLessEqual;
216begin
217 Condition := ReadNext <= ReadNext;
218end;
219
220procedure TCPU.OpcodeTestLess;
221begin
222 Condition := ReadNext < ReadNext;
223end;
224
225procedure TCPU.OpcodeTestZero;
226begin
227 Condition := ReadNext = 0;
228end;
229
230procedure TCPU.OpcodeTestNotZero;
231begin
232 Condition := ReadNext <> 0;
233end;
234
235procedure TCPU.OpcodeJumpCond;
236var
237 Addr: T;
238begin
239 Addr := ReadNext;
240 if Condition then IP := Addr;
241end;
242
243
244procedure TCPU.OpcodeJumpRelCond;
245var
246 Addr: T;
247begin
248 Addr := ReadNext;
249 if Condition then IP := IP + Addr;
250end;
251
252procedure TCPU.OpcodeRor;
253var
254 P1, P2: T;
255begin
256 P1 := ReadNext;
257 P2 := ReadNext;
258 Registers[P1] := (Registers[P1] shr Registers[P2]) or
259 ((Registers[P1] and ((1 shl Registers[P2]) - 1)) shl (SizeOf(T) * 8 - Registers[P2]));
260end;
261
262procedure TCPU.OpcodeRol;
263var
264 P1, P2: T;
265begin
266 P1 := ReadNext;
267 P2 := ReadNext;
268 Registers[P1] := (Registers[P1] shl Registers[P2]) or
269 ((Registers[P1] shr (SizeOf(T) * 8 - Registers[P2])) and ((1 shl Registers[P2]) - 1));
270end;
271
272procedure TCPU.OpcodeShl;
273var
274 P1, P2: T;
275begin
276 P1 := ReadNext;
277 P2 := ReadNext;
278 Registers[P1] := Registers[P1] shl Registers[P2];
279end;
280
281procedure TCPU.OpcodeShr;
282var
283 P1, P2: T;
284begin
285 P1 := ReadNext;
286 P2 := ReadNext;
287 Registers[P1] := Registers[P1] shr Registers[P2];
288end;
289
290procedure TCPU.OpcodeAnd;
291var
292 P1, P2: T;
293begin
294 P1 := ReadNext;
295 P2 := ReadNext;
296 Registers[P1] := Registers[P1] and Registers[P2];
297end;
298
299procedure TCPU.OpcodeOr;
300var
301 P1, P2: T;
302begin
303 P1 := ReadNext;
304 P2 := ReadNext;
305 Registers[P1] := Registers[P1] or Registers[P2];
306end;
307
308procedure TCPU.OpcodeXor;
309var
310 P1, P2: T;
311begin
312 P1 := ReadNext;
313 P2 := ReadNext;
314 Registers[P1] := Registers[P1] xor Registers[P2];
315end;
316
317procedure TCPU.OpcodePush;
318var
319 P1: T;
320begin
321 P1 := ReadNext;
322 SP := SP - Registers[P1].GetByteSize;
323 Registers[P1].WriteToAddr(Pointer(NativeUInt(Memory) + Integer(SP)));
324end;
325
326procedure TCPU.OpcodePop;
327begin
328 SP := SP + Registers[ReadNext].ReadFromAddr(Pointer(NativeUInt(Memory) + Integer(SP)));
329end;
330
331procedure TCPU.OpcodeCall;
332var
333 Addr: T;
334begin
335 Addr := ReadNext;
336 SP := SP - IP.GetByteSize;
337 IP.WriteToAddr(Pointer(NativeUInt(Memory) + SP));
338 IP := Addr;
339end;
340
341procedure TCPU.OpcodeCallRel;
342var
343 Addr: T;
344begin
345 Addr := ReadNext;
346 SP := SP - IP.GetByteSize;
347 IP.WriteToAddr(Pointer(NativeUInt(Memory) + SP));
348 IP := IP + Addr;
349end;
350
351procedure TCPU.OpcodeReturn;
352begin
353 SP := SP + IP.ReadFromAddr(Pointer(NativeUInt(Memory) + SP));
354end;
355
356procedure TCPU.OpcodeOutput;
357var
358 R1: T;
359 R2: T;
360begin
361 R1 := ReadNext;
362 R2 := ReadNext;
363 if Assigned(FOnOutput) then
364 FOnOutput(Registers[R1], Registers[R2]);
365end;
366
367procedure TCPU.OpcodeInput;
368var
369 R1: T;
370 R2: T;
371begin
372 R1 := ReadNext;
373 R2 := ReadNext;
374 if Assigned(FOnInput) then
375 Registers[R1] := FOnInput(Registers[R2]);
376end;
377
378procedure TCPU.OpcodeInc;
379var
380 R: T;
381begin
382 R := ReadNext;
383 Registers[R] := Registers[R] + 1;
384end;
385
386procedure TCPU.OpcodeDec;
387var
388 R: T;
389begin
390 R := ReadNext;
391 Registers[R] := Registers[R] - 1;
392end;
393
394procedure TCPU.OpcodeAdd;
395var
396 R1: T;
397 R2: T;
398begin
399 R1 := ReadNext;
400 R2 := ReadNext;
401 Registers[R1] := Registers[R1] + Registers[R2];
402end;
403
404procedure TCPU.OpcodeSub;
405var
406 R1: T;
407 R2: T;
408begin
409 R1 := ReadNext;
410 R2 := ReadNext;
411 Registers[R1] := Registers[R1] - Registers[R2];
412end;
413
414procedure TCPU.OpcodeMul;
415var
416 R1: T;
417 R2: T;
418begin
419 R1 := ReadNext;
420 R2 := ReadNext;
421 Registers[R1] := Registers[R1] * Registers[R2];
422end;
423
424procedure TCPU.OpcodeDiv;
425var
426 R1: T;
427 R2: T;
428begin
429 R1 := ReadNext;
430 R2 := ReadNext;
431 Registers[R1] := Registers[R1] div Registers[R2];
432end;
433
434procedure TCPU.OpcodeMod;
435var
436 R1: T;
437 R2: T;
438begin
439 R1 := ReadNext;
440 R2 := ReadNext;
441 Registers[R1] := Registers[R1] mod Registers[R2];
442end;
443
444procedure TCPU.OpcodeLdir;
445var
446 Src: T;
447 Dst: T;
448 Count: T;
449 Bytes: T;
450begin
451 Src := ReadNext;
452 Dst := ReadNext;
453 Count := ReadNext;
454 Bytes := ReadNext;
455 while Registers[Count] > 0 do begin
456 Move(Pointer(NativeUInt(Memory) + Registers[Src])^,
457 Pointer(NativeUInt(Memory) + Registers[Dst])^, Bytes);
458 Inc(Registers[Src], Bytes);
459 Inc(Registers[Dst], Bytes);
460 Dec(Registers[Count]);
461 end;
462end;
463
464procedure TCPU.OpcodeLddr;
465var
466 Src: T;
467 Dst: T;
468 Count: T;
469 Bytes: T;
470begin
471 Src := ReadNext;
472 Dst := ReadNext;
473 Count := ReadNext;
474 Bytes := ReadNext;
475 while Registers[Count] > 0 do begin
476 Move(Pointer(NativeUInt(Memory) + Registers[Src])^,
477 Pointer(NativeUInt(Memory) + Registers[Dst])^, Bytes);
478 Dec(Registers[Src], Bytes);
479 Dec(Registers[Dst], Bytes);
480 Dec(Registers[Count]);
481 end;
482end;
483
484procedure TCPU.OpcodeClear;
485var
486 P1: T;
487begin
488 P1 := ReadNext;
489 Registers[P1] := 0;
490end;
491
492procedure TCPU.Start;
493begin
494 Terminated := False;
495 Ticks := 0;
496 IP := 0;
497 SP := MemSize(Memory);
498 while not Terminated do
499 Step;
500end;
501
502procedure TCPU.Stop;
503begin
504 Terminated := True;
505end;
506
507procedure TCPU.Step;
508var
509 Opcode: T;
510begin
511 Opcode := ReadNext;
512 if (Opcode >= 0) and (Opcode <= T(Integer(High(TOpcode)))) then
513 OpcodeHandlers[TOpcode(Byte(Opcode))]
514 else raise Exception.Create(Format('Unsupported instruction %d on address %x', [Int64(Opcode), Int64(IP)]));
515 Inc(Ticks);
516end;
517
518constructor TCPU.Create(AOwner: TComponent);
519begin
520 inherited;
521 SetLength(Registers, 16);
522 OpcodeHandlers[opNop] := OpcodeNop;
523 OpcodeHandlers[opHalt] := OpcodeHalt;
524 OpcodeHandlers[opLoad] := OpcodeLoad;
525 OpcodeHandlers[opLoadConst] := OpcodeLoadConst;
526 OpcodeHandlers[opNeg] := OpcodeNeg;
527 OpcodeHandlers[opJump] := OpcodeJump;
528 OpcodeHandlers[opInc] := OpcodeInc;
529 OpcodeHandlers[opDec] := OpcodeDec;
530 OpcodeHandlers[opJumpRel] := OpcodeJumpRel;
531 OpcodeHandlers[opLoadMem] := OpcodeLoadMem;
532 OpcodeHandlers[opStoreMem] := OpcodeStoreMem;
533 OpcodeHandlers[opExchg] := OpcodeExchange;
534 OpcodeHandlers[opAnd] := OpcodeAnd;
535 OpcodeHandlers[opOr] := OpcodeOr;
536 OpcodeHandlers[opXor] := OpcodeXor;
537 OpcodeHandlers[opShl] := OpcodeShl;
538 OpcodeHandlers[opShr] := OpcodeShr;
539 OpcodeHandlers[opPush] := OpcodePush;
540 OpcodeHandlers[opPop] := OpcodePop;
541 OpcodeHandlers[opCall] := OpcodeCall;
542 OpcodeHandlers[opCallRel] := OpcodeCallRel;
543 OpcodeHandlers[opRet] := OpcodeReturn;
544 OpcodeHandlers[opRor] := OpcodeRor;
545 OpcodeHandlers[opRol] := OpcodeRol;
546 OpcodeHandlers[opInput] := OpcodeInput;
547 OpcodeHandlers[opOutput] := OpcodeOutput;
548 OpcodeHandlers[opAdd] := OpcodeAdd;
549 OpcodeHandlers[opSub] := OpcodeSub;
550 OpcodeHandlers[opLdir] := OpcodeLdir;
551 OpcodeHandlers[opLddr] := OpcodeLddr;
552 OpcodeHandlers[opJumpCond] := OpcodeJumpCond;
553 OpcodeHandlers[opJumpRelCond] := OpcodeJumpRelCond;
554 OpcodeHandlers[opTestEqual] := OpcodeTestEqual;
555 OpcodeHandlers[opTestNotEqual] := OpcodeTestNotEqual;
556 OpcodeHandlers[opTestLess] := OpcodeTestLess;
557 OpcodeHandlers[opTestLessEqual] := OpcodeTestLessEqual;
558 OpcodeHandlers[opTestGreater] := OpcodeTestGreat;
559 OpcodeHandlers[opTestGreaterEqual] := OpcodeTestGreatEqual;
560 OpcodeHandlers[opTestZero] := OpcodeTestZero;
561 OpcodeHandlers[opTestNotZero] := OpcodeTestNotZero;
562 OpcodeHandlers[opMul] := OpcodeMul;
563 OpcodeHandlers[opDiv] := OpcodeDiv;
564 OpcodeHandlers[opClear] := OpcodeClear;
565 OpcodeHandlers[opMod] := OpcodeMod;
566end;
567
568
569end.
570
Note: See TracBrowser for help on using the repository browser.