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 "M6502.hxx"
19#include "System.hxx"
20#include "CartAR.hxx"
21
22// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
23CartridgeAR::CartridgeAR(const ByteBuffer& image, size_t size,
24 const string& md5, const Settings& settings)
25 : Cartridge(settings, md5),
26 mySize(std::max<size_t>(size, 8448)),
27 myWriteEnabled(false),
28 myPower(true),
29 myDataHoldRegister(0),
30 myNumberOfDistinctAccesses(0),
31 myWritePending(false),
32 myCurrentBank(0)
33{
34 // Create a load image buffer and copy the given image
35 myLoadImages = make_unique<uInt8[]>(mySize);
36 myNumberOfLoadImages = uInt8(mySize / 8448);
37 std::copy_n(image.get(), size, myLoadImages.get());
38
39 // Add header if image doesn't include it
40 if(size < 8448)
41 std::copy_n(ourDefaultHeader.data(), ourDefaultHeader.size(), myLoadImages.get()+myImage.size());
42
43 // We use System::PageAccess.codeAccessBase, but don't allow its use
44 // through a pointer, since the AR scheme doesn't support bankswitching
45 // in the normal sense
46 //
47 // Instead, access will be through the getAccessFlags and setAccessFlags
48 // methods below
49 createCodeAccessBase(mySize);
50}
51
52// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
53void CartridgeAR::reset()
54{
55 // Initialize RAM
56#if 0 // TODO - figure out actual behaviour of the real cart
57 initializeRAM(myImage.data(), myImage.size());
58#else
59 myImage.fill(0);
60#endif
61
62 // Initialize SC BIOS ROM
63 initializeROM();
64
65 myWriteEnabled = false;
66 myPower = true;
67
68 myDataHoldRegister = 0;
69 myNumberOfDistinctAccesses = 0;
70 myWritePending = false;
71
72 // Set bank configuration upon reset so ROM is selected and powered up
73 bankConfiguration(0);
74}
75
76// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
77void CartridgeAR::install(System& system)
78{
79 mySystem = &system;
80
81 // Map all of the accesses to call peek and poke (we don't yet indicate RAM areas)
82 System::PageAccess access(this, System::PageAccessType::READ);
83 for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
84 mySystem->setPageAccess(addr, access);
85
86 bankConfiguration(0);
87}
88
89// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
90uInt8 CartridgeAR::peek(uInt16 addr)
91{
92 // In debugger/bank-locked mode, we ignore all hotspots and in general
93 // anything that can change the internal state of the cart
94 if(bankLocked())
95 return myImage[(addr & 0x07FF) + myImageOffset[(addr & 0x0800) ? 1 : 0]];
96
97 // Is the "dummy" SC BIOS hotspot for reading a load being accessed?
98 if(((addr & 0x1FFF) == 0x1850) && (myImageOffset[1] == (3 << 11)))
99 {
100 // Get load that's being accessed (BIOS places load number at 0x80)
101 uInt8 load = mySystem->peek(0x0080);
102
103 // Read the specified load into RAM
104 loadIntoRAM(load);
105
106 return myImage[(addr & 0x07FF) + myImageOffset[1]];
107 }
108
109 // Cancel any pending write if more than 5 distinct accesses have occurred
110 // TODO: Modify to handle when the distinct counter wraps around...
111 if(myWritePending &&
112 (mySystem->m6502().distinctAccesses() > myNumberOfDistinctAccesses + 5))
113 {
114 myWritePending = false;
115 }
116
117 // Is the data hold register being set?
118 if(!(addr & 0x0F00) && (!myWriteEnabled || !myWritePending))
119 {
120 myDataHoldRegister = uInt8(addr); // FIXME - check cast here
121 myNumberOfDistinctAccesses = mySystem->m6502().distinctAccesses();
122 myWritePending = true;
123 }
124 // Is the bank configuration hotspot being accessed?
125 else if((addr & 0x1FFF) == 0x1FF8)
126 {
127 // Yes, so handle bank configuration
128 myWritePending = false;
129 bankConfiguration(myDataHoldRegister);
130 }
131 // Handle poke if writing enabled
132 else if(myWriteEnabled && myWritePending &&
133 (mySystem->m6502().distinctAccesses() == (myNumberOfDistinctAccesses + 5)))
134 {
135 if((addr & 0x0800) == 0)
136 {
137 myImage[(addr & 0x07FF) + myImageOffset[0]] = myDataHoldRegister;
138 mySystem->setDirtyPage(addr);
139 }
140 else if(myImageOffset[1] != (3 << 11)) // Can't poke to ROM :-)
141 {
142 myImage[(addr & 0x07FF) + myImageOffset[1]] = myDataHoldRegister;
143 mySystem->setDirtyPage(addr);
144 }
145 myWritePending = false;
146 }
147
148 return myImage[(addr & 0x07FF) + myImageOffset[(addr & 0x0800) ? 1 : 0]];
149}
150
151// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
152bool CartridgeAR::poke(uInt16 addr, uInt8)
153{
154 bool modified = false;
155
156 // Cancel any pending write if more than 5 distinct accesses have occurred
157 // TODO: Modify to handle when the distinct counter wraps around...
158 if(myWritePending &&
159 (mySystem->m6502().distinctAccesses() > myNumberOfDistinctAccesses + 5))
160 {
161 myWritePending = false;
162 }
163
164 // Is the data hold register being set?
165 if(!(addr & 0x0F00) && (!myWriteEnabled || !myWritePending))
166 {
167 myDataHoldRegister = uInt8(addr); // FIXME - check cast here
168 myNumberOfDistinctAccesses = mySystem->m6502().distinctAccesses();
169 myWritePending = true;
170 }
171 // Is the bank configuration hotspot being accessed?
172 else if((addr & 0x1FFF) == 0x1FF8)
173 {
174 // Yes, so handle bank configuration
175 myWritePending = false;
176 bankConfiguration(myDataHoldRegister);
177 }
178 // Handle poke if writing enabled
179 else if(myWriteEnabled && myWritePending &&
180 (mySystem->m6502().distinctAccesses() == (myNumberOfDistinctAccesses + 5)))
181 {
182 if((addr & 0x0800) == 0)
183 {
184 myImage[(addr & 0x07FF) + myImageOffset[0]] = myDataHoldRegister;
185 modified = true;
186 }
187 else if(myImageOffset[1] != (3 << 11)) // Can't poke to ROM :-)
188 {
189 myImage[(addr & 0x07FF) + myImageOffset[1]] = myDataHoldRegister;
190 modified = true;
191 }
192 myWritePending = false;
193 }
194
195 return modified;
196}
197
198// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
199uInt8 CartridgeAR::getAccessFlags(uInt16 address) const
200{
201 return myCodeAccessBase[(address & 0x07FF) +
202 myImageOffset[(address & 0x0800) ? 1 : 0]];
203}
204
205// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
206void CartridgeAR::setAccessFlags(uInt16 address, uInt8 flags)
207{
208 myCodeAccessBase[(address & 0x07FF) +
209 myImageOffset[(address & 0x0800) ? 1 : 0]] |= flags;
210}
211
212// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
213bool CartridgeAR::bankConfiguration(uInt8 configuration)
214{
215 // D7-D5 of this byte: Write Pulse Delay (n/a for emulator)
216 //
217 // D4-D0: RAM/ROM configuration:
218 // $F000-F7FF $F800-FFFF Address range that banks map into
219 // 000wp 2 ROM
220 // 001wp 0 ROM
221 // 010wp 2 0 as used in Commie Mutants and many others
222 // 011wp 0 2 as used in Suicide Mission
223 // 100wp 2 ROM
224 // 101wp 1 ROM
225 // 110wp 2 1 as used in Killer Satellites
226 // 111wp 1 2 as we use for 2k/4k ROM cloning
227 //
228 // w = Write Enable (1 = enabled; accesses to $F000-$F0FF cause writes
229 // to happen. 0 = disabled, and the cart acts like ROM.)
230 // p = ROM Power (0 = enabled, 1 = off.) Only power the ROM if you're
231 // wanting to access the ROM for multiloads. Otherwise set to 1.
232
233 myCurrentBank = configuration & 0x1F; // remember for the bank() method
234
235 // Handle ROM power configuration
236 myPower = !(configuration & 0x01);
237
238 myWriteEnabled = configuration & 0x02;
239
240 switch((configuration >> 2) & 0x07)
241 {
242 case 0:
243 {
244 myImageOffset[0] = 2 << 11;
245 myImageOffset[1] = 3 << 11;
246 break;
247 }
248
249 case 1:
250 {
251 myImageOffset[0] = 0 ;
252 myImageOffset[1] = 3 << 11;
253 break;
254 }
255
256 case 2:
257 {
258 myImageOffset[0] = 2 << 11;
259 myImageOffset[1] = 0 ;
260 break;
261 }
262
263 case 3:
264 {
265 myImageOffset[0] = 0 ;
266 myImageOffset[1] = 2 << 11;
267 break;
268 }
269
270 case 4:
271 {
272 myImageOffset[0] = 2 << 11;
273 myImageOffset[1] = 3 << 11;
274 break;
275 }
276
277 case 5:
278 {
279 myImageOffset[0] = 1 << 11;
280 myImageOffset[1] = 3 << 11;
281 break;
282 }
283
284 case 6:
285 {
286 myImageOffset[0] = 2 << 11;
287 myImageOffset[1] = 1 << 11;
288 break;
289 }
290
291 case 7:
292 {
293 myImageOffset[0] = 1 << 11;
294 myImageOffset[1] = 2 << 11;
295 break;
296 }
297 }
298 return myBankChanged = true;
299}
300
301// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
302void CartridgeAR::initializeROM()
303{
304 // Note that the following offsets depend on the 'scrom.asm' file
305 // in src/emucore/misc. If that file is ever recompiled (and its
306 // contents placed in the ourDummyROMCode array), the offsets will
307 // almost definitely change
308
309 // The scrom.asm code checks a value at offset 109 as follows:
310 // 0xFF -> do a complete jump over the SC BIOS progress bars code
311 // 0x00 -> show SC BIOS progress bars as normal
312 ourDummyROMCode[109] = mySettings.getBool("fastscbios") ? 0xFF : 0x00;
313
314 // The accumulator should contain a random value after exiting the
315 // SC BIOS code - a value placed in offset 281 will be stored in A
316 ourDummyROMCode[281] = mySystem->randGenerator().next();
317
318 // Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam
319 std::fill_n(myImage.begin() + (3<<11), 2_KB, 0x02);
320
321 // Copy the "dummy" Supercharger BIOS code into the ROM area
322 std::copy_n(ourDummyROMCode.data(), ourDummyROMCode.size(), myImage.data() + (3<<11));
323
324 // Finally set 6502 vectors to point to initial load code at 0xF80A of BIOS
325 myImage[(3<<11) + 2044] = 0x0A;
326 myImage[(3<<11) + 2045] = 0xF8;
327 myImage[(3<<11) + 2046] = 0x0A;
328 myImage[(3<<11) + 2047] = 0xF8;
329}
330
331// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
332uInt8 CartridgeAR::checksum(uInt8* s, uInt16 length)
333{
334 uInt8 sum = 0;
335
336 for(uInt32 i = 0; i < length; ++i)
337 sum += s[i];
338
339 return sum;
340}
341
342// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
343void CartridgeAR::loadIntoRAM(uInt8 load)
344{
345 uInt16 image;
346
347 // Scan through all of the loads to see if we find the one we're looking for
348 for(image = 0; image < myNumberOfLoadImages; ++image)
349 {
350 // Is this the correct load?
351 if(myLoadImages[(image * 8448) + myImage.size() + 5] == load)
352 {
353 // Copy the load's header
354 std::copy_n(myLoadImages.get() + (image * 8448) + myImage.size(), myHeader.size(), myHeader.data());
355
356 // Verify the load's header
357 if(checksum(myHeader.data(), 8) != 0x55)
358 cerr << "WARNING: The Supercharger header checksum is invalid...\n";
359
360 // Load all of the pages from the load
361 bool invalidPageChecksumSeen = false;
362 for(uInt32 j = 0; j < myHeader[3]; ++j)
363 {
364 uInt32 bank = myHeader[16 + j] & 0x03;
365 uInt32 page = (myHeader[16 + j] >> 2) & 0x07;
366 uInt8* src = myLoadImages.get() + (image * 8448) + (j * 256);
367 uInt8 sum = checksum(src, 256) + myHeader[16 + j] + myHeader[64 + j];
368
369 if(!invalidPageChecksumSeen && (sum != 0x55))
370 {
371 cerr << "WARNING: Some Supercharger page checksums are invalid...\n";
372 invalidPageChecksumSeen = true;
373 }
374
375 // Copy page to Supercharger RAM (don't allow a copy into ROM area)
376 if(bank < 3)
377 std::copy_n(src, 256, myImage.data() + (bank * 2048) + (page * 256));
378 }
379
380 // Copy the bank switching byte and starting address into the 2600's
381 // RAM for the "dummy" SC BIOS to access it
382 mySystem->poke(0xfe, myHeader[0]);
383 mySystem->poke(0xff, myHeader[1]);
384 mySystem->poke(0x80, myHeader[2]);
385
386 myBankChanged = true;
387 return;
388 }
389 }
390
391 // TODO: Should probably switch to an internal ROM routine to display
392 // this message to the user...
393 cerr << "ERROR: Supercharger load is missing from ROM image...\n";
394}
395
396// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
397bool CartridgeAR::bank(uInt16 bank)
398{
399 if(!bankLocked())
400 return bankConfiguration(uInt8(bank));
401 else
402 return false;
403}
404
405// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
406uInt16 CartridgeAR::getBank(uInt16) const
407{
408 return myCurrentBank;
409}
410
411// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
412uInt16 CartridgeAR::bankCount() const
413{
414 return 32;
415}
416
417// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
418bool CartridgeAR::patch(uInt16 address, uInt8 value)
419{
420 // TODO - add support for debugger
421 return false;
422}
423
424// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
425const uInt8* CartridgeAR::getImage(size_t& size) const
426{
427 size = mySize;
428 return myLoadImages.get();
429}
430
431// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
432bool CartridgeAR::save(Serializer& out) const
433{
434 try
435 {
436 // Indicates the offest within the image for the corresponding bank
437 out.putIntArray(myImageOffset.data(), myImageOffset.size());
438
439 // The 6K of RAM and 2K of ROM contained in the Supercharger
440 out.putByteArray(myImage.data(), myImage.size());
441
442 // The 256 byte header for the current 8448 byte load
443 out.putByteArray(myHeader.data(), myHeader.size());
444
445 // All of the 8448 byte loads associated with the game
446 // Note that the size of this array is myNumberOfLoadImages * 8448
447 out.putByteArray(myLoadImages.get(), myNumberOfLoadImages * 8448);
448
449 // Indicates how many 8448 loads there are
450 out.putByte(myNumberOfLoadImages);
451
452 // Indicates if the RAM is write enabled
453 out.putBool(myWriteEnabled);
454
455 // Indicates if the ROM's power is on or off
456 out.putBool(myPower);
457
458 // Data hold register used for writing
459 out.putByte(myDataHoldRegister);
460
461 // Indicates number of distinct accesses when data hold register was set
462 out.putInt(myNumberOfDistinctAccesses);
463
464 // Indicates if a write is pending or not
465 out.putBool(myWritePending);
466 }
467 catch(...)
468 {
469 cerr << "ERROR: CartridgeAR::save" << endl;
470 return false;
471 }
472
473 return true;
474}
475
476// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
477bool CartridgeAR::load(Serializer& in)
478{
479 try
480 {
481 // Indicates the offest within the image for the corresponding bank
482 in.getIntArray(myImageOffset.data(), myImageOffset.size());
483
484 // The 6K of RAM and 2K of ROM contained in the Supercharger
485 in.getByteArray(myImage.data(), myImage.size());
486
487 // The 256 byte header for the current 8448 byte load
488 in.getByteArray(myHeader.data(), myHeader.size());
489
490 // All of the 8448 byte loads associated with the game
491 // Note that the size of this array is myNumberOfLoadImages * 8448
492 in.getByteArray(myLoadImages.get(), myNumberOfLoadImages * 8448);
493
494 // Indicates how many 8448 loads there are
495 myNumberOfLoadImages = in.getByte();
496
497 // Indicates if the RAM is write enabled
498 myWriteEnabled = in.getBool();
499
500 // Indicates if the ROM's power is on or off
501 myPower = in.getBool();
502
503 // Data hold register used for writing
504 myDataHoldRegister = in.getByte();
505
506 // Indicates number of distinct accesses when data hold register was set
507 myNumberOfDistinctAccesses = in.getInt();
508
509 // Indicates if a write is pending or not
510 myWritePending = in.getBool();
511 }
512 catch(...)
513 {
514 cerr << "ERROR: CartridgeAR::load" << endl;
515 return false;
516 }
517
518 return true;
519}
520
521// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
522std::array<uInt8, 294> CartridgeAR::ourDummyROMCode = {
523 0xa5, 0xfa, 0x85, 0x80, 0x4c, 0x18, 0xf8, 0xff,
524 0xff, 0xff, 0x78, 0xd8, 0xa0, 0x00, 0xa2, 0x00,
525 0x94, 0x00, 0xe8, 0xd0, 0xfb, 0x4c, 0x50, 0xf8,
526 0xa2, 0x00, 0xbd, 0x06, 0xf0, 0xad, 0xf8, 0xff,
527 0xa2, 0x00, 0xad, 0x00, 0xf0, 0xea, 0xbd, 0x00,
528 0xf7, 0xca, 0xd0, 0xf6, 0x4c, 0x50, 0xf8, 0xff,
529 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
530 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
531 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
532 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
533 0xa2, 0x03, 0xbc, 0x22, 0xf9, 0x94, 0xfa, 0xca,
534 0x10, 0xf8, 0xa0, 0x00, 0xa2, 0x28, 0x94, 0x04,
535 0xca, 0x10, 0xfb, 0xa2, 0x1c, 0x94, 0x81, 0xca,
536 0x10, 0xfb, 0xa9, 0xff, 0xc9, 0x00, 0xd0, 0x03,
537 0x4c, 0x13, 0xf9, 0xa9, 0x00, 0x85, 0x1b, 0x85,
538 0x1c, 0x85, 0x1d, 0x85, 0x1e, 0x85, 0x1f, 0x85,
539 0x19, 0x85, 0x1a, 0x85, 0x08, 0x85, 0x01, 0xa9,
540 0x10, 0x85, 0x21, 0x85, 0x02, 0xa2, 0x07, 0xca,
541 0xca, 0xd0, 0xfd, 0xa9, 0x00, 0x85, 0x20, 0x85,
542 0x10, 0x85, 0x11, 0x85, 0x02, 0x85, 0x2a, 0xa9,
543 0x05, 0x85, 0x0a, 0xa9, 0xff, 0x85, 0x0d, 0x85,
544 0x0e, 0x85, 0x0f, 0x85, 0x84, 0x85, 0x85, 0xa9,
545 0xf0, 0x85, 0x83, 0xa9, 0x74, 0x85, 0x09, 0xa9,
546 0x0c, 0x85, 0x15, 0xa9, 0x1f, 0x85, 0x17, 0x85,
547 0x82, 0xa9, 0x07, 0x85, 0x19, 0xa2, 0x08, 0xa0,
548 0x00, 0x85, 0x02, 0x88, 0xd0, 0xfb, 0x85, 0x02,
549 0x85, 0x02, 0xa9, 0x02, 0x85, 0x02, 0x85, 0x00,
550 0x85, 0x02, 0x85, 0x02, 0x85, 0x02, 0xa9, 0x00,
551 0x85, 0x00, 0xca, 0x10, 0xe4, 0x06, 0x83, 0x66,
552 0x84, 0x26, 0x85, 0xa5, 0x83, 0x85, 0x0d, 0xa5,
553 0x84, 0x85, 0x0e, 0xa5, 0x85, 0x85, 0x0f, 0xa6,
554 0x82, 0xca, 0x86, 0x82, 0x86, 0x17, 0xe0, 0x0a,
555 0xd0, 0xc3, 0xa9, 0x02, 0x85, 0x01, 0xa2, 0x1c,
556 0xa0, 0x00, 0x84, 0x19, 0x84, 0x09, 0x94, 0x81,
557 0xca, 0x10, 0xfb, 0xa6, 0x80, 0xdd, 0x00, 0xf0,
558 0xa9, 0x9a, 0xa2, 0xff, 0xa0, 0x00, 0x9a, 0x4c,
559 0xfa, 0x00, 0xcd, 0xf8, 0xff, 0x4c
560};
561
562// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
563const std::array<uInt8, 256> CartridgeAR::ourDefaultHeader = {
564 0xac, 0xfa, 0x0f, 0x18, 0x62, 0x00, 0x24, 0x02,
565 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
566 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
567 0x01, 0x05, 0x09, 0x0d, 0x11, 0x15, 0x19, 0x1d,
568 0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16, 0x1a, 0x1e,
569 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
570 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
571 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
575 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
576 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
577 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
578 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
579 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
580 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
581 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
582 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
583 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
584 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
585 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
586 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
587 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
588 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
589 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
590 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
591 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
592 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
593 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
594 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
595 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
596};
597