~ubuntu-branches/debian/squeeze/stella/squeeze

« back to all changes in this revision

Viewing changes to src/emucore/CartAR.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Tom Lear
  • Date: 1999-11-06 16:41:05 UTC
  • Revision ID: james.westby@ubuntu.com-19991106164105-iygopamo5mpcozvx
Tags: upstream-1.1
ImportĀ upstreamĀ versionĀ 1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-1999 by Bradford W. Mott
 
12
//
 
13
// See the file "license" for information on usage and redistribution of
 
14
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
 
15
//
 
16
// $Id: CartAR.cxx,v 1.5 1999/02/22 16:30:30 bwmott Exp $
 
17
//============================================================================
 
18
 
 
19
#include <assert.h>
 
20
#include <string.h>
 
21
#include "CartAR.hxx"
 
22
#include "M6502Hi.hxx"
 
23
#include "Random.hxx"
 
24
#include "System.hxx"
 
25
 
 
26
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
27
CartridgeAR::CartridgeAR(const uInt8* image, uInt32 size)
 
28
    : my6502(0)
 
29
{
 
30
  uInt32 i;
 
31
 
 
32
  // Create a load image buffer and copy the given image
 
33
  myLoadImages = new uInt8[size];
 
34
  myNumberOfLoadImages = size / 8448;
 
35
  memcpy(myLoadImages, image, size);
 
36
 
 
37
  // Initialize RAM with random values
 
38
  Random random;
 
39
  for(i = 0; i < 6 * 1024; ++i)
 
40
  {
 
41
    myImage[i] = random.next();
 
42
  }
 
43
 
 
44
  // Initialize ROM with an invalid 6502 opcode 
 
45
  for(i = 6 * 1024; i < 8 * 1024; ++i)
 
46
  {
 
47
    myImage[i] = 0xFF; 
 
48
  }
 
49
}
 
50
 
 
51
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
52
CartridgeAR::~CartridgeAR()
 
53
{
 
54
  delete[] myLoadImages;
 
55
}
 
56
 
 
57
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
58
const char* CartridgeAR::name() const
 
59
{
 
60
  return "CartridgeAR";
 
61
}
 
62
 
 
63
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
64
void CartridgeAR::reset()
 
65
{
 
66
  // Try to load the first load into RAM upon reset
 
67
  loadIntoRAM(0);
 
68
 
 
69
  myPower = true;
 
70
  myPowerRomCycle = 0;
 
71
  myWriteEnabled = false;
 
72
 
 
73
  myLastAccess = 0;
 
74
  myNumberOfDistinctAccesses = 0;
 
75
  myWritePending = false;
 
76
 
 
77
  // Set bank configuration upon reset so ROM is selected
 
78
  myImageOffset[0] = 0 * 2048;
 
79
  myImageOffset[1] = 3 * 2048;
 
80
}
 
81
 
 
82
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
83
void CartridgeAR::systemCyclesReset()
 
84
{
 
85
  // Get the current system cycle
 
86
  uInt32 cycles = mySystem->cycles();
 
87
 
 
88
  // Adjust cycle values
 
89
  myPowerRomCycle -= cycles;
 
90
}
 
91
 
 
92
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
93
void CartridgeAR::install(System& system)
 
94
{
 
95
  mySystem = &system;
 
96
  uInt16 shift = mySystem->pageShift();
 
97
  uInt16 mask = mySystem->pageMask();
 
98
 
 
99
  my6502 = &(M6502High&)mySystem->m6502();
 
100
 
 
101
  // Make sure the system we're being installed in has a page size that'll work
 
102
  assert((0x1000 & mask) == 0);
 
103
 
 
104
  System::PageAccess access;
 
105
  for(uInt32 i = 0x1000; i < 0x2000; i += (1 << shift))
 
106
  {
 
107
    access.directPeekBase = 0;
 
108
    access.directPokeBase = 0;
 
109
    access.device = this;
 
110
    mySystem->setPageAccess(i >> shift, access);
 
111
  }
 
112
 
 
113
  bankConfiguration(0);
 
114
}
 
115
 
 
116
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
117
uInt8 CartridgeAR::peek(uInt16 addr)
 
118
{
 
119
  // Check to see if the Supercharger ROM is being accessed?
 
120
  if(myImageOffset[1] == 3 * 2048)
 
121
  {
 
122
    Int32 cycles = mySystem->cycles();
 
123
 
 
124
    // Is the tape rewind routine being accessed?
 
125
    if((addr & 0x1FFF) == 0x180A)
 
126
    {
 
127
      // See if the ROM has been powered up long enough
 
128
      if(!myPower || (myPower && ((myPowerRomCycle + 7) > cycles)))
 
129
      {
 
130
        cerr << "ERROR: Supercharger ROM has not been powered up!\n";
 
131
      }
 
132
      else
 
133
      {
 
134
        cerr << "ERROR: Supercharger code doesn't handle rewinding tape!\n";
 
135
      }
 
136
    }
 
137
    // Is the multiload routine being accessed?
 
138
    else if((addr & 0x1FFF) == 0x1800)
 
139
    {
 
140
      // See if the ROM has been powered up long enough
 
141
      if(!myPower || (myPower && ((myPowerRomCycle + 7) > cycles)))
 
142
      {
 
143
        cerr << "ERROR: Supercharger ROM has not been powered up!\n";
 
144
      }
 
145
      else
 
146
      {
 
147
        // Get the load they're trying to access
 
148
        uInt8 load = mySystem->peek(0x00FA);
 
149
 
 
150
        // Load the specified load into RAM
 
151
        loadIntoRAM(load);
 
152
 
 
153
        return myImage[(addr & 0x07FF) + myImageOffset[1]];
 
154
      }
 
155
    }
 
156
  }
 
157
 
 
158
  // Are the "value" registers being accessed?
 
159
  if(!(addr & 0x0F00) && (!myWriteEnabled || !myWritePending))
 
160
  {
 
161
    myLastAccess = addr;
 
162
    myNumberOfDistinctAccesses = my6502->distinctAccesses();
 
163
    myWritePending = true;
 
164
  }
 
165
  // Is the bank configuration hotspot being accessed?
 
166
  else if((addr & 0x1FFF) == 0x1FF8)
 
167
  {
 
168
    // Yes, so handle bank configuration
 
169
    myWritePending = false;
 
170
    bankConfiguration(myLastAccess);
 
171
  }
 
172
  // Handle poke if writing enabled
 
173
  else if(myWriteEnabled && myWritePending)
 
174
  {
 
175
    if(my6502->distinctAccesses() >= myNumberOfDistinctAccesses + 5)
 
176
    {
 
177
      if(my6502->distinctAccesses() == myNumberOfDistinctAccesses + 5)
 
178
      {
 
179
        if((addr & 0x0800) == 0)
 
180
          myImage[(addr & 0x07FF) + myImageOffset[0]] = myLastAccess;
 
181
        else if(myImageOffset[1] != 3 * 2048)    // Can't poke to ROM :-)
 
182
          myImage[(addr & 0x07FF) + myImageOffset[1]] = myLastAccess;
 
183
      }
 
184
      myWritePending = false;
 
185
    } 
 
186
  }
 
187
 
 
188
  return myImage[(addr & 0x07FF) + myImageOffset[(addr & 0x0800) ? 1 : 0]];
 
189
}
 
190
 
 
191
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
192
void CartridgeAR::poke(uInt16 addr, uInt8)
 
193
{
 
194
  // Are the "value" registers being accessed?
 
195
  if(!(addr & 0x0F00) && (!myWriteEnabled || !myWritePending))
 
196
  {
 
197
    myLastAccess = addr;
 
198
    myNumberOfDistinctAccesses = my6502->distinctAccesses();
 
199
    myWritePending = true;
 
200
  }
 
201
  // Is the bank configuration hotspot being accessed?
 
202
  else if((addr & 0x1FFF) == 0x1FF8)
 
203
  {
 
204
    // Yes, so handle bank configuration
 
205
    myWritePending = false;
 
206
    bankConfiguration(myLastAccess);
 
207
  }
 
208
  // Handle poke if writing enabled
 
209
  else if(myWriteEnabled && myWritePending)
 
210
  {
 
211
    if(my6502->distinctAccesses() >= myNumberOfDistinctAccesses + 5)
 
212
    {
 
213
      if(my6502->distinctAccesses() == myNumberOfDistinctAccesses + 5)
 
214
      {
 
215
        if((addr & 0x0800) == 0)
 
216
          myImage[(addr & 0x07FF) + myImageOffset[0]] = myLastAccess;
 
217
        else if(myImageOffset[1] != 3 * 2048)    // Can't poke to ROM :-)
 
218
          myImage[(addr & 0x07FF) + myImageOffset[1]] = myLastAccess;
 
219
      }
 
220
      myWritePending = false;
 
221
    } 
 
222
  }
 
223
}
 
224
 
 
225
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
226
void CartridgeAR::bankConfiguration(uInt8 configuration)
 
227
{
 
228
  // D7-D5 of this byte: Write Pulse Delay (n/a for emulator)
 
229
  //
 
230
  // D4-D0: RAM/ROM configuration:
 
231
  //       $F000-F7FF    $F800-FFFF Address range that banks map into
 
232
  //  000wp     2            ROM
 
233
  //  001wp     0            ROM
 
234
  //  010wp     2            0      as used in Commie Mutants and many others
 
235
  //  011wp     0            2      as used in Suicide Mission
 
236
  //  100wp     2            ROM
 
237
  //  101wp     1            ROM
 
238
  //  110wp     2            1      as used in Killer Satellites
 
239
  //  111wp     1            2      as we use for 2k/4k ROM cloning
 
240
  // 
 
241
  //  w = Write Enable (1 = enabled; accesses to $F000-$F0FF cause writes
 
242
  //    to happen.  0 = disabled, and the cart acts like ROM.)
 
243
  //  p = ROM Power (0 = enabled, 1 = off.)  Only power the ROM if you're
 
244
  //    wanting to access the ROM for multiloads.  Otherwise set to 1.
 
245
 
 
246
  // Handle ROM power configuration
 
247
  myPower = !(configuration & 0x01);
 
248
 
 
249
  if(myPower)
 
250
  {
 
251
    myPowerRomCycle = mySystem->cycles();
 
252
  }
 
253
 
 
254
  myWriteEnabled = configuration & 0x02;
 
255
 
 
256
  switch((configuration >> 2) & 0x07)
 
257
  {
 
258
    case 0:
 
259
    {
 
260
      myImageOffset[0] = 2 * 2048;
 
261
      myImageOffset[1] = 3 * 2048;
 
262
      break;
 
263
    }
 
264
 
 
265
    case 1:
 
266
    {
 
267
      myImageOffset[0] = 0 * 2048;
 
268
      myImageOffset[1] = 3 * 2048;
 
269
      break;
 
270
    }
 
271
 
 
272
    case 2:
 
273
    {
 
274
      myImageOffset[0] = 2 * 2048;
 
275
      myImageOffset[1] = 0 * 2048;
 
276
      break;
 
277
    }
 
278
 
 
279
    case 3:
 
280
    {
 
281
      myImageOffset[0] = 0 * 2048;
 
282
      myImageOffset[1] = 2 * 2048;
 
283
      break;
 
284
    }
 
285
 
 
286
    case 4:
 
287
    {
 
288
      myImageOffset[0] = 2 * 2048;
 
289
      myImageOffset[1] = 3 * 2048;
 
290
      break;
 
291
    }
 
292
 
 
293
    case 5:
 
294
    {
 
295
      myImageOffset[0] = 1 * 2048;
 
296
      myImageOffset[1] = 3 * 2048;
 
297
      break;
 
298
    }
 
299
 
 
300
    case 6:
 
301
    {
 
302
      myImageOffset[0] = 2 * 2048;
 
303
      myImageOffset[1] = 1 * 2048;
 
304
      break;
 
305
    }
 
306
 
 
307
    case 7:
 
308
    {
 
309
      myImageOffset[0] = 1 * 2048;
 
310
      myImageOffset[1] = 2 * 2048;
 
311
      break;
 
312
    }
 
313
  }
 
314
}
 
315
 
 
316
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
317
void CartridgeAR::setupROM()
 
318
{
 
319
  static uInt8 dummyROMCode[] = {
 
320
    0xa9, 0x0, 0xa2, 0x0, 0x95, 0x80, 0xe8, 0xe0, 
 
321
    0x80, 0xd0, 0xf9, 0x4c, 0x2b, 0xfa, 0xff, 0xff, 
 
322
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
 
323
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
 
324
    0xa9, 0x0, 0xa2, 0x0, 0x95, 0x80, 0xe8, 0xe0, 
 
325
    0x1e, 0xd0, 0xf9, 0xa2, 0x0, 0xbd, 0x45, 0xfa, 
 
326
    0x95, 0xfa, 0xe8, 0xe0, 0x6, 0xd0, 0xf6, 0xa2, 
 
327
    0xff, 0xa0, 0x0, 0xa9, 0x0, 0x85, 0x80, 0xcd, 
 
328
    0x0, 0xf0, 0x4c, 0xfa, 0x0, 0xad, 0xf8, 0xff, 
 
329
    0x4c, 0x0, 0x0
 
330
  };
 
331
 
 
332
  int size = sizeof(dummyROMCode);
 
333
 
 
334
  // Copy the "dummy" ROM code into the ROM area
 
335
  for(int i = 0; i < size; ++i)
 
336
  {
 
337
    myImage[0x1A00 + i] = dummyROMCode[i];
 
338
  }
 
339
 
 
340
  // Put a JMP $FA20 at multiload entry point ($F800)
 
341
  myImage[0x1800] = 0x4C;
 
342
  myImage[0x1801] = 0x20;
 
343
  myImage[0x1802] = 0xFA;
 
344
 
 
345
  // Update ROM code to have the correct reset address and bank configuration
 
346
  myImage[0x1A00 + size - 2] = myHeader[0];
 
347
  myImage[0x1A00 + size - 1] = myHeader[1];
 
348
  myImage[0x1A00 + size - 11] = myHeader[2];
 
349
  myImage[0x1A00 + size - 15] = myHeader[2];
 
350
 
 
351
  // Finally set 6502 vectors to point to this "dummy" code at 0xFA00
 
352
  myImage[3 * 2048 + 2044] = 0x00;
 
353
  myImage[3 * 2048 + 2045] = 0xFA;
 
354
  myImage[3 * 2048 + 2046] = 0x00;
 
355
  myImage[3 * 2048 + 2047] = 0xFA;
 
356
}
 
357
 
 
358
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
359
uInt8 CartridgeAR::checksum(uInt8* s, uInt16 length)
 
360
{
 
361
  uInt8 sum = 0;
 
362
 
 
363
  for(uInt32 i = 0; i < length; ++i)
 
364
  {
 
365
    sum += s[i];
 
366
  }
 
367
 
 
368
  return sum;
 
369
}
 
370
 
 
371
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
372
void CartridgeAR::loadIntoRAM(uInt8 load)
 
373
{
 
374
  uInt16 image;
 
375
 
 
376
  // Scan through all of the loads to see if we find the one we're looking for
 
377
  for(image = 0; image < myNumberOfLoadImages; ++image)
 
378
  {
 
379
    // Is this the correct load?
 
380
    if(myLoadImages[(image * 8448) + 8192 + 5] == load)
 
381
    {
 
382
      // Copy the load's header
 
383
      memcpy(myHeader, myLoadImages + (image * 8448) + 8192, 256);
 
384
 
 
385
      // Verify the load's header 
 
386
      if(checksum(myHeader, 8) != 0x55)
 
387
      {
 
388
        cerr << "WARNING: The Supercharger header checksum is invalid...\n";
 
389
      }
 
390
 
 
391
      // Load all of the pages from the load
 
392
      bool invalidPageChecksumSeen = false;
 
393
      for(uInt32 j = 0; j < myHeader[3]; ++j)
 
394
      {
 
395
        uInt32 bank = myHeader[16 + j] & 0x03;
 
396
        uInt32 page = (myHeader[16 + j] >> 2) & 0x07;
 
397
        uInt8* src = myLoadImages + (image * 8448) + (j * 256);
 
398
        uInt8 sum = checksum(src, 256) + myHeader[16 + j] + myHeader[64 + j];
 
399
 
 
400
        if(!invalidPageChecksumSeen && (sum != 0x55))
 
401
        {
 
402
          cerr << "WARNING: Some Supercharger page checksums are invalid...\n";
 
403
          invalidPageChecksumSeen = true;
 
404
        }
 
405
 
 
406
        // Copy page to Supercharger RAM
 
407
        memcpy(myImage + (bank * 2048) + (page * 256), src, 256);
 
408
      }
 
409
 
 
410
      // Make sure the "dummy" ROM is installed
 
411
      setupROM();
 
412
      return;
 
413
    }
 
414
  }
 
415
 
 
416
  // TODO: Should probably switch to an internal ROM routine to display
 
417
  // this message to the user...
 
418
  cerr << "ERROR: Supercharger load is missing from ROM image...\n";
 
419
}
 
420