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-2021 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 "CartDPC.hxx"
19 #include "DataGridWidget.hxx"
20 #include "PopUpWidget.hxx"
21 #include "CartDPCWidget.hxx"
22 
23 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeDPCWidget(GuiObject * boss,const GUI::Font & lfont,const GUI::Font & nfont,int x,int y,int w,int h,CartridgeDPC & cart)24 CartridgeDPCWidget::CartridgeDPCWidget(
25       GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
26       int x, int y, int w, int h, CartridgeDPC& cart)
27   : CartDebugWidget(boss, lfont, nfont, x, y, w, h),
28     myCart{cart}
29 {
30   const int V_GAP = 4;
31   size_t size = cart.mySize;
32   ostringstream info;
33 
34   info << "DPC cartridge, two 4K banks + 2K display bank\n"
35        << "DPC registers accessible @ $" << Common::Base::HEX4 << 0xF000 << " - $" << 0xF07F << "\n"
36        << "  $" << 0xF000 << " - " << 0xF03F << " (R), $" << 0xF040 << " - $" << 0xF07F << " (W)\n"
37 
38        << "Startup bank = " << cart.startBank() << " or undetermined\n";
39 
40   // Eventually, we should query this from the debugger/disassembler
41   for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF8; i < 2; ++i, offset += 0x1000)
42   {
43     uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset];
44     start -= start % 0x1000;
45     info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x80) << " - "
46          << "$" << (start + 0xFFF) << " (hotspot = $" << (0xF000 + spot + i) << ")\n";
47   }
48 
49   int xpos = 2,
50       ypos = addBaseInformation(size, "Activision (Pitfall II)", info.str()) +
51               myLineHeight;
52 
53   VariantList items;
54   for(int bank = 0; bank < 2; ++bank)
55   {
56     ostringstream buf;
57 
58     buf << "#" << std::dec << bank << " ($" << Common::Base::HEX4 << (0xFFF8 + bank) << ")";
59     VarList::push_back(items, buf.str());
60   }
61 
62   myBank =
63     new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("#0 ($FFFx)"),
64                     myLineHeight, items, "Set bank     ",
65                     0, kBankChanged);
66   myBank->setTarget(this);
67   addFocusWidget(myBank);
68   ypos += myLineHeight + V_GAP * 3;
69 
70   // Data fetchers
71   new StaticTextWidget(boss, _font, xpos, ypos, "Data fetchers ");
72 
73   // Top registers
74   int lwidth = _font.getStringWidth("Counter registers ");
75   xpos = 2 + _font.getMaxCharWidth() * 2; ypos += myLineHeight + 4;
76   new StaticTextWidget(boss, _font, xpos, ypos, "Top registers ");
77   xpos += lwidth;
78 
79   myTops = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::Fmt::_16);
80   myTops->setTarget(this);
81   myTops->setEditable(false);
82 
83   // Bottom registers
84   xpos = 2 + _font.getMaxCharWidth() * 2; ypos += myLineHeight + 4;
85   new StaticTextWidget(boss, _font, xpos, ypos, "Bottom registers ");
86   xpos += lwidth;
87 
88   myBottoms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::Fmt::_16);
89   myBottoms->setTarget(this);
90   myBottoms->setEditable(false);
91 
92   // Counter registers
93   xpos = 2 + _font.getMaxCharWidth() * 2; ypos += myLineHeight + 4;
94   new StaticTextWidget(boss, _font, xpos, ypos, "Counter registers ");
95   xpos += lwidth;
96 
97   myCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 4, 16, Common::Base::Fmt::_16_4);
98   myCounters->setTarget(this);
99   myCounters->setEditable(false);
100 
101   // Flag registers
102   xpos = 2 + _font.getMaxCharWidth() * 2; ypos += myLineHeight + 4;
103   new StaticTextWidget(boss, _font, xpos, ypos, "Flag registers ");
104   xpos += lwidth;
105 
106   myFlags = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::Fmt::_16);
107   myFlags->setTarget(this);
108   myFlags->setEditable(false);
109 
110   // Music mode
111   xpos = 2; ypos += myLineHeight + V_GAP * 3;
112   lwidth = _font.getStringWidth("Music mode (DF5/DF6/DF7) ");
113   new StaticTextWidget(boss, _font, xpos, ypos, "Music mode (DF5/DF6/DF7) ");
114   xpos += lwidth;
115 
116   myMusicMode = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 2, 8, Common::Base::Fmt::_16);
117   myMusicMode->setTarget(this);
118   myMusicMode->setEditable(false);
119 
120   // Current random number
121   xpos = 2; ypos += myLineHeight + V_GAP * 3;
122   new StaticTextWidget(boss, _font, xpos, ypos, "Current random number ");
123   xpos += lwidth;
124 
125   myRandom = new DataGridWidget(boss, _nfont, xpos, ypos-2, 1, 1, 2, 8, Common::Base::Fmt::_16);
126   myRandom->setTarget(this);
127   myRandom->setEditable(false);
128 }
129 
130 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
saveOldState()131 void CartridgeDPCWidget::saveOldState()
132 {
133   myOldState.tops.clear();
134   myOldState.bottoms.clear();
135   myOldState.counters.clear();
136   myOldState.flags.clear();
137   myOldState.music.clear();
138 
139   for(uInt32 i = 0; i < 8; ++i)
140   {
141     myOldState.tops.push_back(myCart.myTops[i]);
142     myOldState.bottoms.push_back(myCart.myBottoms[i]);
143     myOldState.counters.push_back(myCart.myCounters[i]);
144     myOldState.flags.push_back(myCart.myFlags[i]);
145   }
146   for(uInt32 i = 0; i < 3; ++i)
147     myOldState.music.push_back(myCart.myMusicMode[i]);
148 
149   myOldState.random = myCart.myRandomNumber;
150 
151   for(uInt32 i = 0; i < internalRamSize(); ++i)
152     myOldState.internalram.push_back(myCart.myDisplayImage[i]);
153 
154   myOldState.bank = myCart.getBank();
155 }
156 
157 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
loadConfig()158 void CartridgeDPCWidget::loadConfig()
159 {
160   myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank);
161 
162   // Get registers, using change tracking
163   IntArray alist;
164   IntArray vlist;
165   BoolArray changed;
166 
167   alist.clear();  vlist.clear();  changed.clear();
168   for(int i = 0; i < 8; ++i)
169   {
170     alist.push_back(0);  vlist.push_back(myCart.myTops[i]);
171     changed.push_back(myCart.myTops[i] != myOldState.tops[i]);
172   }
173   myTops->setList(alist, vlist, changed);
174 
175   alist.clear();  vlist.clear();  changed.clear();
176   for(int i = 0; i < 8; ++i)
177   {
178     alist.push_back(0);  vlist.push_back(myCart.myBottoms[i]);
179     changed.push_back(myCart.myBottoms[i] != myOldState.bottoms[i]);
180   }
181   myBottoms->setList(alist, vlist, changed);
182 
183   alist.clear();  vlist.clear();  changed.clear();
184   for(int i = 0; i < 8; ++i)
185   {
186     alist.push_back(0);  vlist.push_back(myCart.myCounters[i]);
187     changed.push_back(myCart.myCounters[i] != myOldState.counters[i]);
188   }
189   myCounters->setList(alist, vlist, changed);
190 
191   alist.clear();  vlist.clear();  changed.clear();
192   for(int i = 0; i < 8; ++i)
193   {
194     alist.push_back(0);  vlist.push_back(myCart.myFlags[i]);
195     changed.push_back(myCart.myFlags[i] != myOldState.flags[i]);
196   }
197   myFlags->setList(alist, vlist, changed);
198 
199   alist.clear();  vlist.clear();  changed.clear();
200   for(int i = 0; i < 3; ++i)
201   {
202     alist.push_back(0);  vlist.push_back(myCart.myMusicMode[i]);
203     changed.push_back(myCart.myMusicMode[i] != myOldState.music[i]);
204   }
205   myMusicMode->setList(alist, vlist, changed);
206 
207   myRandom->setList(0, myCart.myRandomNumber,
208       myCart.myRandomNumber != myOldState.random);
209 
210   CartDebugWidget::loadConfig();
211 }
212 
213 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
handleCommand(CommandSender * sender,int cmd,int data,int id)214 void CartridgeDPCWidget::handleCommand(CommandSender* sender,
215                                        int cmd, int data, int id)
216 {
217   if(cmd == kBankChanged)
218   {
219     myCart.unlockHotspots();
220     myCart.bank(myBank->getSelected());
221     myCart.lockHotspots();
222     invalidate();
223   }
224 }
225 
226 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bankState()227 string CartridgeDPCWidget::bankState()
228 {
229   ostringstream& buf = buffer();
230 
231   buf << "Bank #" << std::dec << myCart.getBank()
232       << " (hotspot $" << Common::Base::HEX4 << (0xFFF8 + myCart.getBank()) << ")";
233 
234   return buf.str();
235 }
236 
237 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
internalRamSize()238 uInt32 CartridgeDPCWidget::internalRamSize()
239 {
240   return 2*1024;
241 }
242 
243 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
internalRamRPort(int start)244 uInt32 CartridgeDPCWidget::internalRamRPort(int start)
245 {
246   return 0x0000 + start;
247 }
248 
249 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
internalRamDescription()250 string CartridgeDPCWidget::internalRamDescription()
251 {
252   ostringstream desc;
253   desc << "2K display data @ $0000 - $" << Common::Base::HEX4 << 0x07FF << "\n"
254     << "  indirectly accessible to 6507 via DPC's\n"
255     << "  data fetcher registers\n";
256 
257   return desc.str();
258 }
259 
260 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
internalRamOld(int start,int count)261 const ByteArray& CartridgeDPCWidget::internalRamOld(int start, int count)
262 {
263   myRamOld.clear();
264   for(int i = 0; i < count; i++)
265     myRamOld.push_back(myOldState.internalram[start + i]);
266   return myRamOld;
267 }
268 
269 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
internalRamCurrent(int start,int count)270 const ByteArray& CartridgeDPCWidget::internalRamCurrent(int start, int count)
271 {
272   myRamCurrent.clear();
273   for(int i = 0; i < count; i++)
274     myRamCurrent.push_back(myCart.myDisplayImage[start + i]);
275   return myRamCurrent;
276 }
277 
278 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
internalRamSetValue(int addr,uInt8 value)279 void CartridgeDPCWidget::internalRamSetValue(int addr, uInt8 value)
280 {
281   myCart.myDisplayImage[addr] = value;
282 }
283 
284 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
internalRamGetValue(int addr)285 uInt8 CartridgeDPCWidget::internalRamGetValue(int addr)
286 {
287   return myCart.myDisplayImage[addr];
288 }
289