source: trunk/Disassembler.pas

Last change on this file was 2, checked in by chronos, 16 months ago
  • Added: Initial development version.
File size: 5.8 KB
Line 
1unit Disassembler;
2
3interface
4
5uses
6 Classes, SysUtils, CpuZ80, Instructions, StrUtils, Memory, Generics.Collections;
7
8type
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
42implementation
43
44{ TDecodedInstructions }
45
46function TDecodedInstructions.SearchAddress(Address: Word): TDecodedInstruction;
47var
48 I: Integer;
49begin
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;
54end;
55
56{ TDecodedInstruction }
57
58constructor TDecodedInstruction.Create;
59begin
60 Parameters := '';
61end;
62
63procedure TDecodedInstruction.AddOpcode(Data: Byte);
64begin
65 SetLength(Opcodes, Length(Opcodes) + 1);
66 Opcodes[Length(Opcodes) - 1] := Data;
67end;
68
69function TDecodedInstruction.GetOpcodesText: string;
70var
71 I: Integer;
72begin
73 Result := '';
74 for I := 0 to Length(Opcodes) - 1 do
75 Result := Result + IntToHex(Opcodes[I], 2) + ' ';
76 Result := Trim(Result);
77end;
78
79procedure TDisassembler.Disassemble;
80var
81 J: Integer;
82 Value: Integer;
83 Instruction: TInstruction;
84 InstructionInfo: TInstructionInfo;
85 DecodedInstruction: TDecodedInstruction;
86begin
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;
156end;
157
158procedure TDisassembler.SaveToFile(FileName: string);
159var
160 Lines: TStringList;
161begin
162 Lines := TStringList.Create;
163 Disassemble;
164 ToLines(Lines);
165 Lines.SaveToFile(FileName);
166 FreeAndNil(Lines);
167end;
168
169procedure TDisassembler.ToLines(Lines: TStrings);
170var
171 I: Integer;
172 OpcodesText: string;
173begin
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;
181end;
182
183constructor TDisassembler.Create;
184begin
185 InstructionSet := TInstructionSet.Create;
186 DecodedInstructions := TDecodedInstructions.Create;
187end;
188
189destructor TDisassembler.Destroy;
190begin
191 FreeAndNil(DecodedInstructions);
192 FreeAndNil(InstructionSet);
193 inherited;
194end;
195
196end.
197
Note: See TracBrowser for help on using the repository browser.