source: trunk/Z80/InstructionSetGen.pas

Last change on this file was 10, checked in by chronos, 3 weeks ago
  • Added: Decoding area of instructions with two prefixes.
  • Modified: Improved parameter handling in disassembler.
  • Modified: Improving handling of flags.
File size: 6.1 KB
Line 
1unit InstructionSetGen;
2
3interface
4
5uses
6 Classes, SysUtils, Common, Z80InstructionInfo, TypInfo;
7
8type
9
10 { TInstructionSetGen }
11
12 TInstructionSetGen = class
13 procedure Generate(FileName: string);
14 private
15 function GetBlock(var Text: string; StartText, EndText: string): string;
16 end;
17
18implementation
19
20{ TInstructionSetGen }
21
22procedure TInstructionSetGen.Generate(FileName: string);
23var
24 Lines: TStringList;
25 Instruction: TStringList;
26 Head: TStringList;
27 Body: TStringList;
28 InitInstructions: TStringList;
29 Combined: TStringList;
30 Info: TStringList;
31 Cell: string;
32 Source: string;
33 Name: string;
34 Opcode: string;
35 Bytes: string;
36 Cycles: string;
37 CyclesFalseCond: string;
38 FlagC: string;
39 FlagN: string;
40 FlagPV: string;
41 FlagH: string;
42 FlagZ: string;
43 FlagS: string;
44 Description: string;
45 Ident: string;
46 Prefix: string;
47 NameOnly: string;
48 Params: string;
49 ParamsPart: string;
50 InfoParams: string;
51 ParamType: TParamType;
52 NewCycles: string;
53const
54 CellStart = '<td >';
55 CellEnd = '</td>';
56 CodeStart = '<code>';
57 CodeEnd = '</code>';
58 DataStart = '<dd>';
59 DataEnd = '</dd>';
60 Generated = 'Generated';
61begin
62 Lines := TStringList.Create;
63 Lines.LoadFromFile(FileName);
64 Source := Lines.Text;
65 Combined := TStringList.Create;
66 Instruction := TStringList.Create;
67 Instruction.Add('interface');
68 Instruction.Add('');
69 Instruction.Add('type');
70 Instruction.Add(' TInstruction = (');
71 Head := TStringList.Create;
72 Head.Add('TCpuZ80 = class');
73 Body := TStringList.Create;
74 Body.Add('implementation');
75 Body.Add('');
76 InitInstructions := TStringList.Create;
77 InitInstructions.Add('procedure TCpuZ80.InitInstructions;');
78 InitInstructions.Add('begin');
79 Info := TStringList.Create;
80 Info.Add('constructor TInstructionSet.Create;');
81 Info.Add('begin');
82 repeat
83 Cell := GetBlock(Source, CellStart, CellEnd);
84 if Cell <> '' then begin
85 Name := GetBlock(Cell, CodeStart, CodeEnd).Trim;
86 if Name = '' then Continue;
87 Name := StringReplace(Name, '<var>', '', [rfReplaceAll]);
88 Name := StringReplace(Name, '</var>', '', [rfReplaceAll]);
89 Params := Name;
90 NameOnly := GetStringPart(Params, ' ');
91
92 Ident := StringReplace(Name.ToUpper, ' ', '_', [rfReplaceAll]);
93 Ident := StringReplace(Ident, ',', '_', [rfReplaceAll]);
94 Ident := StringReplace(Ident, '''', '_Pair', [rfReplaceAll]);
95 Ident := StringReplace(Ident, '+', '_Plus_', [rfReplaceAll]);
96 Ident := StringReplace(Ident, '(', '', [rfReplaceAll]);
97 Ident := StringReplace(Ident, ')', '_Indirect', [rfReplaceAll]);
98 Opcode := GetBlock(Cell, DataStart, DataEnd).Trim;
99 if Pos('<var>', Opcode) >= 1 then
100 Opcode := Copy(Opcode, 1, Pos('<var>', Opcode) - 1).Trim;
101 if Pos(' ', Opcode) >= 1 then begin
102 Prefix := Copy(Opcode, 1, 2);
103 Opcode := Copy(Opcode, 3, MaxInt).Trim;
104 if Prefix = 'CB' then Opcode := '1' + Opcode
105 else if Prefix = 'DD' then Opcode := '2' + Opcode
106 else if Prefix = 'ED' then Opcode := '3' + Opcode
107 else if Prefix = 'FD' then Opcode := '4' + Opcode;
108 end;
109 Bytes := GetBlock(Cell, DataStart, DataEnd).Trim;
110 Cycles := GetBlock(Cell, DataStart, DataEnd).Trim;
111 if Pos('/', Cycles) >= 1 then begin
112 NewCycles := GetStringPart(Cycles, '/');
113 CyclesFalseCond := Cycles;
114 Cycles := NewCycles;
115 end else CyclesFalseCond := '0';
116
117 FlagC := GetBlock(Cell, DataStart, DataEnd).Trim;
118 FlagN := GetBlock(Cell, DataStart, DataEnd).Trim;
119 FlagPV := GetBlock(Cell, DataStart, DataEnd).Trim;
120 FlagH := GetBlock(Cell, DataStart, DataEnd).Trim;
121 FlagZ := GetBlock(Cell, DataStart, DataEnd).Trim;
122 FlagS := GetBlock(Cell, DataStart, DataEnd).Trim;
123 Description := GetBlock(Cell, DataStart, DataEnd).Trim;
124 Description := StringReplace(Description, '<var>', '', [rfReplaceAll]);
125 Description := StringReplace(Description, '</var>', '', [rfReplaceAll]);
126
127 InfoParams := '';
128 Params := Params.ToUpper;
129 while Params <> '' do begin
130 ParamsPart := GetStringPart(Params, ',');
131 ParamType := StrToParamType(ParamsPart, NameOnly);
132 if ParamType <> ptNone then
133 InfoParams := InfoParams + ', ' + GetEnumName(TypeInfo(TParamType), Integer(ParamType));
134 end;
135 if Copy(InfoParams, 1, 2) = ', ' then Delete(InfoParams, 1, 2);
136
137 Info.Add(' AddNew(in_' + Ident + ', ''' + NameOnly.ToUpper + ''', [' + InfoParams + '], ''' +
138 StringReplace(Description, '''', '''''', [rfReplaceAll]) + ''', ' +
139 Cycles + ', ' + CyclesFalseCond + ');');
140 Instruction.Add(' in_' + Ident + ' = $' + Opcode + ',');
141 InitInstructions.Add(' Instructions[in_' + Ident + '] := ' + Ident + ';');
142 Head.Add(' procedure ' + Ident + ';');
143 Body.Add('procedure TCpuZ80.' + Ident + ';');
144 Body.Add('begin');
145 Body.Add(' NotImplemented;');
146 Body.Add('end;');
147 Body.Add('');
148 end else Break;
149 until False;
150 Instruction.Add(' );');
151 Head.Add('end;');
152 InitInstructions.Add('end;');
153 Info.Add('end;');
154
155 ForceDirectories(Generated);
156 Instruction.SaveToFile(Generated + DirectorySeparator + 'Instruction.pas');
157 Head.SaveToFile(Generated + DirectorySeparator + 'Head.pas');
158 Body.SaveToFile(Generated + DirectorySeparator + 'Body.pas');
159 InitInstructions.SaveToFile(Generated + DirectorySeparator + 'InitInstructions.pas');
160 Info.SaveToFile(Generated + DirectorySeparator + 'Info.pas');
161
162 Combined.Add(Instruction.Text);
163 Combined.Add(Head.Text);
164 Combined.Add(Body.Text);
165 Combined.Add(InitInstructions.Text);
166
167 Combined.SaveToFile(Generated + DirectorySeparator + 'Combined.pas');
168
169 Combined.Free;
170 Instruction.Free;
171 Head.Free;
172 Body.Free;
173 InitInstructions.Free;
174 Info.Free;
175 Lines.Free;
176end;
177
178function TInstructionSetGen.GetBlock(var Text: string; StartText, EndText: string
179 ): string;
180var
181 Index: Integer;
182begin
183 Result := '';
184 Index := Pos(StartText, Text);
185 if Index > 0 then begin
186 Text := Copy(Text, Index + Length(StartText), MaxInt);
187 Index := Pos(EndText, Text);
188 if Index > 0 then begin
189 Result := Copy(Text, 1, Index - 1);
190 Text := Copy(Text, Index + Length(EndText), MaxInt);
191 end;
192 end;
193end;
194
195
196end.
197
Note: See TracBrowser for help on using the repository browser.