source: branches/virtualcpu4/UCompilerPascal.pas

Last change on this file was 188, checked in by chronos, 5 years ago
  • Modified: Simplified generated computed goto.
File size: 15.7 KB
Line 
1unit UCompilerPascal;
2
3{$mode delphi}
4
5interface
6
7uses
8 Classes, SysUtils, UInstructionReader, UOpcode, UCpu, strutils;
9
10type
11
12 { TCompilerPascal }
13
14 TCompilerPascal = class
15 private
16 OpcodeDefs: TOpcodeDefs;
17 Instructions: array[TOpcode] of TInstructionEvent;
18 Indent: Integer;
19 Labels: TStringList;
20 procedure InstConvert;
21 procedure InstNop;
22 procedure InstHalt;
23 procedure InstLoad;
24 procedure InstLoadImmediate;
25 procedure InstJump;
26 procedure InstJumpZero;
27 procedure InstJumpNotZero;
28 procedure InstJumpRel;
29 procedure InstJumpRelZero;
30 procedure InstJumpRelNotZero;
31 procedure InstTest;
32 procedure InstNeg;
33 procedure InstClear;
34 procedure InstLoadMem;
35 procedure InstStoreMem;
36 procedure InstExchg;
37 procedure InstPush;
38 procedure InstPop;
39 procedure InstCall;
40 procedure InstRet;
41 procedure InstAdd;
42 procedure InstAddi;
43 procedure InstSub;
44 procedure InstSubi;
45 procedure InstMul;
46 procedure InstDiv;
47 procedure InstMod;
48 procedure InstInc;
49 procedure InstDec;
50 procedure InstIn;
51 procedure InstOut;
52 procedure InstShr;
53 procedure InstShl;
54 procedure InstAnd;
55 procedure InstOr;
56 procedure InstXor;
57 procedure InstLddr;
58 procedure InstLdir;
59 procedure InstDataPrefix8;
60 procedure InstDataPrefix16;
61 procedure InstDataPrefix32;
62 procedure InstDataPrefix64;
63 procedure InstDataSize;
64 procedure InstAddrPrefix8;
65 procedure InstAddrPrefix16;
66 procedure InstAddrPrefix32;
67 procedure InstAddrPrefix64;
68 procedure InstAddrSize;
69 procedure InitInstructions;
70 procedure AddLine(Text: string);
71 function GetRegister(Index: Byte; BitWidth: TBitWidth): string;
72 function GetMemory(Offset: string; BitWidth: TBitWidth): string;
73 function GetJump(LabelName: string): string;
74 public
75 Reader: TInstructionReader;
76 Output: string;
77 procedure Compile;
78 constructor Create;
79 destructor Destroy; override;
80 end;
81
82
83implementation
84
85const
86 BitWidthSuffix: array[TBitWidth] of string = ('', '.B', '.W', '.D', '.Q');
87 BitWidthPtrType: array[TBitWidth] of string = ('', 'PByte', 'PWord', 'PDWord', 'PQWord');
88
89{ TCompilerPascal }
90
91procedure TCompilerPascal.InstConvert;
92var
93 R: Byte;
94begin
95 R := Reader.Read8;
96 AddLine(GetRegister(R, Reader.AddrSize) + ' := ' + GetRegister(R, Reader.DataSize) + ';');
97end;
98
99procedure TCompilerPascal.InstNop;
100begin
101end;
102
103procedure TCompilerPascal.InstHalt;
104begin
105 AddLine('Exit;');
106end;
107
108procedure TCompilerPascal.InstLoad;
109var
110 R1, R2: Byte;
111begin
112 R1 := Reader.Read8;
113 R2 := Reader.Read8;
114 AddLine(GetRegister(R1, Reader.DataSize) + ' := ' + GetRegister(R2, Reader.DataSize) + ';');
115end;
116
117procedure TCompilerPascal.InstLoadImmediate;
118var
119 R: Byte;
120begin
121 R := Reader.Read8;
122 AddLine(GetRegister(R, Reader.DataSize) + ' := ' + IntToHexEx(Reader.ReadData, -1, '$') + ';');
123end;
124
125procedure TCompilerPascal.InstJump;
126begin
127 AddLine(GetJump('L' + IntToStr(Reader.ReadAddress)));
128end;
129
130procedure TCompilerPascal.InstJumpZero;
131begin
132 AddLine('if Zero then ' + GetJump('L' + IntToStr(Reader.ReadAddress)));
133end;
134
135procedure TCompilerPascal.InstJumpNotZero;
136begin
137 AddLine('if not Zero then ' + GetJump('L' + IntToStr(Reader.ReadAddress)));
138end;
139
140procedure TCompilerPascal.InstJumpRel;
141var
142 Addr: TAddressSigned;
143begin
144 Addr := Reader.ReadAddressSigned;
145 AddLine(GetJump('L' + IntToStr(Reader.IP + Addr)));
146end;
147
148procedure TCompilerPascal.InstJumpRelZero;
149var
150 Addr: TAddressSigned;
151begin
152 Addr := Reader.ReadAddressSigned;
153 AddLine('if Zero then ' + GetJump('L' + IntToStr(Reader.IP + Addr)));
154end;
155
156procedure TCompilerPascal.InstJumpRelNotZero;
157var
158 Addr: TAddressSigned;
159begin
160 Addr := Reader.ReadAddressSigned;
161 AddLine('if not Zero then ' + GetJump('L' + IntToStr(Reader.IP + Addr)));
162end;
163
164procedure TCompilerPascal.InstTest;
165var
166 R: TRegIndex;
167begin
168 R := Reader.Read8;
169 AddLine('Zero := ' + GetRegister(R, Reader.DataSize) + ' = 0;');
170end;
171
172procedure TCompilerPascal.InstNeg;
173var
174 R: TRegIndex;
175begin
176 R := Reader.Read8;
177 AddLine(GetRegister(R, Reader.DataSize) + ' := -' + GetRegister(R, Reader.DataSize) + ';');
178end;
179
180procedure TCompilerPascal.InstClear;
181var
182 R: TRegIndex;
183begin
184 R := Reader.Read8;
185 AddLine(GetRegister(R, Reader.DataSize) + ' := 0;');
186end;
187
188procedure TCompilerPascal.InstLoadMem;
189var
190 R1, R2: Byte;
191begin
192 R1 := Reader.Read8;
193 R2 := Reader.Read8;
194 AddLine(GetRegister(R1, Reader.DataSize) + ' := ' +
195 GetMemory(GetRegister(R2, Reader.AddrSize), Reader.AddrSize) + ';');
196end;
197
198procedure TCompilerPascal.InstStoreMem;
199var
200 R1, R2: Byte;
201begin
202 R1 := Reader.Read8;
203 R2 := Reader.Read8;
204 AddLine(GetMemory(GetRegister(R1, Reader.AddrSize), Reader.AddrSize) + ' := ' +
205 GetRegister(R2, Reader.DataSize) + ';');
206end;
207
208procedure TCompilerPascal.InstExchg;
209var
210 R1, R2: Byte;
211begin
212 R1 := Reader.Read8;
213 R2 := Reader.Read8;
214 AddLine('Temp := ' + GetRegister(R1, Reader.DataSize) + ';');
215 AddLine(GetRegister(R1, Reader.DataSize) + ' := ' + GetRegister(R2, Reader.DataSize) + ';');
216 AddLine(GetRegister(R2, Reader.DataSize) + ' := Temp;');
217end;
218
219procedure TCompilerPascal.InstPush;
220var
221 R: Byte;
222begin
223 R := Reader.Read8;
224 AddLine('Dec(SP, ' + IntToStr(BitWidthBytes[Reader.DataSize]) + ');');
225 AddLine(GetMemory('SP', Reader.AddrSize) + ' := ' + GetRegister(R, Reader.DataSize) + ';');
226end;
227
228procedure TCompilerPascal.InstPop;
229var
230 R: Byte;
231begin
232 R := Reader.Read8;
233 AddLine(GetRegister(R, Reader.DataSize) + ' := ' + GetMemory('SP', Reader.AddrSize) + ';');
234 AddLine('Inc(SP, ' + IntToStr(BitWidthBytes[Reader.DataSize]) + ');');
235end;
236
237procedure TCompilerPascal.InstCall;
238var
239 Addr: QWord;
240begin
241 Addr := Reader.ReadAddress;
242 AddLine('Dec(SP, ' + IntToStr(BitWidthBytes[Reader.AddrSize]) + ');');
243 AddLine(GetMemory('SP', Reader.AddrSize) + ' := LongWord(@L' + IntToStr(Reader.IP) + ');');
244 AddLine(GetJump('L' + IntToStr(Addr)));
245end;
246
247procedure TCompilerPascal.InstRet;
248begin
249 AddLine('TempAddr := Pointer(' + GetMemory('SP', Reader.AddrSize) + ');');
250 AddLine('Inc(SP, ' + IntToStr(BitWidthBytes[Reader.AddrSize]) + ');');
251 AddLine(GetJump('TempAddr'));
252end;
253
254procedure TCompilerPascal.InstAdd;
255var
256 R1, R2: Byte;
257begin
258 R1 := Reader.Read8;
259 R2 := Reader.Read8;
260 AddLine(GetRegister(R1, Reader.DataSize) + ' := ' + GetRegister(R1, Reader.DataSize) +
261 ' + ' + GetRegister(R2, Reader.DataSize));
262end;
263
264procedure TCompilerPascal.InstAddi;
265var
266 R: Byte;
267begin
268 R := Reader.Read8;
269 AddLine(GetRegister(R, Reader.DataSize) + ' := ' + GetRegister(R, Reader.DataSize) +
270 ' + ' + IntToStr(Reader.ReadData));
271end;
272
273procedure TCompilerPascal.InstSub;
274var
275 R1, R2: Byte;
276begin
277 R1 := Reader.Read8;
278 R2 := Reader.Read8;
279 AddLine(GetRegister(R1, Reader.DataSize) + ' := ' + GetRegister(R1, Reader.DataSize) +
280 ' - ' + GetRegister(R2, Reader.DataSize));
281end;
282
283procedure TCompilerPascal.InstSubi;
284var
285 R: Byte;
286begin
287 R := Reader.Read8;
288 AddLine(GetRegister(R, Reader.DataSize) + ' := ' + GetRegister(R, Reader.DataSize) +
289 ' - ' + IntToStr(Reader.ReadData));
290end;
291
292procedure TCompilerPascal.InstMul;
293var
294 R1, R2: Byte;
295begin
296 R1 := Reader.Read8;
297 R2 := Reader.Read8;
298 AddLine(GetRegister(R1, Reader.DataSize) + ' := ' + GetRegister(R1, Reader.DataSize) +
299 ' * ' + GetRegister(R2, Reader.DataSize));
300end;
301
302procedure TCompilerPascal.InstDiv;
303var
304 R1, R2: Byte;
305begin
306 R1 := Reader.Read8;
307 R2 := Reader.Read8;
308 AddLine(GetRegister(R1, Reader.DataSize) + ' := ' + GetRegister(R1, Reader.DataSize) +
309 ' div ' + GetRegister(R2, Reader.DataSize));
310end;
311
312procedure TCompilerPascal.InstMod;
313var
314 R1, R2: Byte;
315begin
316 R1 := Reader.Read8;
317 R2 := Reader.Read8;
318 AddLine(GetRegister(R1, Reader.DataSize) + ' := ' + GetRegister(R1, Reader.DataSize) +
319 ' mod ' + GetRegister(R2, Reader.DataSize));
320end;
321
322procedure TCompilerPascal.InstInc;
323var
324 R: Byte;
325begin
326 R := Reader.Read8;
327 AddLine('Inc(' + GetRegister(R, Reader.DataSize) + ');');
328end;
329
330procedure TCompilerPascal.InstDec;
331var
332 R: Byte;
333begin
334 R := Reader.Read8;
335 AddLine('Dec(' + GetRegister(R, Reader.DataSize) + ');');
336end;
337
338procedure TCompilerPascal.InstIn;
339var
340 R: TRegIndex;
341 Port: TAddress;
342begin
343 R := Reader.Read8;
344 Port := Reader.ReadAddress;
345 // TODO
346end;
347
348procedure TCompilerPascal.InstOut;
349var
350 R: TRegIndex;
351 Port: TAddress;
352begin
353 Port := Reader.ReadAddress;
354 R := Reader.Read8;
355 // TODO
356end;
357
358procedure TCompilerPascal.InstShr;
359var
360 R: Byte;
361begin
362 R := Reader.Read8;
363 AddLine(GetRegister(R, Reader.DataSize) + ' := ' + GetRegister(R, Reader.DataSize) +
364 ' shr ' + IntToStr(Reader.ReadData));
365end;
366
367procedure TCompilerPascal.InstShl;
368var
369 R: Byte;
370begin
371 R := Reader.Read8;
372 AddLine(GetRegister(R, Reader.DataSize) + ' := ' + GetRegister(R, Reader.DataSize) +
373 ' shl ' + IntToStr(Reader.ReadData));
374end;
375
376procedure TCompilerPascal.InstAnd;
377var
378 R1, R2: Byte;
379begin
380 R1 := Reader.Read8;
381 R2 := Reader.Read8;
382 AddLine(GetRegister(R1, Reader.DataSize) + ' := ' + GetRegister(R1, Reader.DataSize) +
383 ' and ' + GetRegister(R2, Reader.DataSize));
384end;
385
386procedure TCompilerPascal.InstOr;
387var
388 R1, R2: Byte;
389begin
390 R1 := Reader.Read8;
391 R2 := Reader.Read8;
392 AddLine(GetRegister(R1, Reader.DataSize) + ' := ' + GetRegister(R1, Reader.DataSize) +
393 ' or ' + GetRegister(R2, Reader.DataSize));
394end;
395
396procedure TCompilerPascal.InstXor;
397var
398 R1, R2: Byte;
399begin
400 R1 := Reader.Read8;
401 R2 := Reader.Read8;
402 AddLine(GetRegister(R1, Reader.DataSize) + ' := ' + GetRegister(R1, Reader.DataSize) +
403 ' xor ' + GetRegister(R2, Reader.DataSize));
404end;
405
406procedure TCompilerPascal.InstLddr;
407begin
408 // TODO
409end;
410
411procedure TCompilerPascal.InstLdir;
412begin
413 // TODO
414end;
415
416procedure TCompilerPascal.InstDataPrefix8;
417begin
418 Reader.Prefix := True;
419 Reader.DataSize := bw8;
420end;
421
422procedure TCompilerPascal.InstDataPrefix16;
423begin
424 Reader.Prefix := True;
425 Reader.DataSize := bw16;
426end;
427
428procedure TCompilerPascal.InstDataPrefix32;
429begin
430 Reader.Prefix := True;
431 Reader.DataSize := bw32;
432end;
433
434procedure TCompilerPascal.InstDataPrefix64;
435begin
436 Reader.Prefix := True;
437 Reader.DataSize := bw64;
438end;
439
440procedure TCompilerPascal.InstDataSize;
441var
442 BitWidth: Byte;
443begin
444 BitWidth := Reader.Read8;
445 if (BitWidth <> 0) and (BitWidth <= Byte(High(TBitWidth))) then begin
446 Reader.DataSizeBase := TBitWidth(BitWidth);
447 Reader.DataSize := Reader.DataSizeBase;
448 end;
449end;
450
451procedure TCompilerPascal.InstAddrPrefix8;
452begin
453 Reader.Prefix := True;
454 Reader.AddrSize := bw8;
455end;
456
457procedure TCompilerPascal.InstAddrPrefix16;
458begin
459 Reader.Prefix := True;
460 Reader.AddrSize := bw16;
461end;
462
463procedure TCompilerPascal.InstAddrPrefix32;
464begin
465 Reader.Prefix := True;
466 Reader.AddrSize := bw32;
467end;
468
469procedure TCompilerPascal.InstAddrPrefix64;
470begin
471 Reader.Prefix := True;
472 Reader.AddrSize := bw64;
473end;
474
475procedure TCompilerPascal.InstAddrSize;
476var
477 BitWidth: Byte;
478begin
479 BitWidth := Reader.Read8;
480 if (BitWidth <> 0) and (BitWidth <= Byte(High(TBitWidth))) then begin
481 Reader.AddrSizeBase := TBitWidth(BitWidth);
482 Reader.AddrSize := Reader.AddrSizeBase;
483 end; // TODO error reporting
484end;
485
486procedure TCompilerPascal.InitInstructions;
487begin
488 Instructions[opNop] := InstNop;
489 Instructions[opHalt] := InstHalt;
490 Instructions[opLoad] := InstLoad;
491 Instructions[opLoadi] := InstLoadImmediate;
492 Instructions[opJump] := InstJump;
493 Instructions[opJumpNotZero] := InstJumpNotZero;
494 Instructions[opJumpZero] := InstJumpZero;
495 Instructions[opJumpRel] := InstJumpRel;
496 Instructions[opJumpRelNotZero] := InstJumpRelNotZero;
497 Instructions[opJumpRelZero] := InstJumpRelZero;
498 Instructions[opLoadMem] := InstLoadMem;
499 Instructions[opStoreMem] := InstStoreMem;
500 Instructions[opClear] := InstClear;
501 Instructions[opNeg] := InstNeg;
502 Instructions[opExchg] := InstExchg;
503 Instructions[opPop] := InstPop;
504 Instructions[opPush] := InstPush;
505 Instructions[opCall] := InstCall;
506 Instructions[opRet] := InstRet;
507 Instructions[opAdd] := InstAdd;
508 Instructions[opAddi] := InstAddi;
509 Instructions[opSub] := InstSub;
510 Instructions[opSubi] := InstSubi;
511 Instructions[opInc] := InstInc;
512 Instructions[opDec] := InstDec;
513 Instructions[opIn] := InstIn;
514 Instructions[opOut] := InstOut;
515 Instructions[opShr] := InstShr;
516 Instructions[opShl] := InstShl;
517 Instructions[opDataSize] := InstDataSize;
518 Instructions[opDataPrefix8] := InstDataPrefix8;
519 Instructions[opDataPrefix16] := InstDataPrefix16;
520 Instructions[opDataPrefix32] := InstDataPrefix32;
521 Instructions[opDataPrefix64] := InstDataPrefix64;
522 Instructions[opAddrSize] := InstAddrSize;
523 Instructions[opAddrPrefix8] := InstAddrPrefix8;
524 Instructions[opAddrPrefix16] := InstAddrPrefix16;
525 Instructions[opAddrPrefix32] := InstAddrPrefix32;
526 Instructions[opAddrPrefix64] := InstAddrPrefix64;
527 Instructions[opTest] := InstTest;
528 Instructions[opAnd] := InstAnd;
529 Instructions[opOr] := InstOr;
530 Instructions[opXor] := InstXor;
531 Instructions[opLdir] := InstLdir;
532 Instructions[opLddr] := InstLddr;
533 Instructions[opMul] := InstMul;
534 Instructions[opDiv] := InstDiv;
535 Instructions[opMod] := InstMod;
536 Instructions[opConvert] := InstConvert;
537end;
538
539procedure TCompilerPascal.AddLine(Text: string);
540begin
541 Output := Output + DupeString(' ', Indent) + Text + LineEnding;
542end;
543
544function TCompilerPascal.GetRegister(Index: Byte; BitWidth: TBitWidth): string;
545begin
546 Result := 'R' + IntToStr(Index) + BitWidthSuffix[BitWidth];
547end;
548
549function TCompilerPascal.GetMemory(Offset: string; BitWidth: TBitWidth): string;
550begin
551 Result := BitWidthPtrType[BitWidth] + '(Memory + ' + Offset + ')^';
552end;
553
554function TCompilerPascal.GetJump(LabelName: string): string;
555begin
556 Result := 'asm jmp ' + LabelName + ' end;';
557end;
558
559procedure TCompilerPascal.Compile;
560var
561 Opcode: Byte;
562 MemorySize: QWord;
563 OutputBody: string;
564 LabelsText: string;
565 LabelAddr: QWord;
566 I: Integer;
567begin
568 Reader.Init;
569 MemorySize := MemSize(Reader.Cpu.Memory);
570 AddLine('begin');
571 AddLine(' SP := ' + IntToStr(MemorySize) + ';');
572 AddLine(' Memory := GetMem(' + IntToStr(MemorySize) + ');');
573 Inc(Indent);
574 while Reader.IP < MemorySize do begin
575 Reader.Prefix := False;
576 LabelAddr := Reader.IP;
577 Opcode := Reader.Read8;
578 if Opcode <= Integer(High(TOpcode)) then begin
579 AddLine('L' + IntToStr(LabelAddr) + ':');
580 Labels.Add('L' + IntToStr(LabelAddr));
581 if Opcode < Length(Instructions) then begin
582 if Assigned(Instructions[TOpcode(Opcode)]) then Instructions[TOpcode(Opcode)]
583 else raise Exception.Create('Missing instruction handler for opcode '+ IntToStr(Opcode));
584 end else raise Exception.Create('Unsupported opcode ' + IntToStr(Opcode) + ' at address ' + IntToHex(Reader.IP - 1, 8) + '.');
585 if not Reader.Prefix then begin
586 Reader.DataSize := Reader.DataSizeBase;
587 Reader.AddrSize := Reader.AddrSizeBase;
588 end;
589 end else begin
590 end;
591 end;
592 Dec(Indent);
593 AddLine('end.');
594 OutputBody := Output;
595
596 Output := '';
597 AddLine('type');
598 AddLine(' TBitWidth = (bwNone, bw8, bw16, bw32, bw64);');
599 AddLine(' TRegister = record');
600 AddLine(' case TBitWidth of');
601 AddLine(' bw8: (B: Byte);');
602 AddLine(' bw16: (W: Word);');
603 AddLine(' bw32: (D: DWord);');
604 AddLine(' bw64: (Q: QWord);');
605 AddLine(' end;');
606 AddLine('var');
607 AddLine(' Memory: Pointer;');
608 for I := 0 to High(Reader.Cpu.Registers) do
609 AddLine(' R' + IntToStr(I) + ': TRegister;');
610 AddLine(' SP: QWord;');
611 AddLine(' Zero: Boolean;');
612 AddLine(' Temp: QWord;');
613 AddLine(' TempAddr: Pointer;');
614 AddLine('');
615 LabelsText := '';
616 for I := 0 to Labels.Count - 1 do begin
617 if I > 0 then LabelsText := LabelsText + ', ';
618 LabelsText := LabelsText + Labels[I];
619 end;
620 AddLine('label ' + LabelsText + ';');
621 Output := Output + OutputBody;
622end;
623
624constructor TCompilerPascal.Create;
625begin
626 OpcodeDefs := TOpcodeDefs.Create;
627 Reader := TInstructionReader.Create;
628 Labels := TStringList.Create;
629 InitInstructions;
630end;
631
632destructor TCompilerPascal.Destroy;
633begin
634 FreeAndNil(Reader);
635 FreeAndNil(OpcodeDefs);
636 FreeAndNil(Labels);
637 inherited Destroy;
638end;
639
640end.
641
Note: See TracBrowser for help on using the repository browser.