source: branches/virtualcpu4/UCpu.pas

Last change on this file was 186, checked in by chronos, 5 years ago
  • Added: Partial implementation of compiler to Pascal source.
File size: 32.6 KB
Line 
1unit UCpu;
2
3{$mode delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils;
9
10type
11 TOpcode = (opNop, opHalt, opLoad, opLoadi, opJump, opJumpZero, opJumpNotZero,
12 opJumpRel, opJumpRelZero, opJumpRelNotZero, opNeg, opClear, opLoadMem,
13 opStoreMem, opExchg, opPush, opPop, opCall, opRet, opAdd, opAddi, opSub,
14 opSubi, opInc, opDec, opIn, opOut, opShl, opShr, opDataPrefix8, opDataPrefix16,
15 opDataPrefix32, opDataPrefix64, opDataSize, opAddrSize, opTest, opAnd, opOr,
16 opXor, opLddr, opLdir, opMul, opDiv, opMod, opAddrPrefix8, opAddrPrefix16,
17 opAddrPrefix32, opAddrPrefix64, opConvert);
18
19 TAddressSigned = Int64;
20 TAddress = QWord;
21 PAddress = ^TAddress;
22 TRegIndex = Byte;
23
24 TBitWidth = (bwNone, bw8, bw16, bw32, bw64);
25 TRegister = record
26 case TBitWidth of
27 bw8: (B: Byte);
28 bw16: (W: Word);
29 bw32: (D: DWord);
30 bw64: (Q: QWord);
31 end;
32
33 TInstructionEvent = procedure of object;
34 TInputEvent = function (Port: TAddress): TRegister of object;
35 TOutputEvent = procedure (Port: TAddress; Value: TRegister) of object;
36
37 TCpuThread = class;
38
39 { TCpu }
40
41 TCpu = class
42 private
43 FAddrSizeBase: TBitWidth;
44 FDataSizeBase: TBitWidth;
45 FOnInput: TInputEvent;
46 FOnOutput: TOutputEvent;
47 FRunning: Boolean;
48 FTicks: Integer;
49 Instructions: array[TOpcode] of TInstructionEvent;
50 Prefix: Boolean;
51 Z: Boolean;
52 Thread: TCpuThread;
53 procedure InstConvert;
54 procedure InstNop;
55 procedure InstHalt;
56 procedure InstLoad;
57 procedure InstLoadImmediate;
58 procedure InstJump;
59 procedure InstJumpZero;
60 procedure InstJumpNotZero;
61 procedure InstJumpRel;
62 procedure InstJumpRelZero;
63 procedure InstJumpRelNotZero;
64 procedure InstTest;
65 procedure InstNeg;
66 procedure InstClear;
67 procedure InstLoadMem;
68 procedure InstStoreMem;
69 procedure InstExchg;
70 procedure InstPush;
71 procedure InstPop;
72 procedure InstCall;
73 procedure InstRet;
74 procedure InstAdd;
75 procedure InstAddi;
76 procedure InstSub;
77 procedure InstSubi;
78 procedure InstMul;
79 procedure InstDiv;
80 procedure InstMod;
81 procedure InstInc;
82 procedure InstDec;
83 procedure InstIn;
84 procedure InstOut;
85 procedure InstShr;
86 procedure InstShl;
87 procedure InstAnd;
88 procedure InstOr;
89 procedure InstXor;
90 procedure InstLddr;
91 procedure InstLdir;
92 procedure InstDataPrefix8;
93 procedure InstDataPrefix16;
94 procedure InstDataPrefix32;
95 procedure InstDataPrefix64;
96 procedure InstDataSize;
97 procedure InstAddrPrefix8;
98 procedure InstAddrPrefix16;
99 procedure InstAddrPrefix32;
100 procedure InstAddrPrefix64;
101 procedure InstAddrSize;
102 procedure InitInstructions;
103 procedure SetAddrSizeBase(AValue: TBitWidth);
104 procedure SetDataSizeBase(AValue: TBitWidth);
105 public
106 Memory: Pointer;
107 Registers: array of TRegister;
108 Terminated: Boolean;
109 IP: TAddress;
110 SP: TAddress;
111 DataSize: TBitWidth;
112 AddrSize: TBitWidth;
113 procedure Run;
114 procedure Step; inline;
115 procedure Start;
116 procedure Stop;
117 function Read8: Byte; inline;
118 function Read16: Word; inline;
119 function Read32: DWord; inline;
120 function Read64: QWord; inline;
121 function ReadAddress: TAddress; inline;
122 function ReadAddressSigned: TAddressSigned; inline;
123 constructor Create;
124 destructor Destroy; override;
125 property DataSizeBase: TBitWidth read FDataSizeBase write SetDataSizeBase;
126 property AddrSizeBase: TBitWidth read FAddrSizeBase write SetAddrSizeBase;
127 property Ticks: Integer read FTicks;
128 property Running: Boolean read FRunning;
129 property OnInput: TInputEvent read FOnInput write FOnInput;
130 property OnOutput: TOutputEvent read FOnOutput write FOnOutput;
131 end;
132
133 { TCpuThread }
134
135 TCpuThread = class(TThread)
136 Cpu: TCpu;
137 procedure Execute; override;
138 end;
139
140const
141 BitWidthBytes: array[TBitWidth] of Byte = (0, 1, 2, 4, 8);
142 BitWidthText: array[TBitWidth] of string = ('None', '8-bit', '16-bit', '32-bit', '64-bit');
143
144implementation
145
146{ TCpuThread }
147
148procedure TCpuThread.Execute;
149begin
150 Cpu.Run;
151end;
152
153{ TCpu }
154
155procedure TCpu.InstNop;
156begin
157end;
158
159procedure TCpu.InstHalt;
160begin
161 Terminated := True;
162end;
163
164procedure TCpu.InstLoad;
165var
166 R1, R2: TRegIndex;
167begin
168 R1 := Read8;
169 R2 := Read8;
170 case DataSize of
171 bw8: Registers[R1].B := Registers[R2].B;
172 bw16: Registers[R1].W := Registers[R2].W;
173 bw32: Registers[R1].D := Registers[R2].D;
174 bw64: Registers[R1].Q := Registers[R2].Q;
175 end;
176end;
177
178procedure TCpu.InstLoadImmediate;
179var
180 R: TRegIndex;
181begin
182 R := Read8;
183 case DataSize of
184 bw8: Registers[R].B := Read8;
185 bw16: Registers[R].W := Read16;
186 bw32: Registers[R].D := Read32;
187 bw64: Registers[R].Q := Read64;
188 end;
189end;
190
191procedure TCpu.InstJump;
192begin
193 IP := ReadAddress;
194end;
195
196procedure TCpu.InstJumpZero;
197var
198 Addr: TAddress;
199begin
200 Addr := ReadAddress;
201 if Z then IP := Addr;
202end;
203
204procedure TCpu.InstJumpNotZero;
205var
206 Addr: TAddress;
207begin
208 Addr := ReadAddress;
209 if not Z then IP := Addr;
210end;
211
212procedure TCpu.InstJumpRel;
213begin
214 IP := IP + ReadAddressSigned;
215end;
216
217procedure TCpu.InstJumpRelZero;
218var
219 Addr: TAddressSigned;
220begin
221 Addr := ReadAddressSigned;
222 if Z then IP := IP + Addr;
223end;
224
225procedure TCpu.InstJumpRelNotZero;
226var
227 Addr: TAddressSigned;
228begin
229 Addr := ReadAddressSigned;
230 if not Z then IP := IP + Addr;
231end;
232
233procedure TCpu.InstTest;
234var
235 Reg: TRegIndex;
236begin
237 Reg := Read8;
238 case DataSize of
239 bw8: Z := Registers[Reg].B = 0;
240 bw16: Z := Registers[Reg].W = 0;
241 bw32: Z := Registers[Reg].D = 0;
242 bw64: Z := Registers[Reg].Q = 0;
243 end;
244end;
245
246procedure TCpu.InstNeg;
247var
248 Reg: TRegIndex;
249begin
250 Reg := Read8;
251 case DataSize of
252 bw8: Registers[Reg].B := -Registers[Reg].B;
253 bw16: Registers[Reg].W := -Registers[Reg].W;
254 bw32: Registers[Reg].D := -Registers[Reg].D;
255 bw64: Registers[Reg].Q := -Registers[Reg].Q;
256 end;
257end;
258
259procedure TCpu.InstClear;
260begin
261 case DataSize of
262 bw8: Registers[Read8].B := 0;
263 bw16: Registers[Read8].W := 0;
264 bw32: Registers[Read8].D := 0;
265 bw64: Registers[Read8].Q := 0;
266 end;
267end;
268
269procedure TCpu.InstLoadMem;
270var
271 R1, R2: TRegIndex;
272begin
273 R1 := Read8;
274 R2 := Read8;
275 case AddrSize of
276 bw8: case DataSize of
277 bw8: Registers[R1].B := PByte(Memory + Registers[R2].B)^;
278 bw16: Registers[R1].W := PWord(Memory + Registers[R2].B)^;
279 bw32: Registers[R1].D := PDWord(Memory + Registers[R2].B)^;
280 bw64: Registers[R1].Q := PQWord(Memory + Registers[R2].B)^;
281 end;
282 bw16: case DataSize of
283 bw8: Registers[R1].B := PByte(Memory + Registers[R2].W)^;
284 bw16: Registers[R1].W := PWord(Memory + Registers[R2].W)^;
285 bw32: Registers[R1].D := PDWord(Memory + Registers[R2].W)^;
286 bw64: Registers[R1].Q := PQWord(Memory + Registers[R2].W)^;
287 end;
288 bw32: case DataSize of
289 bw8: Registers[R1].B := PByte(Memory + Registers[R2].D)^;
290 bw16: Registers[R1].W := PWord(Memory + Registers[R2].D)^;
291 bw32: Registers[R1].D := PDWord(Memory + Registers[R2].D)^;
292 bw64: Registers[R1].Q := PQWord(Memory + Registers[R2].D)^;
293 end;
294 bw64: case DataSize of
295 bw8: Registers[R1].B := PByte(Memory + Registers[R2].Q)^;
296 bw16: Registers[R1].W := PWord(Memory + Registers[R2].Q)^;
297 bw32: Registers[R1].D := PDWord(Memory + Registers[R2].Q)^;
298 bw64: Registers[R1].Q := PQWord(Memory + Registers[R2].Q)^;
299 end;
300 end;
301end;
302
303procedure TCpu.InstStoreMem;
304var
305 R1, R2: TRegIndex;
306begin
307 R1 := Read8;
308 R2 := Read8;
309 case AddrSize of
310 bw8: case DataSize of
311 bw8: PByte(Memory + Registers[R1].B)^ := Registers[R2].B;
312 bw16: PWord(Memory + Registers[R1].B)^ := Registers[R2].W;
313 bw32: PDWord(Memory + Registers[R1].B)^ := Registers[R2].D;
314 bw64: PQWord(Memory + Registers[R1].B)^ := Registers[R2].Q;
315 end;
316 bw16: case DataSize of
317 bw8: PByte(Memory + Registers[R1].W)^ := Registers[R2].B;
318 bw16: PWord(Memory + Registers[R1].W)^ := Registers[R2].W;
319 bw32: PDWord(Memory + Registers[R1].W)^ := Registers[R2].D;
320 bw64: PQWord(Memory + Registers[R1].W)^ := Registers[R2].Q;
321 end;
322 bw32: case DataSize of
323 bw8: PByte(Memory + Registers[R1].D)^ := Registers[R2].B;
324 bw16: PWord(Memory + Registers[R1].D)^ := Registers[R2].W;
325 bw32: PDWord(Memory + Registers[R1].D)^ := Registers[R2].D;
326 bw64: PQWord(Memory + Registers[R1].D)^ := Registers[R2].Q;
327 end;
328 bw64: case DataSize of
329 bw8: PByte(Memory + Registers[R1].Q)^ := Registers[R2].B;
330 bw16: PWord(Memory + Registers[R1].Q)^ := Registers[R2].W;
331 bw32: PDWord(Memory + Registers[R1].Q)^ := Registers[R2].D;
332 bw64: PQWord(Memory + Registers[R1].Q)^ := Registers[R2].Q;
333 end;
334 end;
335end;
336
337procedure TCpu.InstExchg;
338var
339 Temp: TRegister;
340 R1, R2: TRegIndex;
341begin
342 R1 := Read8;
343 R2 := Read8;
344 case DataSize of
345 bw8: begin
346 Temp.B := Registers[R1].B;
347 Registers[R1].B := Registers[R2].B;
348 Registers[R2].B := Temp.B;
349 end;
350 bw16: begin
351 Temp.W := Registers[R1].W;
352 Registers[R1].W := Registers[R2].W;
353 Registers[R2].W := Temp.W;
354 end;
355 bw32: begin
356 Temp.D := Registers[R1].D;
357 Registers[R1].D := Registers[R2].D;
358 Registers[R2].D := Temp.D;
359 end;
360 bw64: begin
361 Temp.q := Registers[R1].Q;
362 Registers[R1].q := Registers[R2].Q;
363 Registers[R2].Q := Temp.Q;
364 end;
365 end;
366end;
367
368procedure TCpu.InstPush;
369begin
370 case DataSize of
371 bw8: begin
372 Dec(SP, SizeOf(Byte));
373 PByte(Memory + SP)^ := Registers[Read8].B;
374 end;
375 bw16: begin
376 Dec(SP, SizeOf(Word));
377 PWord(Memory + SP)^ := Registers[Read8].W;
378 end;
379 bw32: begin
380 Dec(SP, SizeOf(DWord));
381 PDWord(Memory + SP)^ := Registers[Read8].D;
382 end;
383 bw64: begin
384 Dec(SP, SizeOf(QWord));
385 PQWord(Memory + SP)^ := Registers[Read8].Q;
386 end;
387 end;
388end;
389
390procedure TCpu.InstPop;
391begin
392 case DataSize of
393 bw8: begin
394 Registers[Read8].B := PByte(Memory + SP)^;
395 Inc(SP, SizeOf(Byte));
396 end;
397 bw16: begin
398 Registers[Read8].W := PWord(Memory + SP)^;
399 Inc(SP, SizeOf(Word));
400 end;
401 bw32: begin
402 Registers[Read8].D := PDWord(Memory + SP)^;
403 Inc(SP, SizeOf(DWord));
404 end;
405 bw64: begin
406 Registers[Read8].Q := PQWord(Memory + SP)^;
407 Inc(SP, SizeOf(QWord));
408 end;
409 end;
410end;
411
412procedure TCpu.InstCall;
413var
414 Dest: TRegister;
415begin
416 case AddrSize of
417 bw8: begin
418 Dest.B := Read8;
419 Dec(SP, SizeOf(Byte));
420 PByte(Memory + SP)^ := Byte(IP);
421 IP := Dest.B;
422 end;
423 bw16: begin
424 Dest.W := Read16;
425 Dec(SP, SizeOf(Word));
426 PWord(Memory + SP)^ := Word(IP);
427 IP := Dest.W;
428 end;
429 bw32: begin
430 Dest.D := Read32;
431 Dec(SP, SizeOf(DWord));
432 PDWord(Memory + SP)^ := DWord(IP);
433 IP := Dest.D;
434 end;
435 bw64: begin
436 Dest.Q := Read64;
437 Dec(SP, SizeOf(QWord));
438 PQWord(Memory + SP)^ := QWord(IP);
439 IP := Dest.Q;
440 end;
441 end;
442end;
443
444procedure TCpu.InstRet;
445begin
446 case AddrSize of
447 bw8: begin
448 IP := PByte(Memory + SP)^;
449 Inc(SP, SizeOf(Byte));
450 end;
451 bw16: begin
452 IP := PWord(Memory + SP)^;
453 Inc(SP, SizeOf(Word));
454 end;
455 bw32: begin
456 IP := PDWord(Memory + SP)^;
457 Inc(SP, SizeOf(DWord));
458 end;
459 bw64: begin
460 IP := PQWord(Memory + SP)^;
461 Inc(SP, SizeOf(QWord));
462 end;
463 end;
464end;
465
466procedure TCpu.InstAdd;
467var
468 R1, R2: TRegIndex;
469begin
470 R1 := Read8;
471 R2 := Read8;
472 case DataSize of
473 bw8: Registers[R1].B := Registers[R1].B + Registers[R2].B;
474 bw16: Registers[R1].W := Registers[R1].W + Registers[R2].W;
475 bw32: Registers[R1].D := Registers[R1].D + Registers[R2].D;
476 bw64: Registers[R1].Q := Registers[R1].Q + Registers[R2].Q;
477 end;
478end;
479
480procedure TCpu.InstAddi;
481var
482 R: TRegIndex;
483begin
484 R := Read8;
485 case DataSize of
486 bw8: Registers[R].B := Registers[R].B + Read8;
487 bw16: Registers[R].W := Registers[R].W + Read16;
488 bw32: Registers[R].D := Registers[R].D + Read32;
489 bw64: Registers[R].Q := Registers[R].Q + Read64;
490 end;
491end;
492
493procedure TCpu.InstSub;
494var
495 R1, R2: TRegIndex;
496begin
497 R1 := Read8;
498 R2 := Read8;
499 case DataSize of
500 bw8: Registers[R1].B := Registers[R1].B - Registers[R2].B;
501 bw16: Registers[R1].W := Registers[R1].W - Registers[R2].W;
502 bw32: Registers[R1].D := Registers[R1].D - Registers[R2].D;
503 bw64: Registers[R1].Q := Registers[R1].Q - Registers[R2].Q;
504 end;
505end;
506
507procedure TCpu.InstSubi;
508var
509 R: TRegIndex;
510begin
511 R := Read8;
512 case DataSize of
513 bw8: Registers[R].B := Registers[R].B - Read8;
514 bw16: Registers[R].W := Registers[R].W - Read16;
515 bw32: Registers[R].D := Registers[R].D - Read32;
516 bw64: Registers[R].Q := Registers[R].Q - Read64;
517 end;
518end;
519
520procedure TCpu.InstMul;
521var
522 R1, R2: TRegIndex;
523begin
524 R1 := Read8;
525 R2 := Read8;
526 case DataSize of
527 bw8: Registers[R1].B := Registers[R1].B * Registers[R2].B;
528 bw16: Registers[R1].W := Registers[R1].W * Registers[R2].W;
529 bw32: Registers[R1].D := Registers[R1].D * Registers[R2].D;
530 bw64: Registers[R1].Q := Registers[R1].Q * Registers[R2].Q;
531 end;
532end;
533
534procedure TCpu.InstDiv;
535var
536 R1, R2: TRegIndex;
537begin
538 R1 := Read8;
539 R2 := Read8;
540 case DataSize of
541 bw8: Registers[R1].B := Registers[R1].B div Registers[R2].B;
542 bw16: Registers[R1].W := Registers[R1].W div Registers[R2].W;
543 bw32: Registers[R1].D := Registers[R1].D div Registers[R2].D;
544 bw64: Registers[R1].Q := Registers[R1].Q div Registers[R2].Q;
545 end;
546end;
547
548procedure TCpu.InstMod;
549var
550 R1, R2: TRegIndex;
551begin
552 R1 := Read8;
553 R2 := Read8;
554 case DataSize of
555 bw8: Registers[R1].B := Registers[R1].B mod Registers[R2].B;
556 bw16: Registers[R1].W := Registers[R1].W mod Registers[R2].W;
557 bw32: Registers[R1].D := Registers[R1].D mod Registers[R2].D;
558 bw64: Registers[R1].Q := Registers[R1].Q mod Registers[R2].Q;
559 end;
560end;
561
562procedure TCpu.InstInc;
563var
564 R1: TRegIndex;
565begin
566 R1 := Read8;
567 case DataSize of
568 bw8: Registers[R1].B := Registers[R1].B + 1;
569 bw16: Registers[R1].W := Registers[R1].W + 1;
570 bw32: Registers[R1].D := Registers[R1].D + 1;
571 bw64: Registers[R1].Q := Registers[R1].Q + 1;
572 end;
573end;
574
575procedure TCpu.InstDec;
576var
577 R: TRegIndex;
578begin
579 R := Read8;
580 case DataSize of
581 bw8: Registers[R].B := Registers[R].B - 1;
582 bw16: Registers[R].W := Registers[R].W - 1;
583 bw32: Registers[R].D := Registers[R].D - 1;
584 bw64: Registers[R].Q := Registers[R].Q - 1;
585 end;
586end;
587
588procedure TCpu.InstIn;
589var
590 R: TRegIndex;
591 Port: TAddress;
592begin
593 R := Read8;
594 Port := ReadAddress;
595 case DataSize of
596 bw8: begin
597 if Assigned(FOnInput) then Registers[R].B := FOnInput(Port).B
598 else Registers[R].B := 0;
599 end;
600 bw16: begin
601 if Assigned(FOnInput) then Registers[R].W := FOnInput(Port).W
602 else Registers[R].W := 0;
603 end;
604 bw32: begin
605 if Assigned(FOnInput) then Registers[R].D := FOnInput(Port).D
606 else Registers[R].D := 0;
607 end;
608 bw64: begin
609 if Assigned(FOnInput) then Registers[R].Q := FOnInput(Port).Q
610 else Registers[R].Q := 0;
611 end;
612 end;
613end;
614
615procedure TCpu.InstOut;
616var
617 R: TRegIndex;
618 Port: TAddress;
619 Value: TRegister;
620begin
621 Port := ReadAddress;
622 R := Read8;
623 case DataSize of
624 bw8: begin
625 Value.B := Registers[R].B;
626 if Assigned(FOnOutput) then
627 FOnOutput(Port, Value);
628 end;
629 bw16: begin
630 Value.W := Registers[R].W;
631 if Assigned(FOnOutput) then
632 FOnOutput(Port, Value);
633 end;
634 bw32: begin
635 Value.D := Registers[R].D;
636 if Assigned(FOnOutput) then
637 FOnOutput(Port, Value);
638 end;
639 bw64: begin
640 Value.Q := Registers[R].Q;
641 if Assigned(FOnOutput) then
642 FOnOutput(Port, Value);
643 end;
644 end;
645end;
646
647procedure TCpu.InstShr;
648var
649 R: TRegIndex;
650begin
651 R := Read8;
652 case DataSize of
653 bw8: Registers[R].B := Registers[R].B shr Read8;
654 bw16: Registers[R].W := Registers[R].W shr Read16;
655 bw32: Registers[R].D := Registers[R].D shr Read32;
656 bw64: Registers[R].Q := Registers[R].Q shr Read64;
657 end;
658end;
659
660procedure TCpu.InstShl;
661var
662 R: TRegIndex;
663begin
664 R := Read8;
665 case DataSize of
666 bw8: Registers[R].B := Registers[R].B shl Read8;
667 bw16: Registers[R].W := Registers[R].W shl Read16;
668 bw32: Registers[R].D := Registers[R].D shl Read32;
669 bw64: Registers[R].Q := Registers[R].Q shl Read64;
670 end;
671end;
672
673procedure TCpu.InstAnd;
674var
675 R1, R2: TRegIndex;
676begin
677 R1 := Read8;
678 R2 := Read8;
679 case DataSize of
680 bw8: Registers[R1].B := Registers[R1].B and Registers[R2].B;
681 bw16: Registers[R1].W := Registers[R1].W and Registers[R2].W;
682 bw32: Registers[R1].D := Registers[R1].D and Registers[R2].D;
683 bw64: Registers[R1].Q := Registers[R1].Q and Registers[R2].Q;
684 end;
685end;
686
687procedure TCpu.InstOr;
688var
689 R1, R2: TRegIndex;
690begin
691 R1 := Read8;
692 R2 := Read8;
693 case DataSize of
694 bw8: Registers[R1].B := Registers[R1].B or Registers[R2].B;
695 bw16: Registers[R1].W := Registers[R1].W or Registers[R2].W;
696 bw32: Registers[R1].D := Registers[R1].D or Registers[R2].D;
697 bw64: Registers[R1].Q := Registers[R1].Q or Registers[R2].Q;
698 end;
699end;
700
701procedure TCpu.InstXor;
702var
703 R1, R2: TRegIndex;
704begin
705 R1 := Read8;
706 R2 := Read8;
707 case DataSize of
708 bw8: Registers[R1].B := Registers[R1].B xor Registers[R2].B;
709 bw16: Registers[R1].W := Registers[R1].W xor Registers[R2].W;
710 bw32: Registers[R1].D := Registers[R1].D xor Registers[R2].D;
711 bw64: Registers[R1].Q := Registers[R1].Q xor Registers[R2].Q;
712 end;
713end;
714
715procedure TCpu.InstConvert;
716var
717 R: TRegIndex;
718begin
719 R := Read8;
720 case AddrSize of
721 bw8: case DataSize of
722 bw8: Registers[R].B := Registers[R].B;
723 bw16: Registers[R].B := Registers[R].W;
724 bw32: Registers[R].B := Registers[R].D;
725 bw64: Registers[R].B := Registers[R].Q;
726 end;
727 bw16: case DataSize of
728 bw8: Registers[R].W := Registers[R].B;
729 bw16: Registers[R].W := Registers[R].W;
730 bw32: Registers[R].W := Registers[R].D;
731 bw64: Registers[R].W := Registers[R].Q;
732 end;
733 bw32: case DataSize of
734 bw8: Registers[R].D := Registers[R].B;
735 bw16: Registers[R].D := Registers[R].W;
736 bw32: Registers[R].D := Registers[R].D;
737 bw64: Registers[R].D := Registers[R].Q;
738 end;
739 bw64: case DataSize of
740 bw8: Registers[R].Q := Registers[R].B;
741 bw16: Registers[R].Q := Registers[R].W;
742 bw32: Registers[R].Q := Registers[R].D;
743 bw64: Registers[R].Q := Registers[R].Q;
744 end;
745 end;
746end;
747
748
749procedure TCpu.InstLddr;
750var
751 Source, Dest, Count: TRegIndex;
752begin
753 Source := Read8;
754 Dest := Read8;
755 Count := Read8;
756 case AddrSize of
757 bw8: while Registers[Count].B > 0 do begin
758 case DataSize of
759 bw8: begin
760 PByte(Memory + Registers[Dest].B)^ := PByte(Memory + Registers[Source].B)^;
761 Dec(Registers[Dest].B, SizeOf(Byte));
762 Dec(Registers[Source].B, SizeOf(Byte));
763 end;
764 bw16: begin
765 PWord(Memory + Registers[Dest].B)^ := PWord(Memory + Registers[Source].B)^;
766 Dec(Registers[Dest].B, SizeOf(Word));
767 Dec(Registers[Source].B, SizeOf(Word));
768 end;
769 bw32: begin
770 PDWord(Memory + Registers[Dest].B)^ := PDWord(Memory + Registers[Source].B)^;
771 Dec(Registers[Dest].B, SizeOf(DWord));
772 Dec(Registers[Source].B, SizeOf(DWord));
773 end;
774 bw64: begin
775 PQWord(Memory + Registers[Dest].B)^ := PQWord(Memory + Registers[Source].B)^;
776 Dec(Registers[Dest].B, SizeOf(QWord));
777 Dec(Registers[Source].B, SizeOf(QWord));
778 end;
779 end;
780 Dec(Registers[Count].B);
781 end;
782 bw16: while Registers[Count].W > 0 do begin
783 case DataSize of
784 bw8: begin
785 PByte(Memory + Registers[Dest].W)^ := PByte(Memory + Registers[Source].W)^;
786 Dec(Registers[Dest].W, SizeOf(Byte));
787 Dec(Registers[Source].W, SizeOf(Byte));
788 end;
789 bw16: begin
790 PWord(Memory + Registers[Dest].W)^ := PWord(Memory + Registers[Source].W)^;
791 Dec(Registers[Dest].W, SizeOf(Word));
792 Dec(Registers[Source].W, SizeOf(Word));
793 end;
794 bw32: begin
795 PDWord(Memory + Registers[Dest].W)^ := PDWord(Memory + Registers[Source].W)^;
796 Dec(Registers[Dest].W, SizeOf(DWord));
797 Dec(Registers[Source].W, SizeOf(DWord));
798 end;
799 bw64: begin
800 PQWord(Memory + Registers[Dest].W)^ := PQWord(Memory + Registers[Source].W)^;
801 Dec(Registers[Dest].W, SizeOf(QWord));
802 Dec(Registers[Source].W, SizeOf(QWord));
803 end;
804 end;
805 Dec(Registers[Count].W);
806 end;
807 bw32: while Registers[Count].D > 0 do begin
808 case DataSize of
809 bw8: begin
810 PByte(Memory + Registers[Dest].D)^ := PByte(Memory + Registers[Source].D)^;
811 Dec(Registers[Dest].D, SizeOf(Byte));
812 Dec(Registers[Source].D, SizeOf(Byte));
813 end;
814 bw16: begin
815 PWord(Memory + Registers[Dest].D)^ := PWord(Memory + Registers[Source].D)^;
816 Dec(Registers[Dest].D, SizeOf(Word));
817 Dec(Registers[Source].D, SizeOf(Word));
818 end;
819 bw32: begin
820 PDWord(Memory + Registers[Dest].W)^ := PDWord(Memory + Registers[Source].D)^;
821 Dec(Registers[Dest].D, SizeOf(DWord));
822 Dec(Registers[Source].D, SizeOf(DWord));
823 end;
824 bw64: begin
825 PQWord(Memory + Registers[Dest].D)^ := PQWord(Memory + Registers[Source].D)^;
826 Dec(Registers[Dest].D, SizeOf(QWord));
827 Dec(Registers[Source].D, SizeOf(QWord));
828 end;
829 end;
830 Dec(Registers[Count].D);
831 end;
832 bw64: while Registers[Count].Q > 0 do begin
833 case DataSize of
834 bw8: begin
835 PByte(Memory + Registers[Dest].Q)^ := PByte(Memory + Registers[Source].Q)^;
836 Dec(Registers[Dest].Q, SizeOf(Byte));
837 Dec(Registers[Source].Q, SizeOf(Byte));
838 end;
839 bw16: begin
840 PWord(Memory + Registers[Dest].Q)^ := PWord(Memory + Registers[Source].Q)^;
841 Dec(Registers[Dest].Q, SizeOf(Word));
842 Dec(Registers[Source].Q, SizeOf(Word));
843 end;
844 bw32: begin
845 PDWord(Memory + Registers[Dest].Q)^ := PDWord(Memory + Registers[Source].Q)^;
846 Dec(Registers[Dest].Q, SizeOf(DWord));
847 Dec(Registers[Source].Q, SizeOf(DWord));
848 end;
849 bw64: begin
850 PQWord(Memory + Registers[Dest].Q)^ := PQWord(Memory + Registers[Source].Q)^;
851 Dec(Registers[Dest].Q, SizeOf(QWord));
852 Dec(Registers[Source].Q, SizeOf(QWord));
853 end;
854 end;
855 Dec(Registers[Count].W);
856 end;
857 end;
858end;
859
860procedure TCpu.InstLdir;
861var
862 Source, Dest, Count: TRegIndex;
863begin
864 Source := Read8;
865 Dest := Read8;
866 Count := Read8;
867 case AddrSize of
868 bw8: while Registers[Count].B > 0 do begin
869 case DataSize of
870 bw8: begin
871 PByte(Memory + Registers[Dest].B)^ := PByte(Memory + Registers[Source].B)^;
872 Inc(Registers[Dest].B, SizeOf(Byte));
873 Inc(Registers[Source].B, SizeOf(Byte));
874 end;
875 bw16: begin
876 PWord(Memory + Registers[Dest].B)^ := PWord(Memory + Registers[Source].B)^;
877 Inc(Registers[Dest].B, SizeOf(Word));
878 Inc(Registers[Source].B, SizeOf(Word));
879 end;
880 bw32: begin
881 PDWord(Memory + Registers[Dest].B)^ := PDWord(Memory + Registers[Source].B)^;
882 Inc(Registers[Dest].B, SizeOf(DWord));
883 Inc(Registers[Source].B, SizeOf(DWord));
884 end;
885 bw64: begin
886 PQWord(Memory + Registers[Dest].B)^ := PQWord(Memory + Registers[Source].B)^;
887 Inc(Registers[Dest].B, SizeOf(QWord));
888 Inc(Registers[Source].B, SizeOf(QWord));
889 end;
890 end;
891 Dec(Registers[Count].B);
892 end;
893 bw16: while Registers[Count].W > 0 do begin
894 case DataSize of
895 bw8: begin
896 PByte(Memory + Registers[Dest].W)^ := PByte(Memory + Registers[Source].W)^;
897 Inc(Registers[Dest].W, SizeOf(Byte));
898 Inc(Registers[Source].W, SizeOf(Byte));
899 end;
900 bw16: begin
901 PWord(Memory + Registers[Dest].W)^ := PWord(Memory + Registers[Source].W)^;
902 Inc(Registers[Dest].W, SizeOf(Word));
903 Inc(Registers[Source].W, SizeOf(Word));
904 end;
905 bw32: begin
906 PDWord(Memory + Registers[Dest].W)^ := PDWord(Memory + Registers[Source].W)^;
907 Inc(Registers[Dest].W, SizeOf(DWord));
908 Inc(Registers[Source].W, SizeOf(DWord));
909 end;
910 bw64: begin
911 PQWord(Memory + Registers[Dest].W)^ := PQWord(Memory + Registers[Source].W)^;
912 Inc(Registers[Dest].W, SizeOf(QWord));
913 Inc(Registers[Source].W, SizeOf(QWord));
914 end;
915 end;
916 Dec(Registers[Count].W);
917 end;
918 bw32: while Registers[Count].D > 0 do begin
919 case DataSize of
920 bw8: begin
921 PByte(Memory + Registers[Dest].D)^ := PByte(Memory + Registers[Source].D)^;
922 Inc(Registers[Dest].D, SizeOf(Byte));
923 Inc(Registers[Source].D, SizeOf(Byte));
924 end;
925 bw16: begin
926 PWord(Memory + Registers[Dest].D)^ := PWord(Memory + Registers[Source].D)^;
927 Inc(Registers[Dest].D, SizeOf(Word));
928 Inc(Registers[Source].D, SizeOf(Word));
929 end;
930 bw32: begin
931 PDWord(Memory + Registers[Dest].W)^ := PDWord(Memory + Registers[Source].D)^;
932 Inc(Registers[Dest].D, SizeOf(DWord));
933 Inc(Registers[Source].D, SizeOf(DWord));
934 end;
935 bw64: begin
936 PQWord(Memory + Registers[Dest].D)^ := PQWord(Memory + Registers[Source].D)^;
937 Inc(Registers[Dest].D, SizeOf(QWord));
938 Inc(Registers[Source].D, SizeOf(QWord));
939 end;
940 end;
941 Dec(Registers[Count].D);
942 end;
943 bw64: while Registers[Count].Q > 0 do begin
944 case DataSize of
945 bw8: begin
946 PByte(Memory + Registers[Dest].Q)^ := PByte(Memory + Registers[Source].Q)^;
947 Inc(Registers[Dest].Q, SizeOf(Byte));
948 Inc(Registers[Source].Q, SizeOf(Byte));
949 end;
950 bw16: begin
951 PWord(Memory + Registers[Dest].Q)^ := PWord(Memory + Registers[Source].Q)^;
952 Inc(Registers[Dest].Q, SizeOf(Word));
953 Inc(Registers[Source].Q, SizeOf(Word));
954 end;
955 bw32: begin
956 PDWord(Memory + Registers[Dest].Q)^ := PDWord(Memory + Registers[Source].Q)^;
957 Inc(Registers[Dest].Q, SizeOf(DWord));
958 Inc(Registers[Source].Q, SizeOf(DWord));
959 end;
960 bw64: begin
961 PQWord(Memory + Registers[Dest].Q)^ := PQWord(Memory + Registers[Source].Q)^;
962 Inc(Registers[Dest].Q, SizeOf(QWord));
963 Inc(Registers[Source].Q, SizeOf(QWord));
964 end;
965 end;
966 Dec(Registers[Count].W);
967 end;
968 end;
969end;
970
971procedure TCpu.InstDataPrefix8;
972begin
973 DataSize := bw8;
974 Prefix := True;
975end;
976
977procedure TCpu.InstDataPrefix16;
978begin
979 DataSize := bw16;
980 Prefix := True;
981end;
982
983procedure TCpu.InstDataPrefix32;
984begin
985 DataSize := bw32;
986 Prefix := True;
987end;
988
989procedure TCpu.InstDataPrefix64;
990begin
991 DataSize := bw64;
992 Prefix := True;
993end;
994
995procedure TCpu.InstDataSize;
996begin
997 DataSizeBase := TBitWidth(Read8);
998 DataSize := DataSizeBase;
999end;
1000
1001procedure TCpu.InstAddrPrefix8;
1002begin
1003 AddrSize := bw8;
1004 Prefix := True;
1005end;
1006
1007procedure TCpu.InstAddrPrefix16;
1008begin
1009 AddrSize := bw16;
1010 Prefix := True;
1011end;
1012
1013procedure TCpu.InstAddrPrefix32;
1014begin
1015 AddrSize := bw32;
1016 Prefix := True;
1017end;
1018
1019procedure TCpu.InstAddrPrefix64;
1020begin
1021 AddrSize := bw64;
1022 Prefix := True;
1023end;
1024
1025procedure TCpu.InstAddrSize;
1026begin
1027 AddrSizeBase := TBitWidth(Read8);
1028 AddrSize := AddrSizeBase;
1029end;
1030
1031procedure TCpu.InitInstructions;
1032begin
1033 Instructions[opNop] := InstNop;
1034 Instructions[opHalt] := InstHalt;
1035 Instructions[opLoad] := InstLoad;
1036 Instructions[opLoadi] := InstLoadImmediate;
1037 Instructions[opJump] := InstJump;
1038 Instructions[opJumpNotZero] := InstJumpNotZero;
1039 Instructions[opJumpZero] := InstJumpZero;
1040 Instructions[opJumpRel] := InstJumpRel;
1041 Instructions[opJumpRelNotZero] := InstJumpRelNotZero;
1042 Instructions[opJumpRelZero] := InstJumpRelZero;
1043 Instructions[opLoadMem] := InstLoadMem;
1044 Instructions[opStoreMem] := InstStoreMem;
1045 Instructions[opClear] := InstClear;
1046 Instructions[opNeg] := InstNeg;
1047 Instructions[opExchg] := InstExchg;
1048 Instructions[opPop] := InstPop;
1049 Instructions[opPush] := InstPush;
1050 Instructions[opCall] := InstCall;
1051 Instructions[opRet] := InstRet;
1052 Instructions[opAdd] := InstAdd;
1053 Instructions[opAddi] := InstAddi;
1054 Instructions[opSub] := InstSub;
1055 Instructions[opSubi] := InstSubi;
1056 Instructions[opInc] := InstInc;
1057 Instructions[opDec] := InstDec;
1058 Instructions[opIn] := InstIn;
1059 Instructions[opOut] := InstOut;
1060 Instructions[opShr] := InstShr;
1061 Instructions[opShl] := InstShl;
1062 Instructions[opDataSize] := InstDataSize;
1063 Instructions[opDataPrefix8] := InstDataPrefix8;
1064 Instructions[opDataPrefix16] := InstDataPrefix16;
1065 Instructions[opDataPrefix32] := InstDataPrefix32;
1066 Instructions[opDataPrefix64] := InstDataPrefix64;
1067 Instructions[opAddrSize] := InstAddrSize;
1068 Instructions[opAddrPrefix8] := InstAddrPrefix8;
1069 Instructions[opAddrPrefix16] := InstAddrPrefix16;
1070 Instructions[opAddrPrefix32] := InstAddrPrefix32;
1071 Instructions[opAddrPrefix64] := InstAddrPrefix64;
1072 Instructions[opTest] := InstTest;
1073 Instructions[opAnd] := InstAnd;
1074 Instructions[opOr] := InstOr;
1075 Instructions[opXor] := InstXor;
1076 Instructions[opLdir] := InstLdir;
1077 Instructions[opLddr] := InstLddr;
1078 Instructions[opMul] := InstMul;
1079 Instructions[opDiv] := InstDiv;
1080 Instructions[opMod] := InstMod;
1081 Instructions[opConvert] := InstConvert;
1082end;
1083
1084procedure TCpu.SetAddrSizeBase(AValue: TBitWidth);
1085begin
1086 if FAddrSizeBase = AValue then Exit;
1087 FAddrSizeBase := AValue;
1088 AddrSize := AValue;
1089end;
1090
1091procedure TCpu.SetDataSizeBase(AValue: TBitWidth);
1092begin
1093 if FDataSizeBase = AValue then Exit;
1094 FDataSizeBase := AValue;
1095 DataSize := AValue;
1096end;
1097
1098procedure TCpu.Run;
1099begin
1100 DataSize := DataSizeBase;
1101 AddrSize := AddrSizeBase;
1102 Terminated := False;
1103 FTicks := 0;
1104 IP := 0;
1105 SP := MemSize(Memory);
1106 while not Terminated do
1107 Step;
1108end;
1109
1110procedure TCpu.Step;
1111var
1112 Opcode: Byte;
1113begin
1114 Prefix := False;
1115 Opcode := Read8;
1116 if Opcode < Length(Instructions) then begin
1117 if Assigned(Instructions[TOpcode(Opcode)]) then Instructions[TOpcode(Opcode)]
1118 else raise Exception.Create('Missing instruction handler for opcode '+ IntToStr(Opcode));
1119 end else raise Exception.Create('Unsupported opcode ' + IntToStr(Opcode) + ' at address ' + IntToHex(IP - 1, 8) + '.');
1120 if not Prefix then begin
1121 DataSize := DataSizeBase;
1122 AddrSize := AddrSizeBase;
1123 end;
1124 IP := IP mod MemSize(Memory);
1125 Inc(FTicks);
1126end;
1127
1128procedure TCpu.Start;
1129begin
1130 if not Running then begin
1131 Terminated := False;
1132 Thread := TCpuThread.Create(True);
1133 Thread.Cpu := Self;
1134 Thread.Start;
1135 FRunning := True;
1136 end;
1137end;
1138
1139procedure TCpu.Stop;
1140begin
1141 if Running then begin
1142 Terminated := True;
1143 Thread.Terminate;
1144 Thread.WaitFor;
1145 FreeAndNil(Thread);
1146 FRunning := False;
1147 end;
1148end;
1149
1150function TCpu.Read8: Byte;
1151begin
1152 Result := PByte(Memory + IP)^;
1153 Inc(IP);
1154end;
1155
1156function TCpu.Read16: Word;
1157begin
1158 Result := PWord(Memory + IP)^;
1159 Inc(IP, SizeOf(Word));
1160end;
1161
1162function TCpu.Read32: DWord;
1163begin
1164 Result := PDWord(Memory + IP)^;
1165 Inc(IP, SizeOf(DWord));
1166end;
1167
1168function TCpu.Read64: QWord;
1169begin
1170 Result := PQWord(Memory + IP)^;
1171 Inc(IP, SizeOf(QWord));
1172end;
1173
1174function TCpu.ReadAddress: TAddress;
1175begin
1176 case AddrSize of
1177 bw8: Result := Read8;
1178 bw16: Result := Read16;
1179 bw32: Result := Read32;
1180 bw64: Result := Read64;
1181 end;
1182end;
1183
1184function TCpu.ReadAddressSigned: TAddressSigned;
1185begin
1186 case AddrSize of
1187 bw8: Result := ShortInt(Read8);
1188 bw16: Result := SmallInt(Read16);
1189 bw32: Result := Integer(Read32);
1190 bw64: Result := Int64(Read64);
1191 end;
1192end;
1193
1194constructor TCpu.Create;
1195begin
1196 DataSizeBase := bw16;
1197 AddrSizeBase := bw16;
1198 SetLength(Registers, 32);
1199 InitInstructions;
1200end;
1201
1202destructor TCpu.Destroy;
1203begin
1204 Stop;
1205 inherited Destroy;
1206end;
1207
1208end.
1209
Note: See TracBrowser for help on using the repository browser.