1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#include "Settings.hxx"
19#include "Debugger.hxx"
20#include "CartDebug.hxx"
21#include "DiStella.hxx"
22#include "CpuDebug.hxx"
23#include "GuiObject.hxx"
24#include "Font.hxx"
25#include "DataGridWidget.hxx"
26#include "EditTextWidget.hxx"
27#include "PopUpWidget.hxx"
28#include "ContextMenu.hxx"
29#include "RomListWidget.hxx"
30#include "RomWidget.hxx"
31
32// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
33RomWidget::RomWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
34 int x, int y, int w, int h)
35 : Widget(boss, lfont, x, y, w, h),
36 CommandSender(boss),
37 myListIsDirty(true)
38{
39 int xpos, ypos;
40 StaticTextWidget* t;
41 WidgetArray wid;
42
43 // Show current bank state
44 xpos = x; ypos = y + 7;
45 t = new StaticTextWidget(boss, lfont, xpos, ypos,
46 lfont.getStringWidth("Bank"),
47 lfont.getFontHeight(),
48 "Bank", TextAlign::Left);
49
50 xpos += t->getWidth() + 5;
51 myBank = new EditTextWidget(boss, nfont, xpos, ypos-2,
52 _w - 2 - xpos, nfont.getLineHeight());
53 myBank->setEditable(false);
54
55 // Create rom listing
56 xpos = x; ypos += myBank->getHeight() + 4;
57
58 myRomList = new RomListWidget(boss, lfont, nfont, xpos, ypos, _w - 4, _h - ypos - 2);
59 myRomList->setTarget(this);
60 addFocusWidget(myRomList);
61}
62
63// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
64void RomWidget::loadConfig()
65{
66 Debugger& dbg = instance().debugger();
67 CartDebug& cart = dbg.cartDebug();
68 const CartState& state = static_cast<const CartState&>(cart.getState());
69 const CartState& oldstate = static_cast<const CartState&>(cart.getOldState());
70
71 // Fill romlist the current bank of source or disassembly
72 myListIsDirty |= cart.disassemble(myListIsDirty);
73 if(myListIsDirty)
74 {
75 myRomList->setList(cart.disassembly());
76 myListIsDirty = false;
77 }
78
79 // Update romlist to point to current PC (if it has changed)
80 int pcline = cart.addressToLine(dbg.cpuDebug().pc());
81 if(pcline >= 0 && pcline != myRomList->getHighlighted())
82 myRomList->setHighlighted(pcline);
83
84 // Set current bank state
85 myBank->setText(state.bank, state.bank != oldstate.bank);
86}
87
88// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
89void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
90{
91 switch(cmd)
92 {
93 case RomListWidget::kBPointChangedCmd:
94 // 'data' is the line in the disassemblylist to be accessed
95 toggleBreak(data);
96 // Refresh the romlist, since the breakpoint may not have
97 // actually changed
98 myRomList->setDirty();
99 myRomList->draw();
100 break;
101
102 case RomListWidget::kRomChangedCmd:
103 // 'data' is the line in the disassemblylist to be accessed
104 // 'id' is the base to use for the data to be changed
105 patchROM(data, myRomList->getText(), Common::Base::Format(id));
106 break;
107
108 case RomListWidget::kSetPCCmd:
109 // 'data' is the line in the disassemblylist to be accessed
110 setPC(data);
111 break;
112
113 case RomListWidget::kRuntoPCCmd:
114 // 'data' is the line in the disassemblylist to be accessed
115 runtoPC(data);
116 break;
117
118 case RomListWidget::kDisassembleCmd:
119 invalidate();
120 break;
121
122 case RomListWidget::kTentativeCodeCmd:
123 {
124 // 'data' is the boolean value
125 DiStella::settings.resolveCode = data;
126 instance().settings().setValue("dis.resolve",
127 DiStella::settings.resolveCode);
128 invalidate();
129 break;
130 }
131
132 case RomListWidget::kPCAddressesCmd:
133 // 'data' is the boolean value
134 DiStella::settings.showAddresses = data;
135 instance().settings().setValue("dis.showaddr",
136 DiStella::settings.showAddresses);
137 invalidate();
138 break;
139
140 case RomListWidget::kGfxAsBinaryCmd:
141 // 'data' is the boolean value
142 if(data)
143 {
144 DiStella::settings.gfxFormat = Common::Base::F_2;
145 instance().settings().setValue("dis.gfxformat", "2");
146 }
147 else
148 {
149 DiStella::settings.gfxFormat = Common::Base::F_16;
150 instance().settings().setValue("dis.gfxformat", "16");
151 }
152 invalidate();
153 break;
154
155 case RomListWidget::kAddrRelocationCmd:
156 // 'data' is the boolean value
157 DiStella::settings.rFlag = data;
158 instance().settings().setValue("dis.relocate",
159 DiStella::settings.rFlag);
160 invalidate();
161 break;
162 }
163}
164
165// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
166void RomWidget::toggleBreak(int disasm_line)
167{
168 const CartDebug::DisassemblyList& list =
169 instance().debugger().cartDebug().disassembly().list;
170 if(disasm_line >= int(list.size())) return;
171
172 if(list[disasm_line].address != 0 && list[disasm_line].bytes != "")
173 instance().debugger().toggleBreakPoint(list[disasm_line].address,
174 instance().debugger().cartDebug().getBank(list[disasm_line].address));
175}
176
177// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
178void RomWidget::setPC(int disasm_line)
179{
180 const CartDebug::DisassemblyList& list =
181 instance().debugger().cartDebug().disassembly().list;
182 if(disasm_line >= int(list.size())) return;
183
184 if(list[disasm_line].address != 0)
185 {
186 ostringstream command;
187 command << "pc #" << list[disasm_line].address;
188 instance().debugger().run(command.str());
189 }
190}
191
192// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
193void RomWidget::runtoPC(int disasm_line)
194{
195 const CartDebug::DisassemblyList& list =
196 instance().debugger().cartDebug().disassembly().list;
197 if(disasm_line >= int(list.size())) return;
198
199 if(list[disasm_line].address != 0)
200 {
201 ostringstream command;
202 command << "runtopc #" << list[disasm_line].address;
203 instance().debugger().run(command.str());
204 }
205}
206
207// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
208void RomWidget::patchROM(int disasm_line, const string& bytes,
209 Common::Base::Format base)
210{
211 const CartDebug::DisassemblyList& list =
212 instance().debugger().cartDebug().disassembly().list;
213 if(disasm_line >= int(list.size())) return;
214
215 if(list[disasm_line].address != 0)
216 {
217 ostringstream command;
218
219 // Temporarily set to correct base, so we don't have to prefix each byte
220 // with the type of data
221 Common::Base::Format oldbase = Common::Base::format();
222
223 Common::Base::setFormat(base);
224 command << "rom #" << list[disasm_line].address << " " << bytes;
225 instance().debugger().run(command.str());
226
227 // Restore previous base
228 Common::Base::setFormat(oldbase);
229 }
230}
231
232// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
233void RomWidget::scrollTo(int line)
234{
235 myRomList->setSelected(line);
236}
237