?login_element?

Subversion Repositories NedoOS

Rev

Rev 539 | 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(const char *name) {
  32.         if (nullptr == name) return false;
  33.         if (strcmp(name, "ZXSPECTRUM48") &&
  34.                 strcmp(name, "ZXSPECTRUM128") &&
  35.                 strcmp(name, "ZXSPECTRUM256") &&
  36.                 strcmp(name, "ZXSPECTRUM512") &&
  37.                 strcmp(name, "ZXSPECTRUM1024") &&
  38.                 strcmp(name, "ZXSPECTRUM2048") &&
  39.                 strcmp(name, "ZXSPECTRUM4096") &&
  40.                 strcmp(name, "ZXSPECTRUM8192"))
  41.         {
  42.                 return false;
  43.         }
  44.         return true;
  45. }
  46.  
  47. bool IsAmstradCPCDevice(const char* name) {
  48.         if (nullptr == name) return false;
  49.         if (strcmp(name, "AMSTRADCPC464") &&
  50.                 strcmp(name, "AMSTRADCPC6128"))
  51.         {
  52.                 return false;
  53.         }
  54.         return true;
  55. }
  56.  
  57. static void initRegularSlotDevice(CDevice* const device, const int32_t slotSize, const int32_t slotCount,
  58.                                                                   const int pageCount, const int* const initialPages) {
  59.         for (int32_t slotAddress = 0; slotAddress < slotSize * slotCount; slotAddress += slotSize) {
  60.                 device->AddSlot(slotAddress, slotSize);
  61.         }
  62.         device->Memory = new byte[slotSize * pageCount]();
  63.         for (byte* memPtr = device->Memory; memPtr < device->Memory + slotSize * pageCount; memPtr += slotSize) {
  64.                 device->AddPage(memPtr, slotSize);
  65.         }
  66.         for (int i = 0; i < device->SlotsCount; ++i) {
  67.                 CDeviceSlot* slot = device->GetSlot(i);
  68.                 slot->Page = device->GetPage(initialPages[i]);
  69.                 slot->InitialPage = slot->Page->Number;
  70.         }
  71.         device->SetSlot(device->SlotsCount - 1);
  72. }
  73.  
  74. static void initZxLikeDevice(
  75.         CDevice* const device, int32_t slotSize, int pageCount, const int* const initialPages, aint ramtop)
  76. {
  77.         initRegularSlotDevice(device, slotSize, 0x10000/slotSize, pageCount, initialPages);
  78.         device->ZxRamTop = (0x5D00 <= ramtop && ramtop <= 0xFFFF) ? ramtop : ZX_RAMTOP_DEFAULT;
  79.  
  80.         // set memory to state like if (for snapshot saving):
  81.                 // CLEAR ZxRamTop (0x5D5B default) : LOAD "bin" CODE : ... USR start_adr
  82.         aint adr;
  83.         // ULA attributes: INK 0 : PAPER 7 : FLASH 0 : BRIGTH 0
  84.         for (adr = 0x5800; adr < 0x5B00; ++adr) device->Poke(adr, 7*8);
  85.  
  86.         // set UDG data at ZX_UDG_ADR (0xFF58)
  87.         adr = ZX_UDG_ADR;
  88.         for (byte value : ZX_UDG_DATA) device->Poke(adr++, value);
  89.  
  90.         // ZX SYSVARS at 0x5C00
  91.         adr = ZX_SYSVARS_ADR;
  92.         for (byte value : ZX_SYSVARS_DATA) device->Poke(adr++, value);
  93.         // set RAMTOP sysvar
  94.         device->Poke(ZX_SYSVARS_ADR+0xB2, device->ZxRamTop & 0xFF);
  95.         device->Poke(ZX_SYSVARS_ADR+0xB3, (device->ZxRamTop>>8) & 0xFF);
  96.  
  97.         // set STACK data (without the "start" address)
  98.         adr = device->ZxRamTop + 1 - sizeof(ZX_STACK_DATA);
  99.         // set ERRSP sysvar to beginning of the fake stack
  100.         device->Poke(ZX_SYSVARS_ADR+0x3D, adr & 0xFF);
  101.         device->Poke(ZX_SYSVARS_ADR+0x3E, (adr>>8) & 0xFF);
  102.         for (byte value : ZX_STACK_DATA) device->Poke(adr++, value);
  103. }
  104.  
  105. static void DeviceZXSpectrum48(CDevice **dev, CDevice *parent, aint ramtop) {
  106.         *dev = new CDevice("ZXSPECTRUM48", parent);
  107.         const int initialPages[] = {0, 1, 2, 3};
  108.         initZxLikeDevice(*dev, 0x4000, 4, initialPages, ramtop);
  109. }
  110.  
  111. const static int initialPagesZx128[] = {7, 5, 2, 0};
  112.  
  113. static void DeviceZXSpectrum128(CDevice **dev, CDevice *parent, aint ramtop) {
  114.         *dev = new CDevice("ZXSPECTRUM128", parent);
  115.         initZxLikeDevice(*dev, 0x4000, 8, initialPagesZx128, ramtop);
  116. }
  117.  
  118. static void DeviceZXSpectrum256(CDevice **dev, CDevice *parent, aint ramtop) {
  119.         *dev = new CDevice("ZXSPECTRUM256", parent);
  120.         initZxLikeDevice(*dev, 0x4000, 16, initialPagesZx128, ramtop);
  121. }
  122.  
  123. static void DeviceZXSpectrum512(CDevice **dev, CDevice *parent, aint ramtop) {
  124.         *dev = new CDevice("ZXSPECTRUM512", parent);
  125.         initZxLikeDevice(*dev, 0x4000, 32, initialPagesZx128, ramtop);
  126. }
  127.  
  128. static void DeviceZXSpectrum1024(CDevice **dev, CDevice *parent, aint ramtop) {
  129.         *dev = new CDevice("ZXSPECTRUM1024", parent);
  130.         initZxLikeDevice(*dev, 0x4000, 64, initialPagesZx128, ramtop);
  131. }
  132.  
  133. static void DeviceZXSpectrum2048(CDevice **dev, CDevice *parent, aint ramtop) {
  134.         *dev = new CDevice("ZXSPECTRUM2048", parent);
  135.         initZxLikeDevice(*dev, 0x4000, 128, initialPagesZx128, ramtop);
  136. }
  137.  
  138. static void DeviceZXSpectrum4096(CDevice **dev, CDevice *parent, aint ramtop) {
  139.         *dev = new CDevice("ZXSPECTRUM4096", parent);
  140.         initZxLikeDevice(*dev, 0x4000, 256, initialPagesZx128, ramtop);
  141. }
  142.  
  143. static void DeviceZXSpectrum8192(CDevice **dev, CDevice *parent, aint ramtop) {
  144.         *dev = new CDevice("ZXSPECTRUM8192", parent);
  145.         initZxLikeDevice(*dev, 0x4000, 512, initialPagesZx128, ramtop);
  146. }
  147.  
  148. static void DeviceZxSpectrumNext(CDevice **dev, CDevice *parent, aint ramtop) {
  149.         if (ramtop) WarningById(W_NO_RAMTOP);
  150.         if (Options::IsI8080) Error("Can't use ZXN device while in i8080 assembling mode", line, FATAL);
  151.         if (Options::IsLR35902) Error("Can't use ZXN device while in Sharp LR35902 assembling mode", line, FATAL);
  152.         *dev = new CDevice("ZXSPECTRUMNEXT", parent);
  153.         const int initialPages[] = {14, 15, 10, 11, 4, 5, 0, 1};        // basically same as ZX128, but 8k
  154.         initRegularSlotDevice(*dev, 0x2000, 8, 224, initialPages);
  155.         // auto-enable ZX Next instruction extensions
  156.         if (0 == Options::syx.IsNextEnabled) {
  157.                 Options::syx.IsNextEnabled = 1;
  158.                 Z80::InitNextExtensions();              // add the special opcodes here (they were not added)
  159.                                 // this is a bit late, but it should work as well as `--zxnext` option I believe
  160.         }
  161. }
  162.  
  163. static void DeviceNoSlot64k(CDevice **dev, CDevice *parent, aint ramtop) {
  164.         if (ramtop) WarningById(W_NO_RAMTOP);
  165.         *dev = new CDevice("NOSLOT64K", parent);
  166.         const int initialPages[] = { 0 };
  167.         initRegularSlotDevice(*dev, 0x10000, 1, 32, initialPages);      // 32*64kiB = 2MiB
  168. }
  169.  
  170. static void DeviceAmstradCPC464(CDevice** dev, CDevice* parent, aint ramtop) {
  171.         if (ramtop) WarningById(W_NO_RAMTOP);
  172.         *dev = new CDevice("AMSTRADCPC464", parent);
  173.         const int initialPages[] = { 0, 1, 2, 3 };
  174.         initRegularSlotDevice(*dev, 0x4000, 4, 4, initialPages);
  175. }
  176.  
  177. static void DeviceAmstradCPC6128(CDevice** dev, CDevice* parent, aint ramtop) {
  178.         if (ramtop) WarningById(W_NO_RAMTOP);
  179.         *dev = new CDevice("AMSTRADCPC6128", parent);
  180.         const int initialPages[] = { 0, 1, 2, 3 };
  181.         initRegularSlotDevice(*dev, 0x4000, 4, 8, initialPages);
  182. }
  183.  
  184. static bool SetUserDefinedDevice(const char* id, CDevice** dev, CDevice* parent, aint ramtop) {
  185.         auto findIt = std::find_if(
  186.                 DefDevices.begin(), DefDevices.end(),
  187.                 [&](const CDeviceDef* el) { return 0 == strcasecmp(id, el->getID()); }
  188.         );
  189.         if (DefDevices.end() == findIt) return false;   // not found
  190.         const CDeviceDef & def = **findIt;
  191.         if (ramtop) WarningById(W_NO_RAMTOP);
  192.         *dev = new CDevice(def.getID(), parent);
  193.         initRegularSlotDevice(*dev, def.SlotSize, def.SlotsCount, def.PagesCount, def.initialPages);
  194.         return true;
  195. }
  196.  
  197. bool SetDevice(const char *const_id, const aint ramtop) {
  198.         CDevice** dev;
  199.         CDevice* parent = nullptr;
  200.         char* id = const_cast<char*>(const_id);         //TODO cmphstr for both const/nonconst variants?
  201.                 // ^ argument is const because of lua bindings
  202.  
  203.         if (!id || cmphstr(id, "none")) {
  204.                 DeviceID = nullptr;
  205.                 Device = nullptr;
  206.                 return true;
  207.         }
  208.  
  209.         if (!DeviceID || strcmp(DeviceID, id)) {        // different device than current, change to it
  210.                 DeviceID = nullptr;
  211.                 dev = &Devices;
  212.                 // search for device
  213.                 while (*dev) {
  214.                         parent = *dev;
  215.                         if (!strcmp(parent->ID, id)) break;
  216.                         dev = &(parent->Next);
  217.                 }
  218.                 if (nullptr == (*dev)) {        // device not found
  219.                         if (cmphstr(id, "zxspectrum48")) {                      // must be lowercase to catch both cases
  220.                                 DeviceZXSpectrum48(dev, parent, ramtop);
  221.                         } else if (cmphstr(id, "zxspectrum128")) {
  222.                                 DeviceZXSpectrum128(dev, parent, ramtop);
  223.                         } else if (cmphstr(id, "zxspectrum256")) {
  224.                                 DeviceZXSpectrum256(dev, parent, ramtop);
  225.                         } else if (cmphstr(id, "zxspectrum512")) {
  226.                                 DeviceZXSpectrum512(dev, parent, ramtop);
  227.                         } else if (cmphstr(id, "zxspectrum1024")) {
  228.                                 DeviceZXSpectrum1024(dev, parent, ramtop);
  229.                         } else if (cmphstr(id, "zxspectrum2048")) {
  230.                                 DeviceZXSpectrum2048(dev, parent, ramtop);
  231.                         } else if (cmphstr(id, "zxspectrum4096")) {
  232.                                 DeviceZXSpectrum4096(dev, parent, ramtop);
  233.                         } else if (cmphstr(id, "zxspectrum8192")) {
  234.                                 DeviceZXSpectrum8192(dev, parent, ramtop);
  235.                         } else if (cmphstr(id, "zxspectrumnext")) {
  236.                                 DeviceZxSpectrumNext(dev, parent, ramtop);
  237.                         } else if (cmphstr(id, "noslot64k")) {
  238.                                 DeviceNoSlot64k(dev, parent, ramtop);
  239.                         } else if (cmphstr(id, "amstradcpc464")) {
  240.                                 DeviceAmstradCPC464(dev, parent, ramtop);
  241.                         } else if (cmphstr(id, "amstradcpc6128")) {
  242.                                 DeviceAmstradCPC6128(dev, parent, ramtop);
  243.                         } else if (!SetUserDefinedDevice(id, dev, parent, ramtop)) {
  244.                                 return false;
  245.                         }
  246.                 }
  247.                 // set up the found/new device
  248.                 Device = (*dev);
  249.                 DeviceID = Device->ID;
  250.                 Device->CheckPage(CDevice::CHECK_RESET);
  251.         }
  252.         if (ramtop && Device->ZxRamTop && ramtop != Device->ZxRamTop) {
  253.                 WarningById(W_DEV_RAMTOP);
  254.         }
  255.         if (IsSldExportActive()) {
  256.                 // SLD tracing data are being exported, export the device data
  257.                 int pageSize = Device->GetCurrentSlot()->Size;
  258.                 int pageCount = Device->PagesCount;
  259.                 int slotsCount = Device->SlotsCount;
  260.                 char buf[LINEMAX];
  261.                 snprintf(buf, LINEMAX, "pages.size:%d,pages.count:%d,slots.count:%d",
  262.                         pageSize, pageCount, slotsCount
  263.                 );
  264.                 for (int slotI = 0; slotI < slotsCount; ++slotI) {
  265.                         size_t bufLen = strlen(buf);
  266.                         char* bufAppend = buf + bufLen;
  267.                         snprintf(bufAppend, LINEMAX-bufLen,
  268.                                                 (0 == slotI) ? ",slots.adr:%d" : ",%d",
  269.                                                 Device->GetSlot(slotI)->Address);
  270.                 }
  271.                 // pagesize
  272.                 WriteToSldFile(-1,-1,'Z',buf);
  273.         }
  274.         return true;
  275. }
  276.  
  277. const char* DEVICE_NONE_ID = "NONE";
  278.  
  279. const char* GetDeviceName() {
  280.         return DeviceID ? DeviceID : DEVICE_NONE_ID;
  281. }
  282.  
  283. std::vector<CDeviceDef*> DefDevices;
  284.  
  285. CDeviceDef::CDeviceDef(const char* name, aint slot_size, aint page_count)
  286.         : SlotSize(slot_size), SlotsCount((0x10000 + slot_size - 1) / slot_size), PagesCount(page_count) {
  287.         assert(name);
  288.         ID = STRDUP(name);
  289. }
  290.  
  291. CDeviceDef::~CDeviceDef() {
  292.         free(ID);
  293. }
  294.  
  295. CDevice::CDevice(const char *name, CDevice *parent)
  296.         : Next(nullptr), SlotsCount(0), PagesCount(0), Memory(nullptr), ZxRamTop(0), CurrentSlot(0),
  297.         previousSlotI(0), previousSlotOpt(CDeviceSlot::ESlotOptions::O_NONE), limitExceeded(false) {
  298.         ID = STRDUP(name);
  299.         if (parent) parent->Next = this;
  300.         for (auto & slot : Slots) slot = nullptr;
  301.         for (auto & page : Pages) page = nullptr;
  302. }
  303.  
  304. CDevice::~CDevice() {
  305.         for (auto & slot : Slots) if (slot) delete slot;
  306.         for (auto & page : Pages) if (page) delete page;
  307.         if (Memory) delete[] Memory;
  308.         if (Next) delete Next;
  309.         free(ID);
  310. }
  311.  
  312. void CDevice::AddSlot(int32_t adr, int32_t size) {
  313.         if (CDeviceDef::MAX_SLOT_N == SlotsCount) ErrorInt("Can't add more slots, already at max", CDeviceDef::MAX_SLOT_N, FATAL);
  314.         Slots[SlotsCount++] = new CDeviceSlot(adr, size);
  315. }
  316.  
  317. void CDevice::AddPage(byte* memory, int32_t size) {
  318.         if (CDeviceDef::MAX_PAGE_N == PagesCount) ErrorInt("Can't add more pages, already at max", CDeviceDef::MAX_PAGE_N, FATAL);
  319.         Pages[PagesCount] = new CDevicePage(memory, size, PagesCount);
  320.         PagesCount++;
  321. }
  322.  
  323. CDeviceSlot* CDevice::GetSlot(int num) {
  324.         if (Slots[num]) return Slots[num];
  325.         Error("Wrong slot number", lp);
  326.         return Slots[0];
  327. }
  328.  
  329. CDevicePage* CDevice::GetPage(int num) {
  330.         if (Pages[num]) return Pages[num];
  331.         Error("Wrong page number", lp);
  332.         return Pages[0];
  333. }
  334.  
  335. // returns slot belonging to the Z80-address (16bit)
  336. int CDevice::GetSlotOfA16(int32_t address) {
  337.         for (int i=SlotsCount; i--; ) {
  338.                 CDeviceSlot* const S = Slots[i];
  339.                 if (address < S->Address) continue;
  340.                 if (S->Address + S->Size <= address) return -1;         // outside of slot
  341.                 return i;
  342.         }
  343.         return -1;
  344. }
  345.  
  346. // returns currently mapped page for the Z80-address (16bit)
  347. int CDevice::GetPageOfA16(int32_t address) {
  348.         int slotNum = GetSlotOfA16(address);
  349.         if (-1 == slotNum) return -1;
  350.         if (nullptr == Slots[slotNum]->Page) return -1;
  351.         return Slots[slotNum]->Page->Number;
  352. }
  353.  
  354. void CDevice::CheckPage(const ECheckPageLevel level) {
  355.         // fake DISP address gets auto-wrapped FFFF->0 (with warning only)
  356.         // only with "emit" mode, labels may get the value 0x10000 before the address gets truncated
  357.         if (DISP_NONE != PseudoORG && CHECK_NO_EMIT != level && 0x10000 <= CurAddress) {
  358.                 if (LASTPASS == pass) {
  359.                         char buf[64];
  360.                         SPRINTF1(buf, 64, "RAM limit exceeded 0x%X by DISP", (unsigned int)CurAddress);
  361.                         Warning(buf);
  362.                 }
  363.                 CurAddress &= 0xFFFF;
  364.         }
  365.         // check the emit address for bytecode
  366.         const int realAddr = DISP_NONE != PseudoORG ? adrdisp : CurAddress;
  367.         // quicker check to avoid scanning whole slots array every byte
  368.         if (CHECK_RESET != level
  369.                 && Slots[previousSlotI]->Address <= realAddr
  370.                 && realAddr < Slots[previousSlotI]->Address + Slots[previousSlotI]->Size) return;
  371.         for (int i=SlotsCount; i--; ) {
  372.                 CDeviceSlot* const S = Slots[i];
  373.                 if (realAddr < S->Address) continue;
  374.                 Page = S->Page;
  375.                 MemoryPointer = Page->RAM + (realAddr - S->Address);
  376.                 if (CHECK_RESET == level) {
  377.                         previousSlotOpt = S->Option;
  378.                         previousSlotI = i;
  379.                         limitExceeded = false;
  380.                         return;
  381.                 }
  382.                 // if still in the same slot and within boundaries, we are done
  383.                 if (i == previousSlotI && realAddr < S->Address + S->Size) return;
  384.                 // crossing into other slot, check options for special functionality of old slot
  385.                 if (S->Address + S->Size <= realAddr) MemoryPointer = nullptr; // you're not writing there
  386.                 switch (previousSlotOpt) {
  387.                         case CDeviceSlot::O_ERROR:
  388.                                 if (LASTPASS == pass && CHECK_EMIT == level && !limitExceeded) {
  389.                                         ErrorInt("Write outside of memory slot", realAddr, SUPPRESS);
  390.                                         limitExceeded = true;
  391.                                 }
  392.                                 break;
  393.                         case CDeviceSlot::O_WARNING:
  394.                                 if (LASTPASS == pass && CHECK_EMIT == level && !limitExceeded) {
  395.                                         Warning("Write outside of memory slot");
  396.                                         limitExceeded = true;
  397.                                 }
  398.                                 break;
  399.                         case CDeviceSlot::O_NEXT:
  400.                         {
  401.                                 CDeviceSlot* const prevS = Slots[previousSlotI];
  402.                                 const int nextPageN = prevS->Page->Number + 1;
  403.                                 if (PagesCount <= nextPageN) {
  404.                                         ErrorInt("No more memory pages to map next one into slot", previousSlotI, SUPPRESS);
  405.                                         // disable the option on the overflowing slot
  406.                                         prevS->Option = CDeviceSlot::O_NONE;
  407.                                         break;          // continue into next slot, don't wrap any more
  408.                                 }
  409.                                 if (realAddr != (prevS->Address + prevS->Size)) {       // should be equal
  410.                                         ErrorInt("Write beyond memory slot in wrap-around slot catched too late by",
  411.                                                                 realAddr - prevS->Address - prevS->Size, FATAL);
  412.                                         break;
  413.                                 }
  414.                                 prevS->Page = Pages[nextPageN];         // map next page into the guarded slot
  415.                                 Page = prevS->Page;
  416.                                 if (DISP_NONE != PseudoORG) adrdisp -= prevS->Size;
  417.                                 else CurAddress -= prevS->Size;
  418.                                 MemoryPointer = Page->RAM;
  419.                                 return;         // preserve current option status
  420.                         }
  421.                         default:
  422.                                 if (LASTPASS == pass && CHECK_EMIT == level && !limitExceeded && !MemoryPointer) {
  423.                                         ErrorInt("Write outside of device memory at", realAddr, SUPPRESS);
  424.                                         limitExceeded = true;
  425.                                 }
  426.                                 break;
  427.                 }
  428.                 // refresh check slot settings
  429.                 limitExceeded &= (previousSlotI == i);  // reset limit flag if slot changed (in non check_reset mode)
  430.                 previousSlotI = i;
  431.                 previousSlotOpt = S->Option;
  432.                 return;
  433.         }
  434.         Error("CheckPage(..): please, contact the author of this program.", nullptr, FATAL);
  435. }
  436.  
  437. bool CDevice::SetSlot(int slotNumber) {
  438.         if (slotNumber < 0 || SlotsCount <= slotNumber || nullptr == Slots[slotNumber]) return false;
  439.         CurrentSlot = slotNumber;
  440.         return true;
  441. }
  442.  
  443. CDeviceSlot* CDevice::GetCurrentSlot() {
  444.         return GetSlot(CurrentSlot);
  445. }
  446.  
  447. // Calling this with (PagesCount, 0) will return total memory size
  448. int32_t CDevice::GetMemoryOffset(int page, int32_t offset) const {
  449.         if (!Pages[0]) return 0;
  450.         return offset + page * Pages[0]->Size;
  451. }
  452.  
  453. void CDevice::Poke(aint z80adr, byte value) {
  454.         // write byte into device memory with current page-mapping
  455.         const int adrPage = GetPageOfA16(z80adr);
  456.         if (-1 == adrPage) return;              // silently ignore invalid address
  457.         CDevicePage* page = GetPage(adrPage);
  458.         page->RAM[z80adr & (page->Size-1)] = value;
  459. }
  460.  
  461. aint CDevice::SlotNumberFromPreciseAddress(aint address) {
  462.         if (address < SlotsCount) return address;               // seems to be slot number, not address
  463.         // check if the address (input value) does exactly match start-address of some slot
  464.         int slotNum = GetSlotOfA16(address);
  465.         if (-1 == slotNum) return address;                              // does not belong to any slot
  466.         if (address != GetSlot(slotNum)->Address) return address;               // not exact match
  467.         return slotNum;                                                                 // return address converted into slot number
  468. }
  469.  
  470. CDevicePage::CDevicePage(byte* memory, int32_t size, int number)
  471.         : Size(size), Number(number), RAM(memory) {
  472.         if (nullptr == RAM) Error("No memory defined", nullptr, FATAL);
  473. }
  474.  
  475. CDeviceSlot::CDeviceSlot(int32_t adr, int32_t size)
  476.         : Address(adr), Size(size), Page(nullptr), InitialPage(-1), Option(O_NONE) {
  477. }
  478.  
  479. CDeviceSlot::~CDeviceSlot() {
  480. }
  481.  
  482. const unsigned char ZX_SYSVARS_DATA[] = {
  483.         0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
  484.         0x01, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x01, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00,
  485.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  486.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x40, 0x00, 0xff, 0xcc, 0x01, 0x54, 0xff, 0x00,
  487.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xcb, 0x5c, 0x00, 0x00, 0xb6,
  488.         0x5c, 0xb6, 0x5c, 0xcb, 0x5c, 0x00, 0x00, 0xca, 0x5c, 0xcc, 0x5c, 0xcc, 0x5c, 0xcc, 0x5c, 0x00,
  489.         0x00, 0xce, 0x5c, 0xce, 0x5c, 0xce, 0x5c, 0x00, 0x92, 0x5c, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,
  490.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xff, 0x00, 0x00, 0x21,
  491.         0x5b, 0x00, 0x21, 0x17, 0x00, 0x40, 0xe0, 0x50, 0x21, 0x18, 0x21, 0x17, 0x01, 0x38, 0x00, 0x38,
  492.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  493.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  494.         0x00, 0x00, 0x57, 0xff, 0xff, 0xff, 0xf4, 0x09, 0xa8, 0x10, 0x4b, 0xf4, 0x09, 0xc4, 0x15, 0x53,
  495.         0x81, 0x0f, 0xc4, 0x15, 0x52, 0xf4, 0x09, 0xc4, 0x15, 0x50, 0x80, 0x80, 0x0d, 0x80, 0x00, 0x00,
  496.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  497.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  498.         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  499. };
  500.  
  501. const unsigned char ZX_STACK_DATA[] = {
  502.         0x03, 0x13, 0x00, 0x3e
  503. };
  504.  
  505. const unsigned char ZX_UDG_DATA[168] = {
  506.         0x00, 0x3c, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x00, 0x00, 0x7c, 0x42, 0x7c, 0x42, 0x42, 0x7c, 0x00,
  507.         0x00, 0x3c, 0x42, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x44, 0x78, 0x00,
  508.         0x00, 0x7e, 0x40, 0x7c, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x7e, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x00,
  509.         0x00, 0x3c, 0x42, 0x40, 0x4e, 0x42, 0x3c, 0x00, 0x00, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x00,
  510.         0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00,
  511.         0x00, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00,
  512.         0x00, 0x42, 0x66, 0x5a, 0x42, 0x42, 0x42, 0x00, 0x00, 0x42, 0x62, 0x52, 0x4a, 0x46, 0x42, 0x00,
  513.         0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x00,
  514.         0x00, 0x3c, 0x42, 0x42, 0x52, 0x4a, 0x3c, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x7c, 0x44, 0x42, 0x00,
  515.         0x00, 0x3c, 0x40, 0x3c, 0x02, 0x42, 0x3c, 0x00, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00,
  516.         0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00
  517. };
  518.