1 | unit UCpu;
|
---|
2 |
|
---|
3 | {$mode delphi}{$H+}
|
---|
4 |
|
---|
5 | interface
|
---|
6 |
|
---|
7 | uses
|
---|
8 | Classes, SysUtils;
|
---|
9 |
|
---|
10 | type
|
---|
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 |
|
---|
140 | const
|
---|
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 |
|
---|
144 | implementation
|
---|
145 |
|
---|
146 | { TCpuThread }
|
---|
147 |
|
---|
148 | procedure TCpuThread.Execute;
|
---|
149 | begin
|
---|
150 | Cpu.Run;
|
---|
151 | end;
|
---|
152 |
|
---|
153 | { TCpu }
|
---|
154 |
|
---|
155 | procedure TCpu.InstNop;
|
---|
156 | begin
|
---|
157 | end;
|
---|
158 |
|
---|
159 | procedure TCpu.InstHalt;
|
---|
160 | begin
|
---|
161 | Terminated := True;
|
---|
162 | end;
|
---|
163 |
|
---|
164 | procedure TCpu.InstLoad;
|
---|
165 | var
|
---|
166 | R1, R2: TRegIndex;
|
---|
167 | begin
|
---|
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;
|
---|
176 | end;
|
---|
177 |
|
---|
178 | procedure TCpu.InstLoadImmediate;
|
---|
179 | var
|
---|
180 | R: TRegIndex;
|
---|
181 | begin
|
---|
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;
|
---|
189 | end;
|
---|
190 |
|
---|
191 | procedure TCpu.InstJump;
|
---|
192 | begin
|
---|
193 | IP := ReadAddress;
|
---|
194 | end;
|
---|
195 |
|
---|
196 | procedure TCpu.InstJumpZero;
|
---|
197 | var
|
---|
198 | Addr: TAddress;
|
---|
199 | begin
|
---|
200 | Addr := ReadAddress;
|
---|
201 | if Z then IP := Addr;
|
---|
202 | end;
|
---|
203 |
|
---|
204 | procedure TCpu.InstJumpNotZero;
|
---|
205 | var
|
---|
206 | Addr: TAddress;
|
---|
207 | begin
|
---|
208 | Addr := ReadAddress;
|
---|
209 | if not Z then IP := Addr;
|
---|
210 | end;
|
---|
211 |
|
---|
212 | procedure TCpu.InstJumpRel;
|
---|
213 | begin
|
---|
214 | IP := IP + ReadAddressSigned;
|
---|
215 | end;
|
---|
216 |
|
---|
217 | procedure TCpu.InstJumpRelZero;
|
---|
218 | var
|
---|
219 | Addr: TAddressSigned;
|
---|
220 | begin
|
---|
221 | Addr := ReadAddressSigned;
|
---|
222 | if Z then IP := IP + Addr;
|
---|
223 | end;
|
---|
224 |
|
---|
225 | procedure TCpu.InstJumpRelNotZero;
|
---|
226 | var
|
---|
227 | Addr: TAddressSigned;
|
---|
228 | begin
|
---|
229 | Addr := ReadAddressSigned;
|
---|
230 | if not Z then IP := IP + Addr;
|
---|
231 | end;
|
---|
232 |
|
---|
233 | procedure TCpu.InstTest;
|
---|
234 | var
|
---|
235 | Reg: TRegIndex;
|
---|
236 | begin
|
---|
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;
|
---|
244 | end;
|
---|
245 |
|
---|
246 | procedure TCpu.InstNeg;
|
---|
247 | var
|
---|
248 | Reg: TRegIndex;
|
---|
249 | begin
|
---|
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;
|
---|
257 | end;
|
---|
258 |
|
---|
259 | procedure TCpu.InstClear;
|
---|
260 | begin
|
---|
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;
|
---|
267 | end;
|
---|
268 |
|
---|
269 | procedure TCpu.InstLoadMem;
|
---|
270 | var
|
---|
271 | R1, R2: TRegIndex;
|
---|
272 | begin
|
---|
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;
|
---|
301 | end;
|
---|
302 |
|
---|
303 | procedure TCpu.InstStoreMem;
|
---|
304 | var
|
---|
305 | R1, R2: TRegIndex;
|
---|
306 | begin
|
---|
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;
|
---|
335 | end;
|
---|
336 |
|
---|
337 | procedure TCpu.InstExchg;
|
---|
338 | var
|
---|
339 | Temp: TRegister;
|
---|
340 | R1, R2: TRegIndex;
|
---|
341 | begin
|
---|
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;
|
---|
366 | end;
|
---|
367 |
|
---|
368 | procedure TCpu.InstPush;
|
---|
369 | begin
|
---|
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;
|
---|
388 | end;
|
---|
389 |
|
---|
390 | procedure TCpu.InstPop;
|
---|
391 | begin
|
---|
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;
|
---|
410 | end;
|
---|
411 |
|
---|
412 | procedure TCpu.InstCall;
|
---|
413 | var
|
---|
414 | Dest: TRegister;
|
---|
415 | begin
|
---|
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;
|
---|
442 | end;
|
---|
443 |
|
---|
444 | procedure TCpu.InstRet;
|
---|
445 | begin
|
---|
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;
|
---|
464 | end;
|
---|
465 |
|
---|
466 | procedure TCpu.InstAdd;
|
---|
467 | var
|
---|
468 | R1, R2: TRegIndex;
|
---|
469 | begin
|
---|
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;
|
---|
478 | end;
|
---|
479 |
|
---|
480 | procedure TCpu.InstAddi;
|
---|
481 | var
|
---|
482 | R: TRegIndex;
|
---|
483 | begin
|
---|
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;
|
---|
491 | end;
|
---|
492 |
|
---|
493 | procedure TCpu.InstSub;
|
---|
494 | var
|
---|
495 | R1, R2: TRegIndex;
|
---|
496 | begin
|
---|
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;
|
---|
505 | end;
|
---|
506 |
|
---|
507 | procedure TCpu.InstSubi;
|
---|
508 | var
|
---|
509 | R: TRegIndex;
|
---|
510 | begin
|
---|
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;
|
---|
518 | end;
|
---|
519 |
|
---|
520 | procedure TCpu.InstMul;
|
---|
521 | var
|
---|
522 | R1, R2: TRegIndex;
|
---|
523 | begin
|
---|
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;
|
---|
532 | end;
|
---|
533 |
|
---|
534 | procedure TCpu.InstDiv;
|
---|
535 | var
|
---|
536 | R1, R2: TRegIndex;
|
---|
537 | begin
|
---|
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;
|
---|
546 | end;
|
---|
547 |
|
---|
548 | procedure TCpu.InstMod;
|
---|
549 | var
|
---|
550 | R1, R2: TRegIndex;
|
---|
551 | begin
|
---|
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;
|
---|
560 | end;
|
---|
561 |
|
---|
562 | procedure TCpu.InstInc;
|
---|
563 | var
|
---|
564 | R1: TRegIndex;
|
---|
565 | begin
|
---|
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;
|
---|
573 | end;
|
---|
574 |
|
---|
575 | procedure TCpu.InstDec;
|
---|
576 | var
|
---|
577 | R: TRegIndex;
|
---|
578 | begin
|
---|
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;
|
---|
586 | end;
|
---|
587 |
|
---|
588 | procedure TCpu.InstIn;
|
---|
589 | var
|
---|
590 | R: TRegIndex;
|
---|
591 | Port: TAddress;
|
---|
592 | begin
|
---|
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;
|
---|
613 | end;
|
---|
614 |
|
---|
615 | procedure TCpu.InstOut;
|
---|
616 | var
|
---|
617 | R: TRegIndex;
|
---|
618 | Port: TAddress;
|
---|
619 | Value: TRegister;
|
---|
620 | begin
|
---|
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;
|
---|
645 | end;
|
---|
646 |
|
---|
647 | procedure TCpu.InstShr;
|
---|
648 | var
|
---|
649 | R: TRegIndex;
|
---|
650 | begin
|
---|
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;
|
---|
658 | end;
|
---|
659 |
|
---|
660 | procedure TCpu.InstShl;
|
---|
661 | var
|
---|
662 | R: TRegIndex;
|
---|
663 | begin
|
---|
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;
|
---|
671 | end;
|
---|
672 |
|
---|
673 | procedure TCpu.InstAnd;
|
---|
674 | var
|
---|
675 | R1, R2: TRegIndex;
|
---|
676 | begin
|
---|
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;
|
---|
685 | end;
|
---|
686 |
|
---|
687 | procedure TCpu.InstOr;
|
---|
688 | var
|
---|
689 | R1, R2: TRegIndex;
|
---|
690 | begin
|
---|
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;
|
---|
699 | end;
|
---|
700 |
|
---|
701 | procedure TCpu.InstXor;
|
---|
702 | var
|
---|
703 | R1, R2: TRegIndex;
|
---|
704 | begin
|
---|
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;
|
---|
713 | end;
|
---|
714 |
|
---|
715 | procedure TCpu.InstConvert;
|
---|
716 | var
|
---|
717 | R: TRegIndex;
|
---|
718 | begin
|
---|
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;
|
---|
746 | end;
|
---|
747 |
|
---|
748 |
|
---|
749 | procedure TCpu.InstLddr;
|
---|
750 | var
|
---|
751 | Source, Dest, Count: TRegIndex;
|
---|
752 | begin
|
---|
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;
|
---|
858 | end;
|
---|
859 |
|
---|
860 | procedure TCpu.InstLdir;
|
---|
861 | var
|
---|
862 | Source, Dest, Count: TRegIndex;
|
---|
863 | begin
|
---|
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;
|
---|
969 | end;
|
---|
970 |
|
---|
971 | procedure TCpu.InstDataPrefix8;
|
---|
972 | begin
|
---|
973 | DataSize := bw8;
|
---|
974 | Prefix := True;
|
---|
975 | end;
|
---|
976 |
|
---|
977 | procedure TCpu.InstDataPrefix16;
|
---|
978 | begin
|
---|
979 | DataSize := bw16;
|
---|
980 | Prefix := True;
|
---|
981 | end;
|
---|
982 |
|
---|
983 | procedure TCpu.InstDataPrefix32;
|
---|
984 | begin
|
---|
985 | DataSize := bw32;
|
---|
986 | Prefix := True;
|
---|
987 | end;
|
---|
988 |
|
---|
989 | procedure TCpu.InstDataPrefix64;
|
---|
990 | begin
|
---|
991 | DataSize := bw64;
|
---|
992 | Prefix := True;
|
---|
993 | end;
|
---|
994 |
|
---|
995 | procedure TCpu.InstDataSize;
|
---|
996 | begin
|
---|
997 | DataSizeBase := TBitWidth(Read8);
|
---|
998 | DataSize := DataSizeBase;
|
---|
999 | end;
|
---|
1000 |
|
---|
1001 | procedure TCpu.InstAddrPrefix8;
|
---|
1002 | begin
|
---|
1003 | AddrSize := bw8;
|
---|
1004 | Prefix := True;
|
---|
1005 | end;
|
---|
1006 |
|
---|
1007 | procedure TCpu.InstAddrPrefix16;
|
---|
1008 | begin
|
---|
1009 | AddrSize := bw16;
|
---|
1010 | Prefix := True;
|
---|
1011 | end;
|
---|
1012 |
|
---|
1013 | procedure TCpu.InstAddrPrefix32;
|
---|
1014 | begin
|
---|
1015 | AddrSize := bw32;
|
---|
1016 | Prefix := True;
|
---|
1017 | end;
|
---|
1018 |
|
---|
1019 | procedure TCpu.InstAddrPrefix64;
|
---|
1020 | begin
|
---|
1021 | AddrSize := bw64;
|
---|
1022 | Prefix := True;
|
---|
1023 | end;
|
---|
1024 |
|
---|
1025 | procedure TCpu.InstAddrSize;
|
---|
1026 | begin
|
---|
1027 | AddrSizeBase := TBitWidth(Read8);
|
---|
1028 | AddrSize := AddrSizeBase;
|
---|
1029 | end;
|
---|
1030 |
|
---|
1031 | procedure TCpu.InitInstructions;
|
---|
1032 | begin
|
---|
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;
|
---|
1082 | end;
|
---|
1083 |
|
---|
1084 | procedure TCpu.SetAddrSizeBase(AValue: TBitWidth);
|
---|
1085 | begin
|
---|
1086 | if FAddrSizeBase = AValue then Exit;
|
---|
1087 | FAddrSizeBase := AValue;
|
---|
1088 | AddrSize := AValue;
|
---|
1089 | end;
|
---|
1090 |
|
---|
1091 | procedure TCpu.SetDataSizeBase(AValue: TBitWidth);
|
---|
1092 | begin
|
---|
1093 | if FDataSizeBase = AValue then Exit;
|
---|
1094 | FDataSizeBase := AValue;
|
---|
1095 | DataSize := AValue;
|
---|
1096 | end;
|
---|
1097 |
|
---|
1098 | procedure TCpu.Run;
|
---|
1099 | begin
|
---|
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;
|
---|
1108 | end;
|
---|
1109 |
|
---|
1110 | procedure TCpu.Step;
|
---|
1111 | var
|
---|
1112 | Opcode: Byte;
|
---|
1113 | begin
|
---|
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);
|
---|
1126 | end;
|
---|
1127 |
|
---|
1128 | procedure TCpu.Start;
|
---|
1129 | begin
|
---|
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;
|
---|
1137 | end;
|
---|
1138 |
|
---|
1139 | procedure TCpu.Stop;
|
---|
1140 | begin
|
---|
1141 | if Running then begin
|
---|
1142 | Terminated := True;
|
---|
1143 | Thread.Terminate;
|
---|
1144 | Thread.WaitFor;
|
---|
1145 | FreeAndNil(Thread);
|
---|
1146 | FRunning := False;
|
---|
1147 | end;
|
---|
1148 | end;
|
---|
1149 |
|
---|
1150 | function TCpu.Read8: Byte;
|
---|
1151 | begin
|
---|
1152 | Result := PByte(Memory + IP)^;
|
---|
1153 | Inc(IP);
|
---|
1154 | end;
|
---|
1155 |
|
---|
1156 | function TCpu.Read16: Word;
|
---|
1157 | begin
|
---|
1158 | Result := PWord(Memory + IP)^;
|
---|
1159 | Inc(IP, SizeOf(Word));
|
---|
1160 | end;
|
---|
1161 |
|
---|
1162 | function TCpu.Read32: DWord;
|
---|
1163 | begin
|
---|
1164 | Result := PDWord(Memory + IP)^;
|
---|
1165 | Inc(IP, SizeOf(DWord));
|
---|
1166 | end;
|
---|
1167 |
|
---|
1168 | function TCpu.Read64: QWord;
|
---|
1169 | begin
|
---|
1170 | Result := PQWord(Memory + IP)^;
|
---|
1171 | Inc(IP, SizeOf(QWord));
|
---|
1172 | end;
|
---|
1173 |
|
---|
1174 | function TCpu.ReadAddress: TAddress;
|
---|
1175 | begin
|
---|
1176 | case AddrSize of
|
---|
1177 | bw8: Result := Read8;
|
---|
1178 | bw16: Result := Read16;
|
---|
1179 | bw32: Result := Read32;
|
---|
1180 | bw64: Result := Read64;
|
---|
1181 | end;
|
---|
1182 | end;
|
---|
1183 |
|
---|
1184 | function TCpu.ReadAddressSigned: TAddressSigned;
|
---|
1185 | begin
|
---|
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;
|
---|
1192 | end;
|
---|
1193 |
|
---|
1194 | constructor TCpu.Create;
|
---|
1195 | begin
|
---|
1196 | DataSizeBase := bw16;
|
---|
1197 | AddrSizeBase := bw16;
|
---|
1198 | SetLength(Registers, 32);
|
---|
1199 | InitInstructions;
|
---|
1200 | end;
|
---|
1201 |
|
---|
1202 | destructor TCpu.Destroy;
|
---|
1203 | begin
|
---|
1204 | Stop;
|
---|
1205 | inherited Destroy;
|
---|
1206 | end;
|
---|
1207 |
|
---|
1208 | end.
|
---|
1209 |
|
---|