| 1 | unit Disassembler;
|
|---|
| 2 |
|
|---|
| 3 | interface
|
|---|
| 4 |
|
|---|
| 5 | uses
|
|---|
| 6 | Classes, SysUtils, CpuZ80, Instructions, StrUtils, Memory, Generics.Collections;
|
|---|
| 7 |
|
|---|
| 8 | type
|
|---|
| 9 |
|
|---|
| 10 | { TDecodedInstruction }
|
|---|
| 11 |
|
|---|
| 12 | TDecodedInstruction = class
|
|---|
| 13 | Address: Word;
|
|---|
| 14 | Opcodes: array of Byte;
|
|---|
| 15 | Name: string;
|
|---|
| 16 | Parameters: string;
|
|---|
| 17 | constructor Create;
|
|---|
| 18 | procedure AddOpcode(Data: Byte);
|
|---|
| 19 | function GetOpcodesText: string;
|
|---|
| 20 | end;
|
|---|
| 21 |
|
|---|
| 22 | { TDecodedInstructions }
|
|---|
| 23 |
|
|---|
| 24 | TDecodedInstructions = class(TObjectList<TDecodedInstruction>)
|
|---|
| 25 | function SearchAddress(Address: Word): TDecodedInstruction;
|
|---|
| 26 | end;
|
|---|
| 27 |
|
|---|
| 28 | { TDisassembler }
|
|---|
| 29 |
|
|---|
| 30 | TDisassembler = class
|
|---|
| 31 | InstructionSet: TInstructionSet;
|
|---|
| 32 | Memory: TMemory;
|
|---|
| 33 | DecodedInstructions: TDecodedInstructions;
|
|---|
| 34 | procedure Disassemble;
|
|---|
| 35 | procedure SaveToFile(FileName: string);
|
|---|
| 36 | procedure ToLines(Lines: TStrings);
|
|---|
| 37 | constructor Create;
|
|---|
| 38 | destructor Destroy; override;
|
|---|
| 39 | end;
|
|---|
| 40 |
|
|---|
| 41 |
|
|---|
| 42 | implementation
|
|---|
| 43 |
|
|---|
| 44 | { TDecodedInstructions }
|
|---|
| 45 |
|
|---|
| 46 | function TDecodedInstructions.SearchAddress(Address: Word): TDecodedInstruction;
|
|---|
| 47 | var
|
|---|
| 48 | I: Integer;
|
|---|
| 49 | begin
|
|---|
| 50 | I := 0;
|
|---|
| 51 | while (I < Count) and (Items[I].Address <> Address) do Inc(I);
|
|---|
| 52 | if I < Count then Result := Items[I]
|
|---|
| 53 | else Result := nil;
|
|---|
| 54 | end;
|
|---|
| 55 |
|
|---|
| 56 | { TDecodedInstruction }
|
|---|
| 57 |
|
|---|
| 58 | constructor TDecodedInstruction.Create;
|
|---|
| 59 | begin
|
|---|
| 60 | Parameters := '';
|
|---|
| 61 | end;
|
|---|
| 62 |
|
|---|
| 63 | procedure TDecodedInstruction.AddOpcode(Data: Byte);
|
|---|
| 64 | begin
|
|---|
| 65 | SetLength(Opcodes, Length(Opcodes) + 1);
|
|---|
| 66 | Opcodes[Length(Opcodes) - 1] := Data;
|
|---|
| 67 | end;
|
|---|
| 68 |
|
|---|
| 69 | function TDecodedInstruction.GetOpcodesText: string;
|
|---|
| 70 | var
|
|---|
| 71 | I: Integer;
|
|---|
| 72 | begin
|
|---|
| 73 | Result := '';
|
|---|
| 74 | for I := 0 to Length(Opcodes) - 1 do
|
|---|
| 75 | Result := Result + IntToHex(Opcodes[I], 2) + ' ';
|
|---|
| 76 | Result := Trim(Result);
|
|---|
| 77 | end;
|
|---|
| 78 |
|
|---|
| 79 | procedure TDisassembler.Disassemble;
|
|---|
| 80 | var
|
|---|
| 81 | J: Integer;
|
|---|
| 82 | Value: Integer;
|
|---|
| 83 | Instruction: TInstruction;
|
|---|
| 84 | InstructionInfo: TInstructionInfo;
|
|---|
| 85 | DecodedInstruction: TDecodedInstruction;
|
|---|
| 86 | begin
|
|---|
| 87 | Memory.Position := 0;
|
|---|
| 88 | while Memory.Position < Memory.Size do begin
|
|---|
| 89 | DecodedInstruction := TDecodedInstruction.Create;
|
|---|
| 90 | DecodedInstruction.Address := Memory.Position;
|
|---|
| 91 | Value := Memory.ReadByte;
|
|---|
| 92 | DecodedInstruction.AddOpcode(Value);
|
|---|
| 93 | if Value = $cb then begin
|
|---|
| 94 | Value := Memory.ReadByte;
|
|---|
| 95 | DecodedInstruction.AddOpcode(Value);
|
|---|
| 96 | Value := $cb00 or Value;
|
|---|
| 97 | end else
|
|---|
| 98 | if Value = $dd then begin
|
|---|
| 99 | Value := Memory.ReadByte;
|
|---|
| 100 | DecodedInstruction.AddOpcode(Value);
|
|---|
| 101 | Value := $dd00 or Value;
|
|---|
| 102 | end else
|
|---|
| 103 | if Value = $ed then begin
|
|---|
| 104 | Value := Memory.ReadByte;
|
|---|
| 105 | DecodedInstruction.AddOpcode(Value);
|
|---|
| 106 | Value := $ed00 or Value;
|
|---|
| 107 | end else
|
|---|
| 108 | if Value = $fd then begin
|
|---|
| 109 | Value := Memory.ReadByte;
|
|---|
| 110 | DecodedInstruction.AddOpcode(Value);
|
|---|
| 111 | Value := $fd00 or Value;
|
|---|
| 112 | end;
|
|---|
| 113 | if (Value >= 0) and (Value <= Integer(High(TInstruction))) then begin
|
|---|
| 114 | Instruction := TInstruction(Value);
|
|---|
| 115 | InstructionInfo := InstructionSet.SearchInstruction(Instruction);
|
|---|
| 116 | if Assigned(InstructionInfo) then begin
|
|---|
| 117 | DecodedInstruction.Name := InstructionInfo.Name;
|
|---|
| 118 | for J := 0 to Length(InstructionInfo.Params) - 1 do begin
|
|---|
| 119 | if J > 0 then
|
|---|
| 120 | DecodedInstruction.Parameters := DecodedInstruction.Parameters + ', ';
|
|---|
| 121 | if InstructionInfo.Params[J] = ptNumberByte then begin
|
|---|
| 122 | Value := Memory.ReadByte;
|
|---|
| 123 | DecodedInstruction.AddOpcode(Value);
|
|---|
| 124 | DecodedInstruction.Parameters := DecodedInstruction.Parameters + IntToHex(Value, 2);
|
|---|
| 125 | end else
|
|---|
| 126 | if InstructionInfo.Params[J] = ptNumberWord then begin
|
|---|
| 127 | Value := Memory.ReadWord;
|
|---|
| 128 | DecodedInstruction.AddOpcode(Value shr 8);
|
|---|
| 129 | DecodedInstruction.AddOpcode(Value and $ff);
|
|---|
| 130 | DecodedInstruction.Parameters := DecodedInstruction.Parameters + IntToHex(Value, 4);
|
|---|
| 131 | end else
|
|---|
| 132 | if InstructionInfo.Params[J] = ptNumberByteIndir then begin
|
|---|
| 133 | Value := Memory.ReadByte;
|
|---|
| 134 | DecodedInstruction.AddOpcode(Value);
|
|---|
| 135 | DecodedInstruction.Parameters := DecodedInstruction.Parameters + '(' + IntToHex(Value, 2) + ')';
|
|---|
| 136 | end else
|
|---|
| 137 | if InstructionInfo.Params[J] = ptNumberWordIndir then begin
|
|---|
| 138 | Value := Memory.ReadWord;
|
|---|
| 139 | DecodedInstruction.AddOpcode(Value shr 8);
|
|---|
| 140 | DecodedInstruction.AddOpcode(Value and $ff);
|
|---|
| 141 | DecodedInstruction.Parameters := DecodedInstruction.Parameters + '(' + IntToHex(Value, 4) + ')';
|
|---|
| 142 | end else
|
|---|
| 143 | if InstructionInfo.Params[J] in [ptRegA, ptRegB, ptRegC, ptRegD,
|
|---|
| 144 | ptRegE, ptRegH, ptRegL, ptRegBC, ptRegDE, ptRegHL, ptRegSP,
|
|---|
| 145 | ptFlagZ, ptFlagNZ, ptFlagC, ptFlagNC,
|
|---|
| 146 | ptRegBCIndir, ptRegDEIndir, ptRegHLIndir,
|
|---|
| 147 | pt00, pt08, pt10, pt18, pt20, pt28, pt30, pt38, pt0, pt1, pt2] then begin
|
|---|
| 148 | DecodedInstruction.Parameters := DecodedInstruction.Parameters + ParamTypeText[InstructionInfo.Params[J]];
|
|---|
| 149 | end else
|
|---|
| 150 | raise Exception.Create('Unsupported instruction parameter type');
|
|---|
| 151 | end;
|
|---|
| 152 | end;
|
|---|
| 153 | end;
|
|---|
| 154 | DecodedInstructions.Add(DecodedInstruction);
|
|---|
| 155 | end;
|
|---|
| 156 | end;
|
|---|
| 157 |
|
|---|
| 158 | procedure TDisassembler.SaveToFile(FileName: string);
|
|---|
| 159 | var
|
|---|
| 160 | Lines: TStringList;
|
|---|
| 161 | begin
|
|---|
| 162 | Lines := TStringList.Create;
|
|---|
| 163 | Disassemble;
|
|---|
| 164 | ToLines(Lines);
|
|---|
| 165 | Lines.SaveToFile(FileName);
|
|---|
| 166 | FreeAndNil(Lines);
|
|---|
| 167 | end;
|
|---|
| 168 |
|
|---|
| 169 | procedure TDisassembler.ToLines(Lines: TStrings);
|
|---|
| 170 | var
|
|---|
| 171 | I: Integer;
|
|---|
| 172 | OpcodesText: string;
|
|---|
| 173 | begin
|
|---|
| 174 | Lines.Clear;
|
|---|
| 175 | for I := 0 to DecodedInstructions.Count - 1 do
|
|---|
| 176 | with TDecodedInstruction(DecodedInstructions[I]) do begin
|
|---|
| 177 | OpcodesText := GetOpcodesText;
|
|---|
| 178 | OpcodesText := OpcodesText + DupeString(' ', 13 - Length(OpcodesText));
|
|---|
| 179 | Lines.Add(IntToHex(Address, 4) + ' ' + OpcodesText + ' ' + Name + ' ' + Parameters);
|
|---|
| 180 | end;
|
|---|
| 181 | end;
|
|---|
| 182 |
|
|---|
| 183 | constructor TDisassembler.Create;
|
|---|
| 184 | begin
|
|---|
| 185 | InstructionSet := TInstructionSet.Create;
|
|---|
| 186 | DecodedInstructions := TDecodedInstructions.Create;
|
|---|
| 187 | end;
|
|---|
| 188 |
|
|---|
| 189 | destructor TDisassembler.Destroy;
|
|---|
| 190 | begin
|
|---|
| 191 | FreeAndNil(DecodedInstructions);
|
|---|
| 192 | FreeAndNil(InstructionSet);
|
|---|
| 193 | inherited;
|
|---|
| 194 | end;
|
|---|
| 195 |
|
|---|
| 196 | end.
|
|---|
| 197 |
|
|---|