source: trunk/Debugger.pas

Last change on this file was 15, checked in by chronos, 3 weeks ago
  • Modified: Faster instruction stepping.
File size: 4.5 KB
Line 
1unit Debugger;
2
3interface
4
5uses
6 Classes, SysUtils, Generics.Collections, Generics.Defaults, Z80, Disassembler;
7
8type
9 TDebugMode = (dmNone, dmStepIn, dmStepOut, dmStepOver, dmStopAddress);
10
11 { TBreakPoints }
12
13 TBreakPoints = class(TList<Word>)
14 private
15 function Comparer(constref Left, Right: Word): Integer;
16 public
17 function Contains(Address: Word): Boolean;
18 procedure AddNew(Address: Word);
19 end;
20
21 TCallStack = class;
22
23 { TCallStackItem }
24
25 TCallStackItem = class
26 private
27 FCommentDecoded: Boolean;
28 FComment: string;
29 function GetComment: string;
30 public
31 CallStack: TCallStack;
32 Address: Word;
33 Value: Word;
34 property Comment: string read GetComment;
35 end;
36
37 { TCallStack }
38
39 TCallStack = class(TObjectList<TCallStackItem>)
40 Disassembler: TDisassembler;
41 function AddNew(Address: Word): TCallStackItem;
42 end;
43
44 { TDebugger }
45
46 TDebugger = class
47 private
48 FCpu: TCpuZ80;
49 FDisassembler: TDisassembler;
50 FOnChange: TNotifyEvent;
51 procedure Pause;
52 procedure SetCpu(AValue: TCpuZ80);
53 procedure CpuCall(Address: Word);
54 procedure CpuReturn;
55 procedure CpuStep;
56 procedure DoOnChange;
57 procedure SetDisassembler(AValue: TDisassembler);
58 public
59 BreakPoints: TBreakPoints;
60 DebugMode: TDebugMode;
61 DebugStopAddress: Word;
62 CallStack: TCallStack;
63 procedure Reset;
64 constructor Create;
65 destructor Destroy; override;
66 property Cpu: TCpuZ80 read FCpu write SetCpu;
67 property Disassembler: TDisassembler read FDisassembler write SetDisassembler;
68 property OnChange: TNotifyEvent read FOnChange write FOnChange;
69 end;
70
71
72implementation
73
74{ TDebugger }
75
76procedure TDebugger.SetCpu(AValue: TCpuZ80);
77begin
78 if FCpu = AValue then Exit;
79 if Assigned(FCpu) then begin
80 FCpu.OnCall := nil;
81 FCpu.OnReturn := nil;
82 FCpu.OnStep := nil;
83 end;
84 FCpu := AValue;
85 if Assigned(FCpu) then begin
86 FCpu.OnCall := CpuCall;
87 FCpu.OnReturn := CpuReturn;
88 FCpu.OnStep := CpuStep;
89 end;
90end;
91
92procedure TDebugger.CpuCall(Address: Word);
93begin
94 CallStack.AddNew(Address);
95 if DebugMode = dmStepOver then begin
96 DebugStopAddress := Cpu.PC;
97 DebugMode := dmStopAddress;
98 end;
99 DoOnChange;
100end;
101
102procedure TDebugger.CpuReturn;
103begin
104 if CallStack.Count > 0 then CallStack.Delete(CallStack.Count - 1);
105 if DebugMode = dmStepOut then begin
106 Cpu.Paused := True;
107 DebugMode := dmNone;
108 end;
109 DoOnChange;
110end;
111
112procedure TDebugger.Pause;
113begin
114 DebugMode := dmNone;
115 Cpu.Paused := True;
116 DoOnChange;
117end;
118
119procedure TDebugger.CpuStep;
120begin
121 if DebugMode <> dmNone then begin
122 if DebugMode = dmStepIn then begin
123 Pause;
124 end;
125 if (DebugMode = dmStopAddress) and (DebugStopAddress = Cpu.PC) then begin
126 Pause;
127 end;
128 if DebugMode = dmStepOver then begin
129 Pause;
130 end;
131 end;
132 if BreakPoints.Contains(Cpu.PC) then begin
133 Pause;
134 end;
135 DoOnChange;
136end;
137
138procedure TDebugger.DoOnChange;
139begin
140 if Assigned(FOnChange) then FOnChange(Self);
141end;
142
143procedure TDebugger.SetDisassembler(AValue: TDisassembler);
144begin
145 if FDisassembler = AValue then Exit;
146 FDisassembler := AValue;
147 CallStack.Disassembler := AValue;
148end;
149
150procedure TDebugger.Reset;
151begin
152 BreakPoints.Clear;
153 CallStack.Clear;
154end;
155
156constructor TDebugger.Create;
157begin
158 BreakPoints := TBreakPoints.Create(TComparer<Word>.Construct(TBreakPoints.Comparer));
159 CallStack := TCallStack.Create;
160end;
161
162destructor TDebugger.Destroy;
163begin
164 FreeAndNil(CallStack);
165 FreeAndNil(BreakPoints);
166 inherited;
167end;
168
169{ TBreakPoints }
170
171function TBreakPoints.Comparer(constref Left, Right: Word): Integer;
172begin
173 if Left > Right then Result := 1
174 else if Left < Right then Result := -1
175 else Result := 0;
176end;
177
178function TBreakPoints.Contains(Address: Word): Boolean;
179var
180 Index: SizeInt;
181begin
182 if (Count > 0) and BinarySearch(Address, Index) then begin
183 Result := True;
184 end else Result := False;
185end;
186
187procedure TBreakPoints.AddNew(Address: Word);
188begin
189 Add(Address);
190 Sort;
191end;
192
193{ TCallStackItem }
194
195function TCallStackItem.GetComment: string;
196var
197 Instruction: TDecodedInstruction;
198begin
199 if not FCommentDecoded then begin
200 Instruction := CallStack.Disassembler.DecodedInstructions.SearchAddress(Address);
201 if Assigned(Instruction) then
202 FComment := Instruction.Comment;
203 FCommentDecoded := True;
204 end;
205 Result := FComment;
206end;
207
208{ TCallStack }
209
210function TCallStack.AddNew(Address: Word): TCallStackItem;
211begin
212 Result := TCallStackItem.Create;
213 Result.Address := Address;
214 Result.CallStack := Self;
215 Add(Result);
216end;
217
218
219end.
220
Note: See TracBrowser for help on using the repository browser.