| 1 | unit InstructionSetGen;
|
|---|
| 2 |
|
|---|
| 3 | interface
|
|---|
| 4 |
|
|---|
| 5 | uses
|
|---|
| 6 | Classes, SysUtils, Common, Z80InstructionInfo, TypInfo;
|
|---|
| 7 |
|
|---|
| 8 | type
|
|---|
| 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 |
|
|---|
| 18 | implementation
|
|---|
| 19 |
|
|---|
| 20 | { TInstructionSetGen }
|
|---|
| 21 |
|
|---|
| 22 | procedure TInstructionSetGen.Generate(FileName: string);
|
|---|
| 23 | var
|
|---|
| 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;
|
|---|
| 53 | const
|
|---|
| 54 | CellStart = '<td >';
|
|---|
| 55 | CellEnd = '</td>';
|
|---|
| 56 | CodeStart = '<code>';
|
|---|
| 57 | CodeEnd = '</code>';
|
|---|
| 58 | DataStart = '<dd>';
|
|---|
| 59 | DataEnd = '</dd>';
|
|---|
| 60 | Generated = 'Generated';
|
|---|
| 61 | begin
|
|---|
| 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;
|
|---|
| 176 | end;
|
|---|
| 177 |
|
|---|
| 178 | function TInstructionSetGen.GetBlock(var Text: string; StartText, EndText: string
|
|---|
| 179 | ): string;
|
|---|
| 180 | var
|
|---|
| 181 | Index: Integer;
|
|---|
| 182 | begin
|
|---|
| 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;
|
|---|
| 193 | end;
|
|---|
| 194 |
|
|---|
| 195 |
|
|---|
| 196 | end.
|
|---|
| 197 |
|
|---|