CartF8SC.cxx 6.25 KB
Newer Older
1
2
//============================================================================
//
3
4
5
//   SSSS    tt          lll  lll
//  SS  SS   tt           ll   ll
//  SS     tttttt  eeee   ll   ll   aaaa
6
7
8
9
10
//   SSSS    tt   ee  ee  ll   ll      aa
//      SS   tt   eeeeee  ll   ll   aaaaa  --  "An Atari 2600 VCS Emulator"
//  SS  SS   tt   ee      ll   ll  aa  aa
//   SSSS     ttt  eeeee llll llll  aaaaa
//
11
// Copyright (c) 1995-2018 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
16
17
18
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================

#include "System.hxx"
19
#include "CartF8SC.hxx"
20
21

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22
23
CartridgeF8SC::CartridgeF8SC(const BytePtr& image, uInt32 size,
                             const Settings& settings)
24
  : Cartridge(settings),
25
    myBankOffset(0)
26
27
{
  // Copy the ROM image into my buffer
28
  memcpy(myImage, image.get(), std::min(8192u, size));
29
  createCodeAccessBase(8192);
30
  createReadFromWritePortValues(myImage, 8192);
31
32
33
34
35
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF8SC::reset()
{
36
  initializeRAM(myRAM, 128);
37
  initializeStartBank();
38

39
  // Upon reset we switch to the startup bank
40
  bank(startBank());
41
42
43
44
45
46
47
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF8SC::install(System& system)
{
  mySystem = &system;

48
  System::PageAccess access(this, System::PA_READ);
49

50
  // Set the page accessing method for the RAM writing pages
51
  access.type = System::PA_WRITE;
52
  for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
53
  {
54
55
56
    access.directPokeBase = &myRAM[addr & 0x007F];
    access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
    mySystem->setPageAccess(addr, access);
57
  }
58

59
  // Set the page accessing method for the RAM reading pages
60
  access.directPokeBase = nullptr;
61
  access.type = System::PA_READ;
62
  for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
63
  {
64
65
66
    access.directPeekBase = &myRAM[addr & 0x007F];
    access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
    mySystem->setPageAccess(addr, access);
67
68
  }

69
  // Install pages for the startup bank
70
  bank(startBank());
71
72
73
74
75
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeF8SC::peek(uInt16 address)
{
76
  uInt16 peekAddress = address;
77
  address &= 0x0FFF;
78

stephena's avatar
stephena committed
79
80
81
82
83
84
85
  // Switch banks if necessary
  switch(address)
  {
    case 0x0FF8:
      // Set the current bank to the lower 4k bank
      bank(0);
      break;
86

stephena's avatar
stephena committed
87
88
89
90
    case 0x0FF9:
      // Set the current bank to the upper 4k bank
      bank(1);
      break;
91

stephena's avatar
stephena committed
92
93
    default:
      break;
94
95
  }

96
  if(address < 0x0080)  // Write port is at 0xF000 - 0xF07F (128 bytes)
stephena's avatar
stephena committed
97
  {
98
    // Reading from the write port triggers an unwanted write
99
    uInt8 value = randomReadFromWritePortValue(address);
100

101
    if(bankLocked())
102
103
104
      return value;
    else
    {
105
      myRAM[address] = value;
106
      triggerReadFromWritePort(peekAddress);
107
      return value;
108
    }
stephena's avatar
stephena committed
109
  }
stephena's avatar
stephena committed
110
  else
111
    return myImage[myBankOffset + address];
112
113
114
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
115
bool CartridgeF8SC::poke(uInt16 address, uInt8)
116
{
117
  address &= 0x0FFF;
118

stephena's avatar
stephena committed
119
120
121
122
123
124
125
  // Switch banks if necessary
  switch(address)
  {
    case 0x0FF8:
      // Set the current bank to the lower 4k bank
      bank(0);
      break;
126

stephena's avatar
stephena committed
127
128
129
130
    case 0x0FF9:
      // Set the current bank to the upper 4k bank
      bank(1);
      break;
131

stephena's avatar
stephena committed
132
133
    default:
      break;
134
135
136
137
138
  }

  // NOTE: This does not handle accessing RAM, however, this function
  // should never be called for RAM because of the way page accessing
  // has been setup
139
  return false;
140
141
}

142
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
143
bool CartridgeF8SC::bank(uInt16 bank)
stephena's avatar
stephena committed
144
{
145
  if(bankLocked()) return false;
146
147

  // Remember what bank we're in
148
  myBankOffset = bank << 12;
149

150
  System::PageAccess access(this, System::PA_READ);
151

152
  // Set the page accessing methods for the hot spots
153
154
  for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000;
      addr += System::PAGE_SIZE)
155
  {
156
157
    access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
    mySystem->setPageAccess(addr, access);
158
159
160
  }

  // Setup the page access methods for the current bank
161
162
  for(uInt16 addr = 0x1100; addr < (0x1FF8U & ~System::PAGE_MASK);
      addr += System::PAGE_SIZE)
163
  {
164
165
166
    access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
    access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
    mySystem->setPageAccess(addr, access);
167
  }
168
  return myBankChanged = true;
169
170
171
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
172
uInt16 CartridgeF8SC::getBank() const
173
{
174
  return myBankOffset >> 12;
175
176
177
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
178
uInt16 CartridgeF8SC::bankCount() const
179
180
181
182
183
184
185
{
  return 2;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeF8SC::patch(uInt16 address, uInt8 value)
{
186
187
  address &= 0x0FFF;

188
  if(address < 0x0100)
189
190
191
192
  {
    // Normally, a write to the read port won't do anything
    // However, the patch command is special in that ignores such
    // cart restrictions
193
    myRAM[address & 0x007F] = value;
194
195
  }
  else
196
    myImage[myBankOffset + address] = value;
197

198
  return myBankChanged = true;
stephena's avatar
stephena committed
199
}
200
201

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
202
const uInt8* CartridgeF8SC::getImage(uInt32& size) const
203
204
{
  size = 8192;
205
  return myImage;
206
207
208
209
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeF8SC::save(Serializer& out) const
210
211
212
{
  try
  {
213
    out.putShort(myBankOffset);
214
    out.putByteArray(myRAM, 128);
215
  }
216
  catch(...)
217
  {
218
    cerr << "ERROR: CartridgeF8SC::save" << endl;
219
220
221
222
223
224
225
    return false;
  }

  return true;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
226
bool CartridgeF8SC::load(Serializer& in)
227
228
229
{
  try
  {
230
    myBankOffset = in.getShort();
231
    in.getByteArray(myRAM, 128);
232
  }
233
  catch(...)
234
  {
235
    cerr << "ERROR: CartridgeF8SC::load" << endl;
236
237
238
239
    return false;
  }

  // Remember what bank we were in
240
  bank(myBankOffset >> 12);
241
242
243

  return true;
}