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 "CartCM.hxx"
19#include "Debugger.hxx"
20#include "CartDebug.hxx"
21#include "RiotDebug.hxx"
22#include "DataGridWidget.hxx"
23#include "EditTextWidget.hxx"
24#include "PopUpWidget.hxx"
25#include "ToggleBitWidget.hxx"
26#include "CartCMWidget.hxx"
27
28// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
29CartridgeCMWidget::CartridgeCMWidget(
30 GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
31 int x, int y, int w, int h, CartridgeCM& cart)
32 : CartDebugWidget(boss, lfont, nfont, x, y, w, h),
33 myCart(cart)
34{
35 uInt16 size = 4 * 4096;
36
37 string info =
38 "CM cartridge, four 4K banks + 2K RAM\n"
39 "2K RAM accessible @ $1800 - $1FFF in read or write-only mode "
40 "(no separate ports)\n"
41 "All TIA controller registers (INPT0-INPT5) and RIOT SWCHA are "
42 "used to control the cart functionality\n"
43 "Startup bank = 3 (ROM), RAM disabled\n";
44
45 int xpos = 2,
46 ypos = addBaseInformation(size, "CompuMate", info) + myLineHeight;
47
48 VariantList items;
49 VarList::push_back(items, " 0 ");
50 VarList::push_back(items, " 1 ");
51 VarList::push_back(items, " 2 ");
52 VarList::push_back(items, " 3 ");
53 myBank =
54 new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth(" 0 "),
55 myLineHeight, items, "Set bank ",
56 0, kBankChanged);
57 myBank->setTarget(this);
58 addFocusWidget(myBank);
59
60 // Raw SWCHA value (this will be broken down further in other UI elements)
61 int lwidth = _font.getStringWidth("Current column ");
62 ypos += myLineHeight + 8;
63 new StaticTextWidget(boss, _font, xpos, ypos+2, lwidth, myFontHeight,
64 "Current SWCHA ", TextAlign::Left);
65 xpos += lwidth;
66 mySWCHA = new ToggleBitWidget(boss, _nfont, xpos, ypos, 8, 1);
67 mySWCHA->setTarget(this);
68 mySWCHA->setEditable(false);
69
70 // Current column number
71 xpos = 10; ypos += myLineHeight + 5;
72 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
73 myFontHeight, "Current column ", TextAlign::Left);
74 xpos += lwidth;
75
76 myColumn = new DataGridWidget(boss, _nfont, xpos, ypos-2, 1, 1, 2, 8, Common::Base::F_16);
77 myColumn->setTarget(this);
78 myColumn->setEditable(false);
79
80 // Relevant pins of SWCHA
81 xpos = 30;
82
83 // D6 (column part)
84 ypos += myLineHeight + 8;
85 myIncrease = new CheckboxWidget(boss, _font, xpos, ypos, "Increase Column");
86 myIncrease->setTarget(this);
87 myIncrease->setEditable(false);
88
89 int orig_ypos = ypos; // save for when we go to the next column
90
91 // D5 (column part)
92 ypos += myLineHeight + 4;
93 myReset = new CheckboxWidget(boss, _font, xpos, ypos, "Reset Column");
94 myReset->setTarget(this);
95 myReset->setEditable(false);
96
97 // Row inputs
98 ypos += myLineHeight + 4;
99 myRow[0] = new CheckboxWidget(boss, _font, xpos, ypos, "Row 0");
100 myRow[0]->setTarget(this);
101 myRow[0]->setEditable(false);
102 ypos += myLineHeight + 4;
103 myRow[1] = new CheckboxWidget(boss, _font, xpos, ypos, "Row 1");
104 myRow[1]->setTarget(this);
105 myRow[1]->setEditable(false);
106 ypos += myLineHeight + 4;
107 myRow[2] = new CheckboxWidget(boss, _font, xpos, ypos, "Row 2");
108 myRow[2]->setTarget(this);
109 myRow[2]->setEditable(false);
110 ypos += myLineHeight + 4;
111 myRow[3] = new CheckboxWidget(boss, _font, xpos, ypos, "Row 3");
112 myRow[3]->setTarget(this);
113 myRow[3]->setEditable(false);
114
115 // Func and Shift keys
116 ypos += myLineHeight + 4;
117 myFunc = new CheckboxWidget(boss, _font, xpos, ypos, "FUNC key pressed");
118 myFunc->setTarget(this);
119 myFunc->setEditable(false);
120 ypos += myLineHeight + 4;
121 myShift = new CheckboxWidget(boss, _font, xpos, ypos, "Shift key pressed");
122 myShift->setTarget(this);
123 myShift->setEditable(false);
124
125 // Move to next column
126 xpos += myShift->getWidth() + 20; ypos = orig_ypos;
127
128 // D7
129 myAudIn = new CheckboxWidget(boss, _font, xpos, ypos, "Audio Input");
130 myAudIn->setTarget(this);
131 myAudIn->setEditable(false);
132
133 // D6 (audio part)
134 ypos += myLineHeight + 4;
135 myAudOut = new CheckboxWidget(boss, _font, xpos, ypos, "Audio Output");
136 myAudOut->setTarget(this);
137 myAudOut->setEditable(false);
138
139 // Ram state (combination of several bits in SWCHA)
140 ypos += myLineHeight + 8;
141 lwidth = _font.getStringWidth("Ram State ");
142 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
143 myFontHeight, "Ram State ", TextAlign::Left);
144 myRAM = new EditTextWidget(boss, _nfont, xpos+lwidth, ypos-2,
145 _nfont.getStringWidth(" Write-only "), myLineHeight, "");
146 myRAM->setEditable(false, true);
147}
148
149// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
150void CartridgeCMWidget::saveOldState()
151{
152 myOldState.swcha = myCart.mySWCHA;
153 myOldState.column = myCart.column();
154
155 myOldState.internalram.clear();
156 for(uInt32 i = 0; i < internalRamSize(); ++i)
157 myOldState.internalram.push_back(myCart.myRAM[i]);
158
159 myOldState.bank = myCart.getBank();
160}
161
162// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
163void CartridgeCMWidget::loadConfig()
164{
165 myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank);
166
167 RiotDebug& riot = Debugger::debugger().riotDebug();
168 const RiotState& state = static_cast<const RiotState&>(riot.getState());
169
170 uInt8 swcha = myCart.mySWCHA;
171
172 // SWCHA
173 BoolArray oldbits, newbits, changed;
174 Debugger::set_bits(myOldState.swcha, oldbits);
175 Debugger::set_bits(swcha, newbits);
176
177 for(uInt32 i = 0; i < oldbits.size(); ++i)
178 changed.push_back(oldbits[i] != newbits[i]);
179 mySWCHA->setState(newbits, changed);
180
181 // Column
182 myColumn->setList(0, myCart.column(), myCart.column() != myOldState.column);
183
184 // Various bits from SWCHA and INPTx
185 myIncrease->setState(swcha & 0x40);
186 myReset->setState(swcha & 0x20);
187 myRow[0]->setState(!(state.INPT4 & 0x80));
188 myRow[1]->setState(!(swcha & 0x04));
189 myRow[2]->setState(!(state.INPT5 & 0x80));
190 myRow[3]->setState(!(swcha & 0x08));
191 myFunc->setState(state.INPT0 & 0x80);
192 myShift->setState(state.INPT3 & 0x80);
193
194 // Audio in and out (used for communicating with the external cassette)
195 myAudIn->setState(swcha & 0x80);
196 myAudOut->setState(swcha & 0x40);
197
198 // RAM state (several bits from SWCHA)
199 const string& ram = (swcha & 0x10) ? " Inactive" :
200 (swcha & 0x20) ? " Read-only" : " Write-only";
201 myRAM->setText(ram, (swcha & 0x30) != (myOldState.swcha & 0x30));
202
203 CartDebugWidget::loadConfig();
204}
205
206// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
207void CartridgeCMWidget::handleCommand(CommandSender* sender,
208 int cmd, int data, int id)
209{
210 if(cmd == kBankChanged)
211 {
212 myCart.unlockBank();
213 myCart.mySWCHA &= 0xFC;
214 myCart.mySWCHA |= myBank->getSelected();
215 myCart.bank(myCart.mySWCHA & 0x03);
216 myCart.lockBank();
217 invalidate();
218 }
219}
220
221// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
222string CartridgeCMWidget::bankState()
223{
224 ostringstream& buf = buffer();
225
226 buf << "Bank = " << std::dec << myCart.getBank()
227 << ", RAM is" << ((myCart.mySWCHA & 0x10) ? " Inactive" :
228 (myCart.mySWCHA & 0x20) ? " Read-only" : " Write-only");
229
230 return buf.str();
231}
232
233
234// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
235uInt32 CartridgeCMWidget::internalRamSize()
236{
237 return 2048;
238}
239
240// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
241uInt32 CartridgeCMWidget::internalRamRPort(int start)
242{
243 return 0xF800 + start;
244}
245
246// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
247string CartridgeCMWidget::internalRamDescription()
248{
249 ostringstream desc;
250 desc << "$F800 - $FFFF used for Exclusive Read\n"
251 << " or Exclusive Write Access";
252
253 return desc.str();
254}
255
256// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
257const ByteArray& CartridgeCMWidget::internalRamOld(int start, int count)
258{
259 myRamOld.clear();
260 for(int i = 0; i < count; i++)
261 myRamOld.push_back(myOldState.internalram[start + i]);
262 return myRamOld;
263}
264
265// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
266const ByteArray& CartridgeCMWidget::internalRamCurrent(int start, int count)
267{
268 myRamCurrent.clear();
269 for(int i = 0; i < count; i++)
270 myRamCurrent.push_back(myCart.myRAM[start + i]);
271 return myRamCurrent;
272}
273
274// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
275void CartridgeCMWidget::internalRamSetValue(int addr, uInt8 value)
276{
277 myCart.myRAM[addr] = value;
278}
279
280// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
281uInt8 CartridgeCMWidget::internalRamGetValue(int addr)
282{
283 return myCart.myRAM[addr];
284}
285
286// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
287string CartridgeCMWidget::internalRamLabel(int addr)
288{
289 CartDebug& dbg = instance().debugger().cartDebug();
290 return dbg.getLabel(addr + 0xF800, false);
291}
292