?login_element?

Subversion Repositories NedoOS

Rev

Rev 129 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download

  1. /*
  2.  
  3.   SjASMPlus Z80 Cross Compiler
  4.  
  5.   Copyright (c) 2004-2006 Aprisobal
  6.  
  7.   This software is provided 'as-is', without any express or implied warranty.
  8.   In no event will the authors be held liable for any damages arising from the
  9.   use of this software.
  10.  
  11.   Permission is granted to anyone to use this software for any purpose,
  12.   including commercial applications, and to alter it and redistribute it freely,
  13.   subject to the following restrictions:
  14.  
  15.   1. The origin of this software must not be misrepresented; you must not claim
  16.          that you wrote the original software. If you use this software in a product,
  17.          an acknowledgment in the product documentation would be appreciated but is
  18.          not required.
  19.  
  20.   2. Altered source versions must be plainly marked as such, and must not be
  21.          misrepresented as being the original software.
  22.  
  23.   3. This notice may not be removed or altered from any source distribution.
  24.  
  25. */
  26.  
  27. // devices.cpp
  28.  
  29. #include "sjdefs.h"
  30.  
  31. bool IsZXSpectrumDevice(char *name) {
  32.         if (strcmp(name, "ZXSPECTRUM48") &&
  33.                 strcmp(name, "ZXSPECTRUM128") &&
  34.                 strcmp(name, "ZXSPECTRUM256") &&
  35.                 strcmp(name, "ZXSPECTRUM512") &&
  36.                 strcmp(name, "ZXSPECTRUM1024") &&
  37.                 strcmp(name, "ZXSPECTRUM2048") &&
  38.                 strcmp(name, "ZXSPECTRUM4096") &&
  39.                 strcmp(name, "ZXSPECTRUM8192"))
  40.         {
  41.                 return false;
  42.         }
  43.         return true;
  44. }
  45.  
  46. static void initRegularSlotDevice(CDevice* const device, const int32_t slotSize, const int32_t slotCount,
  47.                                                                   const int pageCount, const int* const initialPages) {
  48.         for (int32_t slotAddress = 0; slotAddress < slotSize * slotCount; slotAddress += slotSize) {
  49.                 device->AddSlot(slotAddress, slotSize);
  50.         }
  51.         device->Memory = new byte[slotSize * pageCount]();
  52.         for (byte* memPtr = device->Memory; memPtr < device->Memory + slotSize * pageCount; memPtr += slotSize) {
  53.                 device->AddPage(memPtr, slotSize);
  54.         }
  55.         for (int i = 0; i < device->SlotsCount; ++i) {
  56.                 CDeviceSlot* slot = device->GetSlot(i);
  57.                 slot->Page = device->GetPage(initialPages[i]);
  58.                 slot->InitialPage = slot->Page->Number;
  59.         }
  60.         device->SetSlot(device->SlotsCount - 1);
  61. }
  62.  
  63. static void initZxLikeDevice(
  64.         CDevice* const device, int32_t slotSize, int pageCount, const int* const initialPages, aint ramtop)
  65. {
  66.         initRegularSlotDevice(device, slotSize, 0x10000/slotSize, pageCount, initialPages);
  67.         device->ZxRamTop = (0x5D00 <= ramtop && ramtop <= 0xFFFF) ? ramtop : ZX_RAMTOP_DEFAULT;
  68.  
  69.         // set memory to state like if (for snapshot saving):
  70.                 // CLEAR ZxRamTop (0x5D5B default) : LOAD "bin" CODE : ... USR start_adr
  71.         aint adr;
  72.         // ULA attributes: INK 0 : PAPER 7 : FLASH 0 : BRIGTH 0
  73.         for (adr = 0x5800; adr < 0x5B00; ++adr) device->Poke(adr, 7*8);
  74.  
  75.         // set UDG data at ZX_UDG_ADR (0xFF58)
  76.         adr = ZX_UDG_ADR;
  77.         for (byte value : ZX_UDG_DATA) device->Poke(adr++, value);
  78.  
  79.         // ZX SYSVARS at 0x5C00
  80.         adr = ZX_SYSVARS_ADR;
  81.         for (byte value : ZX_SYSVARS_DATA) device->Poke(adr++, value);
  82.         // set RAMTOP sysvar
  83.         device->Poke(ZX_SYSVARS_ADR+0xB2, device->ZxRamTop & 0xFF);
  84.         device->Poke(ZX_SYSVARS_ADR+0xB3, (device->ZxRamTop>>8) & 0xFF);
  85.  
  86.         // set STACK data (without the "start" address)
  87.         adr = device->ZxRamTop + 1 - sizeof(ZX_STACK_DATA);
  88.         // set ERRSP sysvar to beginning of the fake stack
  89.         device->Poke(ZX_SYSVARS_ADR+0x3D, adr & 0xFF);
  90.         device->Poke(ZX_SYSVARS_ADR+0x3E, (adr>>8) & 0xFF);
  91.         for (byte value : ZX_STACK_DATA) device->Poke(adr++, value);
  92. }
  93.  
  94. static void DeviceZXSpectrum48(CDevice **dev, CDevice *parent, aint ramtop) {
  95.         *dev = new CDevice("ZXSPECTRUM48", parent);
  96.         const int initialPages[] = {0, 1, 2, 3};
  97.         initZxLikeDevice(*dev, 0x4000, 4, initialPages, ramtop);
  98. }
  99.  
  100. const static int initialPagesZx128[] = {7, 5, 2, 0};
  101.  
  102. static void DeviceZXSpectrum128(CDevice **dev, CDevice *parent, aint ramtop) {
  103.         *dev = new CDevice("ZXSPECTRUM128", parent);
  104.         initZxLikeDevice(*dev, 0x4000, 8, initialPagesZx128, ramtop);
  105. }
  106.  
  107. static void DeviceZXSpectrum256(CDevice **dev, CDevice *parent, aint ramtop) {
  108.         *dev = new CDevice("ZXSPECTRUM256", parent);
  109.         initZxLikeDevice(*dev, 0x4000, 16, initialPagesZx128, ramtop);
  110. }
  111.  
  112. static void DeviceZXSpectrum512(CDevice **dev, CDevice *parent, aint ramtop) {
  113.         *dev = new CDevice("ZXSPECTRUM512", parent);
  114.         initZxLikeDevice(*dev, 0x4000, 32, initialPagesZx128, ramtop);
  115. }
  116.  
  117. static void DeviceZXSpectrum1024(CDevice **dev, CDevice *parent, aint ramtop) {
  118.         *dev = new CDevice("ZXSPECTRUM1024", parent);
  119.         initZxLikeDevice(*dev, 0x4000, 64, initialPagesZx128, ramtop);
  120. }
  121.  
  122. static void DeviceZXSpectrum2048(CDevice **dev, CDevice *parent, aint ramtop) {
  123.         *dev = new CDevice("ZXSPECTRUM2048", parent);
  124.         initZxLikeDevice(*dev, 0x4000, 128, initialPagesZx128, ramtop);
  125. }
  126.  
  127. static void DeviceZXSpectrum4096(CDevice **dev, CDevice *parent, aint ramtop) {
  128.         *dev = new CDevice("ZXSPECTRUM4096", parent);
  129.         initZxLikeDevice(*dev, 0x4000, 256, initialPagesZx128, ramtop);
  130. }
  131.  
  132. static void DeviceZXSpectrum8192(CDevice **dev, CDevice *parent, aint ramtop) {
  133.         *dev = new CDevice("ZXSPECTRUM8192", parent);
  134.         initZxLikeDevice(*dev, 0x4000, 512, initialPagesZx128, ramtop);
  135. }
  136.  
  137. static void DeviceZxSpectrumNext(CDevice **dev, CDevice *parent, aint ramtop) {
  138.         if (ramtop) Warning("ZXN device doesn't init memory in any way (RAMTOP is ignored)");
  139.         if (Options::IsI8080) Error("Can't use ZXN device while in i8080 assembling mode.", line, FATAL);
  140.         if (Options::IsLR35902) Error("Can't use ZXN device while in Sharp LR35902 assembling mode.", line, FATAL);
  141.         *dev = new CDevice("ZXSPECTRUMNEXT", parent);
  142.         const int initialPages[] = {14, 15, 10, 11, 4, 5, 0, 1};        // basically same as ZX128, but 8k
  143.         initRegularSlotDevice(*dev, 0x2000, 8, 224, initialPages);
  144.         // auto-enable ZX Next instruction extensions
  145.         if (0 == Options::syx.IsNextEnabled) {
  146.                 Options::syx.IsNextEnabled = 1;
  147.                 Z80::InitNextExtensions();              // add the special opcodes here (they were not added)
  148.                                 // this is a bit late, but it should work as well as `--zxnext` option I believe
  149.         }
  150. }
  151.  
  152. int SetDevice(char *id, const aint ramtop) {
  153.         CDevice** dev;
  154.         CDevice* parent = nullptr;
  155.  
  156.         if (!id || cmphstr(id, "none")) {
  157.                 DeviceID = 0; return true;
  158.         }
  159.  
  160.         if (!DeviceID || strcmp(DeviceID, id)) {        // different device than current, change to it
  161.                 DeviceID = 0;
  162.                 dev = &Devices;
  163.                 // search for device
  164.                 while (*dev) {
  165.                         parent = *dev;
  166.                         if (!strcmp(parent->ID, id)) break;
  167.                         dev = &(parent->Next);
  168.                 }
  169.                 if (nullptr == (*dev)) {        // device not found
  170.                         if (cmphstr(id, "zxspectrum48")) {                      // must be lowercase to catch both cases
  171.                                 DeviceZXSpectrum48(dev, parent, ramtop);
  172.                         } else if (cmphstr(id, "zxspectrum128")) {
  173.                                 DeviceZXSpectrum128(dev, parent, ramtop);
  174.                         } else if (cmphstr(id, "zxspectrum256")) {
  175.                                 DeviceZXSpectrum256(dev, parent, ramtop);
  176.                         } else if (cmphstr(id, "zxspectrum512")) {
  177.                                 DeviceZXSpectrum512(dev, parent, ramtop);
  178.                         } else if (cmphstr(id, "zxspectrum1024")) {
  179.                                 DeviceZXSpectrum1024(dev, parent, ramtop);
  180.                         } else if (cmphstr(id, "zxspectrum2048")) {
  181.                                 DeviceZXSpectrum2048(dev, parent, ramtop);
  182.                         } else if (cmphstr(id, "zxspectrum4096")) {
  183.                                 DeviceZXSpectrum4096(dev, parent, ramtop);
  184.                         } else if (cmphstr(id, "zxspectrum8192")) {
  185.                                 DeviceZXSpectrum8192(dev, parent, ramtop);
  186.                         } else if (cmphstr(id, "zxspectrumnext")) {
  187.                                 DeviceZxSpectrumNext(dev, parent, ramtop);
  188.                         } else {
  189.                                 return false;
  190.                         }
  191.                 }
  192.                 // set up the found/new device
  193.                 Device = (*dev);
  194.                 DeviceID = Device->ID;
  195.                 Device->CheckPage(CDevice::CHECK_RESET);
  196.         }
  197.         if (ramtop && Device->ZxRamTop && ramtop != Device->ZxRamTop) {
  198.                 Warning("[DEVICE] this device was already opened with different RAMTOP value");
  199.         }
  200.         return true;
  201. }
  202.  
  203. char* GetDeviceName() {
  204.         if (!DeviceID) {
  205.                 return (char *)"NONE";
  206.         } else {
  207.                 return DeviceID;
  208.         }
  209. }
  210.  
  211. CDevice::CDevice(const char *name, CDevice *parent)
  212.         : Next(NULL), SlotsCount(0), PagesCount(0), Memory(nullptr), ZxRamTop(0), CurrentSlot(0) {
  213.         ID = STRDUP(name);
  214.         if (parent) parent->Next = this;
  215.         for (auto & slot : Slots) slot = NULL;
  216.         for (auto & page : Pages) page = NULL;
  217. }
  218.  
  219. CDevice::~CDevice() {
  220.         for (auto & slot : Slots) if (slot) delete slot;
  221.         for (auto & page : Pages) if (page) delete page;
  222.         if (Memory) delete[] Memory;
  223.         if (Next) delete Next;
  224.         free(ID);
  225. }
  226.  
  227. void CDevice::AddSlot(int32_t adr, int32_t size) {
  228.         if (MAX_SLOT_N == SlotsCount) ErrorInt("Can't add more slots, already at max", MAX_SLOT_N, FATAL);
  229.         Slots[SlotsCount++] = new CDeviceSlot(adr, size);
  230. }
  231.  
  232. void CDevice::AddPage(byte* memory, int32_t size) {
  233.         if (MAX_PAGE_N == PagesCount) ErrorInt("Can't add more pages, already at max", MAX_PAGE_N, FATAL);
  234.         Pages[PagesCount] = new CDevicePage(memory, size, PagesCount);
  235.         PagesCount++;
  236. }
  237.  
  238. CDeviceSlot* CDevice::GetSlot(int num) {
  239.         if (Slots[num]) return Slots[num];
  240.         Error("Wrong slot number", lp);
  241.         return Slots[0];
  242. }
  243.  
  244. CDevicePage* CDevice::GetPage(int num) {
  245.         if (Pages[num]) return Pages[num];
  246.         Error("Wrong page number", lp);
  247.         return Pages[0];
  248. }
  249.  
  250. // returns slot belonging to the Z80-address (16bit)
  251. int CDevice::GetSlotOfA16(int32_t address) {
  252.         for (int i=SlotsCount; i--; ) {
  253.                 CDeviceSlot* const S = Slots[i];
  254.                 if (address < S->Address) continue;
  255.                 if (S->Address + S->Size <= address) return -1;         // outside of slot
  256.                 return i;
  257.         }
  258.         return -1;
  259. }
  260.  
  261. // returns currently mapped page for the Z80-address (16bit)
  262. int CDevice::GetPageOfA16(int32_t address) {
  263.         int slotNum = GetSlotOfA16(address);
  264.         if (-1 == slotNum) return -1;
  265.         if (nullptr == Slots[slotNum]->Page) return -1;
  266.         return Slots[slotNum]->Page->Number;
  267. }
  268.  
  269. void CDevice::CheckPage(const ECheckPageLevel level) {
  270.         // fake DISP address gets auto-wrapped FFFF->0 (with warning only)
  271.         // only with "emit" mode, labels may get the value 0x10000 before the address gets truncated
  272.         if (PseudoORG && CHECK_NO_EMIT != level && 0x10000 <= CurAddress) {
  273.                 if (LASTPASS == pass) {
  274.                         char buf[64];
  275.                         SPRINTF1(buf, 64, "RAM limit exceeded 0x%X by DISP", (unsigned int)CurAddress);
  276.                         Warning(buf);
  277.                 }
  278.                 CurAddress &= 0xFFFF;
  279.         }
  280.         // check the emit address for bytecode
  281.         const int realAddr = PseudoORG ? adrdisp : CurAddress;
  282.         // quicker check to avoid scanning whole slots array every byte
  283.         if (CHECK_RESET != level
  284.                 && Slots[previousSlotI]->Address <= realAddr
  285.                 && realAddr < Slots[previousSlotI]->Address + Slots[previousSlotI]->Size) return;
  286.         for (int i=SlotsCount; i--; ) {
  287.                 CDeviceSlot* const S = Slots[i];
  288.                 if (realAddr < S->Address) continue;
  289.                 Page = S->Page;
  290.                 MemoryPointer = Page->RAM + (realAddr - S->Address);
  291.                 if (CHECK_RESET == level) {
  292.                         previousSlotOpt = S->Option;
  293.                         previousSlotI = i;
  294.                         limitExceeded = false;
  295.                         return;
  296.                 }
  297.                 // if still in the same slot and within boundaries, we are done
  298.                 if (i == previousSlotI && realAddr < S->Address + S->Size) return;
  299.                 // crossing into other slot, check options for special functionality of old slot
  300.                 if (S->Address + S->Size <= realAddr) MemoryPointer = NULL; // you're not writing there
  301.                 switch (previousSlotOpt) {
  302.                         case CDeviceSlot::O_ERROR:
  303.                                 if (LASTPASS == pass && CHECK_EMIT == level && !limitExceeded) {
  304.                                         ErrorInt("Write outside of memory slot", realAddr, SUPPRESS);
  305.                                         limitExceeded = true;
  306.                                 }
  307.                                 break;
  308.                         case CDeviceSlot::O_WARNING:
  309.                                 if (LASTPASS == pass && CHECK_EMIT == level && !limitExceeded) {
  310.                                         Warning("Write outside of memory slot");
  311.                                         limitExceeded = true;
  312.                                 }
  313.                                 break;
  314.                         case CDeviceSlot::O_NEXT:
  315.                         {
  316.                                 CDeviceSlot* const prevS = Slots[previousSlotI];
  317.                                 const int nextPageN = prevS->Page->Number + 1;
  318.                                 if (PagesCount <= nextPageN) {
  319.                                         ErrorInt("No more memory pages to map next one into slot", previousSlotI, SUPPRESS);
  320.                                         // disable the option on the overflowing slot
  321.                                         prevS->Option = CDeviceSlot::O_NONE;
  322.                                         break;          // continue into next slot, don't wrap any more
  323.                                 }
  324.                                 if (realAddr != (prevS->Address + prevS->Size)) {       // should be equal
  325.                                         ErrorInt("Write beyond memory slot in wrap-around slot catched too late by",
  326.                                                                 realAddr - prevS->Address - prevS->Size, FATAL);
  327.                                         break;
  328.                                 }
  329.                                 prevS->Page = Pages[nextPageN];         // map next page into the guarded slot
  330.                                 Page = prevS->Page;
  331.                                 if (PseudoORG) adrdisp -= prevS->Size;
  332.                                 else CurAddress -= prevS->Size;
  333.                                 MemoryPointer = Page->RAM;
  334.                                 return;         // preserve current option status
  335.                         }
  336.                         default:
  337.                                 if (LASTPASS == pass && CHECK_EMIT == level && !limitExceeded && !MemoryPointer) {
  338.                                         ErrorInt("Write outside of device memory at", realAddr, SUPPRESS);
  339.                                         limitExceeded = true;
  340.                                 }
  341.                                 break;
  342.                 }
  343.                 // refresh check slot settings
  344.                 limitExceeded &= (previousSlotI == i);  // reset limit flag if slot changed (in non check_reset mode)
  345.                 previousSlotI = i;
  346.                 previousSlotOpt = S->Option;
  347.                 return;
  348.         }
  349.         Error("CheckPage(..): please, contact the author of this program.", NULL, FATAL);
  350. }
  351.  
  352. bool CDevice::SetSlot(int slotNumber) {
  353.         if (slotNumber < 0 || SlotsCount <= slotNumber || NULL == Slots[slotNumber]) return false;
  354.         CurrentSlot = slotNumber;
  355.         return true;
  356. }
  357.  
  358. CDeviceSlot* CDevice::GetCurrentSlot() {
  359.         return GetSlot(CurrentSlot);
  360. }
  361.  
  362. // Calling this with (PagesCount, 0) will return total memory size
  363. int32_t CDevice::GetMemoryOffset(int page, int32_t offset) const {
  364.         if (!Pages[0]) return 0;
  365.         return offset + page * Pages[0]->Size;
  366. }
  367.  
  368. void CDevice::Poke(aint z80adr, byte value) {
  369.         // write byte into device memory with current page-mapping
  370.         const int adrPage = GetPageOfA16(z80adr);
  371.         if (-1 == adrPage) return;              // silently ignore invalid address
  372.         CDevicePage* page = GetPage(adrPage);
  373.         page->RAM[z80adr & (page->Size-1)] = value;
  374. }
  375.  
  376. CDevicePage::CDevicePage(byte* memory, int32_t size, int number)
  377.         : Size(size), Number(number), RAM(memory) {
  378.         if (nullptr == RAM) Error("No memory defined", nullptr, FATAL);
  379. }
  380.  
  381. CDeviceSlot::CDeviceSlot(int32_t adr, int32_t size)
  382.         : Address(adr), Size(size), Page(NULL), InitialPage(-1), Option(O_NONE) {
  383. }
  384.  
  385. CDeviceSlot::~CDeviceSlot() {
  386. }
  387.  
  388. const unsigned char ZX_SYSVARS_DATA[] = {
  389.         0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
  390.         0x01, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x01, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00,
  391.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  392.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x40, 0x00, 0xff, 0xcc, 0x01, 0x54, 0xff, 0x00,
  393.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xcb, 0x5c, 0x00, 0x00, 0xb6,
  394.         0x5c, 0xb6, 0x5c, 0xcb, 0x5c, 0x00, 0x00, 0xca, 0x5c, 0xcc, 0x5c, 0xcc, 0x5c, 0xcc, 0x5c, 0x00,
  395.         0x00, 0xce, 0x5c, 0xce, 0x5c, 0xce, 0x5c, 0x00, 0x92, 0x5c, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,
  396.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xff, 0x00, 0x00, 0x21,
  397.         0x5b, 0x00, 0x21, 0x17, 0x00, 0x40, 0xe0, 0x50, 0x21, 0x18, 0x21, 0x17, 0x01, 0x38, 0x00, 0x38,
  398.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  399.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  400.         0x00, 0x00, 0x57, 0xff, 0xff, 0xff, 0xf4, 0x09, 0xa8, 0x10, 0x4b, 0xf4, 0x09, 0xc4, 0x15, 0x53,
  401.         0x81, 0x0f, 0xc4, 0x15, 0x52, 0xf4, 0x09, 0xc4, 0x15, 0x50, 0x80, 0x80, 0x0d, 0x80, 0x00, 0x00,
  402.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  403.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  404.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  405. };
  406.  
  407. const unsigned char ZX_STACK_DATA[] = {
  408.         0x03, 0x13, 0x00, 0x3e
  409. };
  410.  
  411. const unsigned char ZX_UDG_DATA[168] = {
  412.         0x00, 0x3c, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x00, 0x00, 0x7c, 0x42, 0x7c, 0x42, 0x42, 0x7c, 0x00,
  413.         0x00, 0x3c, 0x42, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x44, 0x78, 0x00,
  414.         0x00, 0x7e, 0x40, 0x7c, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x7e, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x00,
  415.         0x00, 0x3c, 0x42, 0x40, 0x4e, 0x42, 0x3c, 0x00, 0x00, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x00,
  416.         0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00,
  417.         0x00, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00,
  418.         0x00, 0x42, 0x66, 0x5a, 0x42, 0x42, 0x42, 0x00, 0x00, 0x42, 0x62, 0x52, 0x4a, 0x46, 0x42, 0x00,
  419.         0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x00,
  420.         0x00, 0x3c, 0x42, 0x42, 0x52, 0x4a, 0x3c, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x7c, 0x44, 0x42, 0x00,
  421.         0x00, 0x3c, 0x40, 0x3c, 0x02, 0x42, 0x3c, 0x00, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00,
  422.         0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00
  423. };
  424.