• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

z00m128 / sjasmplus / 26135148044

20 May 2026 01:12AM UTC coverage: 97.798% (+0.5%) from 97.312%
26135148044

push

github

ped7g
CI: details tuning, switching coveralls.io to lcov data

Changes:
- Makefile has new target `coverage-lcov` producing web page with lcov
- using official coveralls github action to upload coverage
- processing coverage data for coveralls.io with lcov
- more diverse linux build runners (x64 + arm64, gcc container + ubuntu
runner)
- both macos-15 + macos-26 (arm64 only)
- test runner script shows sjasmplus version just before summary
- sjasmplus --version shows when unit tests are included ("+ut" version
suffix)
- `make clean` now also removes HTML coverage pages and
build/{examples|tests} folders

1 of 1 new or added line in 1 file covered. (100.0%)

154 existing lines in 14 files now uncovered.

10128 of 10356 relevant lines covered (97.8%)

172537.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.82
/sjasm/devices.cpp
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) {
55✔
32
        if (nullptr == name) return false;
55✔
33
        if (strcmp(name, "ZXSPECTRUM48") &&
55✔
34
                strcmp(name, "ZXSPECTRUM128") &&
31✔
35
                strcmp(name, "ZXSPECTRUM256") &&
19✔
36
                strcmp(name, "ZXSPECTRUM512") &&
14✔
37
                strcmp(name, "ZXSPECTRUM1024") &&
11✔
38
                strcmp(name, "ZXSPECTRUM2048") &&
8✔
39
                strcmp(name, "ZXSPECTRUM4096") &&
6✔
40
                strcmp(name, "ZXSPECTRUM8192"))
4✔
41
        {
42
                return false;
2✔
43
        }
44
        return true;
53✔
45
}
46

47
bool IsAmstradCPCDevice(const char* name) {
83✔
48
        if (nullptr == name) return false;
83✔
49
        if (strcmp(name, "AMSTRADCPC464") &&
82✔
50
                strcmp(name, "AMSTRADCPC6128"))
12✔
51
        {
52
                return false;
7✔
53
        }
54
        return true;
75✔
55
}
56

57
bool IsAmstradPLUSDevice(const char* name) {
11✔
58
        if (nullptr == name) return false;
11✔
59
        if (strcmp(name, "AMSTRADCPCPLUS"))
10✔
60
        {
61
                return false;
1✔
62
        }
63
        return true;
9✔
64
}
65

66
static void initRegularSlotDevice(CDevice* const device, const int32_t slotSize, const int32_t slotCount,
659✔
67
                                                                  const int pageCount, const int* const initialPages) {
68
        for (int32_t slotAddress = 0; slotAddress < slotSize * slotCount; slotAddress += slotSize) {
4,471✔
69
                device->AddSlot(slotAddress, slotSize);
3,812✔
70
        }
71
        device->Memory = new byte[slotSize * pageCount]();
380,088,979✔
72
        for (byte* memPtr = device->Memory; memPtr < device->Memory + slotSize * pageCount; memPtr += slotSize) {
35,203✔
73
                device->AddPage(memPtr, slotSize);
34,544✔
74
        }
75
        for (int i = 0; i < device->SlotsCount; ++i) {
4,471✔
76
                CDeviceSlot* slot = device->GetSlot(i);
3,812✔
77
                slot->Page = device->GetPage(initialPages[i]);
3,812✔
78
                slot->InitialPage = slot->Page->Number;
3,812✔
79
        }
80
        device->SetSlot(device->SlotsCount - 1);
659✔
81
}
659✔
82

83
static void initZxLikeDevice(
432✔
84
        CDevice* const device, int32_t slotSize, int pageCount, const int* const initialPages, aint ramtop)
85
{
86
        initRegularSlotDevice(device, slotSize, 0x10000/slotSize, pageCount, initialPages);
432✔
87
        device->ZxRamTop = ((-1 == ramtop) || (0x5D00 <= ramtop && ramtop <= 0xFFFF)) ? ramtop : ZX_RAMTOP_DEFAULT;
432✔
88
        if (-1 == ramtop) return;                // explicit user's request to skip ZX memory init
432✔
89

90
        // set memory to state like if (for snapshot saving):
91
        // CLEAR ZxRamTop (0x5D5B default) : LOAD "bin" CODE : ... USR start_adr
92
        aint adr;
93
        // ULA attributes: INK 0 : PAPER 7 : FLASH 0 : BRIGTH 0
94
        for (adr = 0x5800; adr < 0x5B00; ++adr) device->Poke(adr, 7*8);
329,901✔
95

96
        // set UDG data at ZX_UDG_ADR (0xFF58)
97
        adr = ZX_UDG_ADR;
429✔
98
        for (byte value : ZX_UDG_DATA) device->Poke(adr++, value);
72,501✔
99

100
        // ZX SYSVARS at 0x5C00
101
        adr = ZX_SYSVARS_ADR;
429✔
102
        for (byte value : ZX_SYSVARS_DATA) device->Poke(adr++, value);
110,253✔
103
        // set RAMTOP sysvar
104
        device->Poke(ZX_SYSVARS_ADR+0xB2, device->ZxRamTop & 0xFF);
429✔
105
        device->Poke(ZX_SYSVARS_ADR+0xB3, (device->ZxRamTop>>8) & 0xFF);
429✔
106

107
        // set STACK data (without the "start" address)
108
        adr = device->ZxRamTop + 1 - sizeof(ZX_STACK_DATA);
429✔
109
        // set ERRSP sysvar to beginning of the fake stack
110
        device->Poke(ZX_SYSVARS_ADR+0x3D, adr & 0xFF);
429✔
111
        device->Poke(ZX_SYSVARS_ADR+0x3E, (adr>>8) & 0xFF);
429✔
112
        for (byte value : ZX_STACK_DATA) device->Poke(adr++, value);
2,145✔
113
}
114

115
static void DeviceZXSpectrum48(CDevice **dev, CDevice *parent, aint ramtop) {
216✔
116
        *dev = new CDevice("ZXSPECTRUM48", parent);
216✔
117
        const int initialPages[] = {0, 1, 2, 3};
216✔
118
        initZxLikeDevice(*dev, 0x4000, 4, initialPages, ramtop);
216✔
119
}
216✔
120

121
const static int initialPagesZx128[] = {7, 5, 2, 0};
122

123
static void DeviceZXSpectrum128(CDevice **dev, CDevice *parent, aint ramtop) {
159✔
124
        *dev = new CDevice("ZXSPECTRUM128", parent);
159✔
125
        initZxLikeDevice(*dev, 0x4000, 8, initialPagesZx128, ramtop);
159✔
126
}
159✔
127

128
static void DeviceZXSpectrum256(CDevice **dev, CDevice *parent, aint ramtop) {
12✔
129
        *dev = new CDevice("ZXSPECTRUM256", parent);
12✔
130
        initZxLikeDevice(*dev, 0x4000, 16, initialPagesZx128, ramtop);
12✔
131
}
12✔
132

133
static void DeviceZXSpectrum512(CDevice **dev, CDevice *parent, aint ramtop) {
9✔
134
        *dev = new CDevice("ZXSPECTRUM512", parent);
9✔
135
        initZxLikeDevice(*dev, 0x4000, 32, initialPagesZx128, ramtop);
9✔
136
}
9✔
137

138
static void DeviceZXSpectrum1024(CDevice **dev, CDevice *parent, aint ramtop) {
27✔
139
        *dev = new CDevice("ZXSPECTRUM1024", parent);
27✔
140
        initZxLikeDevice(*dev, 0x4000, 64, initialPagesZx128, ramtop);
27✔
141
}
27✔
142

143
static void DeviceZXSpectrum2048(CDevice **dev, CDevice *parent, aint ramtop) {
3✔
144
        *dev = new CDevice("ZXSPECTRUM2048", parent);
3✔
145
        initZxLikeDevice(*dev, 0x4000, 128, initialPagesZx128, ramtop);
3✔
146
}
3✔
147

148
static void DeviceZXSpectrum4096(CDevice **dev, CDevice *parent, aint ramtop) {
3✔
149
        *dev = new CDevice("ZXSPECTRUM4096", parent);
3✔
150
        initZxLikeDevice(*dev, 0x4000, 256, initialPagesZx128, ramtop);
3✔
151
}
3✔
152

153
static void DeviceZXSpectrum8192(CDevice **dev, CDevice *parent, aint ramtop) {
3✔
154
        *dev = new CDevice("ZXSPECTRUM8192", parent);
3✔
155
        initZxLikeDevice(*dev, 0x4000, 512, initialPagesZx128, ramtop);
3✔
156
}
3✔
157

158
static void DeviceZxSpectrumNext(CDevice **dev, CDevice *parent, aint ramtop) {
116✔
159
        if (ramtop) WarningById(W_NO_RAMTOP);
116✔
160
        if (Options::IsI8080) Error("Can't use ZXN device while in i8080 assembling mode", line, FATAL);
116✔
161
        if (Options::IsLR35902) Error("Can't use ZXN device while in Sharp LR35902 assembling mode", line, FATAL);
115✔
162
        *dev = new CDevice("ZXSPECTRUMNEXT", parent);
114✔
163
        const int initialPages[] = {14, 15, 10, 11, 4, 5, 0, 1};        // basically same as ZX128, but 8k
114✔
164
        initRegularSlotDevice(*dev, 0x2000, 8, 224, initialPages);
114✔
165
        // auto-enable ZX Next instruction extensions
166
        if (0 == Options::syx.IsNextEnabled) {
114✔
167
                Options::syx.IsNextEnabled = 1;
114✔
168
                Z80::InitNextExtensions();                // add the special opcodes here (they were not added)
114✔
169
                                // this is a bit late, but it should work as well as `--zxnext` option I believe
170
        }
171
}
114✔
172

173
static void DeviceNoSlot64k(CDevice **dev, CDevice *parent, aint ramtop) {
18✔
174
        if (ramtop) WarningById(W_NO_RAMTOP);
18✔
175
        *dev = new CDevice("NOSLOT64K", parent);
18✔
176
        const int initialPages[] = { 0 };
18✔
177
        initRegularSlotDevice(*dev, 0x10000, 1, 32, initialPages);        // 32*64kiB = 2MiB
18✔
178
}
18✔
179

180
static void DeviceAmstradCPC464(CDevice** dev, CDevice* parent, aint ramtop) {
33✔
181
        if (ramtop) WarningById(W_NO_RAMTOP);
33✔
182
        *dev = new CDevice("AMSTRADCPC464", parent);
33✔
183
        const int initialPages[] = { 0, 1, 2, 3 };
33✔
184
        initRegularSlotDevice(*dev, 0x4000, 4, 4, initialPages);
33✔
185
}
33✔
186

187
static void DeviceAmstradCPC6128(CDevice** dev, CDevice* parent, aint ramtop) {
24✔
188
        if (ramtop) WarningById(W_NO_RAMTOP);
24✔
189
        *dev = new CDevice("AMSTRADCPC6128", parent);
24✔
190
        const int initialPages[] = { 0, 1, 2, 3 };
24✔
191
        initRegularSlotDevice(*dev, 0x4000, 4, 8, initialPages);
24✔
192
}
24✔
193

194
static void DeviceAmstradCPCPLUS(CDevice** dev, CDevice* parent, aint ramtop) {
12✔
195
        if (ramtop) WarningById(W_NO_RAMTOP);
12✔
196
        *dev = new CDevice("AMSTRADCPCPLUS", parent);
12✔
197
        const int initialPages[] = { 0, 1, 2, 3 };
12✔
198
        initRegularSlotDevice(*dev, 0x4000, 4, 32, initialPages);        // 32*16kiB = 512MiB (maximum cartridge size)
12✔
199
}
12✔
200

201
static bool SetUserDefinedDevice(const char* id, CDevice** dev, CDevice* parent, aint ramtop) {
37✔
202
        auto findIt = std::find_if(
37✔
203
                DefDevices.begin(), DefDevices.end(),
204
                [&](const CDeviceDef* el) { return 0 == strcasecmp(id, el->getID()); }
69✔
205
        );
206
        if (DefDevices.end() == findIt) return false;        // not found
37✔
207
        const CDeviceDef & def = **findIt;
26✔
208
        if (ramtop) WarningById(W_NO_RAMTOP);
26✔
209
        *dev = new CDevice(def.getID(), parent);
26✔
210
        initRegularSlotDevice(*dev, def.SlotSize, def.SlotsCount, def.PagesCount, def.initialPages);
26✔
211
        return true;
26✔
212
}
213

214
bool SetDevice(const char *const_id, const aint ramtop) {
950✔
215
        CDevice** dev;
216
        CDevice* parent = nullptr;
950✔
217
        char* id = const_cast<char*>(const_id);                //TODO cmphstr for both const/nonconst variants?
950✔
218
                // ^ argument is const because of lua bindings
219

220
        if (!id || cmphstr(id, "none")) {
950✔
221
                DeviceID = nullptr;
151✔
222
                Device = nullptr;
151✔
223
                return true;
151✔
224
        }
225

226
        if (!DeviceID || strcmp(DeviceID, id)) {        // different device than current, change to it
799✔
227
                DeviceID = nullptr;
737✔
228
                dev = &Devices;
737✔
229
                // search for device
230
                while (*dev) {
1,064✔
231
                        parent = *dev;
392✔
232
                        if (!strcmp(parent->ID, id)) break;
392✔
233
                        dev = &(parent->Next);
327✔
234
                }
235
                if (nullptr == (*dev)) {        // device not found
737✔
236
                        if (cmphstr(id, "zxspectrum48")) {                        // must be lowercase to catch both cases
672✔
237
                                DeviceZXSpectrum48(dev, parent, ramtop);
216✔
238
                        } else if (cmphstr(id, "zxspectrum128")) {
456✔
239
                                DeviceZXSpectrum128(dev, parent, ramtop);
159✔
240
                        } else if (cmphstr(id, "zxspectrum256")) {
297✔
241
                                DeviceZXSpectrum256(dev, parent, ramtop);
12✔
242
                        } else if (cmphstr(id, "zxspectrum512")) {
285✔
243
                                DeviceZXSpectrum512(dev, parent, ramtop);
9✔
244
                        } else if (cmphstr(id, "zxspectrum1024")) {
276✔
245
                                DeviceZXSpectrum1024(dev, parent, ramtop);
27✔
246
                        } else if (cmphstr(id, "zxspectrum2048")) {
249✔
247
                                DeviceZXSpectrum2048(dev, parent, ramtop);
3✔
248
                        } else if (cmphstr(id, "zxspectrum4096")) {
246✔
249
                                DeviceZXSpectrum4096(dev, parent, ramtop);
3✔
250
                        } else if (cmphstr(id, "zxspectrum8192")) {
243✔
251
                                DeviceZXSpectrum8192(dev, parent, ramtop);
3✔
252
                        } else if (cmphstr(id, "zxspectrumnext")) {
240✔
253
                                DeviceZxSpectrumNext(dev, parent, ramtop);
116✔
254
                        } else if (cmphstr(id, "noslot64k")) {
124✔
255
                                DeviceNoSlot64k(dev, parent, ramtop);
18✔
256
                        } else if (cmphstr(id, "amstradcpc464")) {
106✔
257
                                DeviceAmstradCPC464(dev, parent, ramtop);
33✔
258
                        } else if (cmphstr(id, "amstradcpc6128")) {
73✔
259
                                DeviceAmstradCPC6128(dev, parent, ramtop);
24✔
260
                        } else if (cmphstr(id, "amstradcpcplus")) {
49✔
261
                                DeviceAmstradCPCPLUS(dev, parent, ramtop);
12✔
262
                        } else if (!SetUserDefinedDevice(id, dev, parent, ramtop)) {
37✔
263
                                return false;
11✔
264
                        }
265
                }
266
                // set up the found/new device
267
                Device = (*dev);
724✔
268
                DeviceID = Device->ID;
724✔
269
                Device->CheckPage(CDevice::CHECK_RESET);
724✔
270
        }
271
        if (ramtop && Device->ZxRamTop && ramtop != Device->ZxRamTop) {
786✔
272
                WarningById(W_DEV_RAMTOP);
30✔
273
        }
274
        if (IsSldExportActive()) {
786✔
275
                // SLD tracing data are being exported, export the device data
276
                int pageSize = Device->GetCurrentSlot()->Size;
24✔
277
                int pageCount = Device->PagesCount;
24✔
278
                int slotsCount = Device->SlotsCount;
24✔
279
                char buf[LINEMAX];
280
                snprintf(buf, LINEMAX, "pages.size:%d,pages.count:%d,slots.count:%d",
24✔
281
                        pageSize, pageCount, slotsCount
282
                );
283
                for (int slotI = 0; slotI < slotsCount; ++slotI) {
180✔
284
                        size_t bufLen = strlen(buf);
156✔
285
                        char* bufAppend = buf + bufLen;
156✔
286
                        snprintf(bufAppend, LINEMAX-bufLen,
156✔
287
                                                (0 == slotI) ? ",slots.adr:%d" : ",%d",
288
                                                Device->GetSlot(slotI)->Address);
156✔
289
                }
290
                // pagesize
291
                WriteToSldFile(-1,-1,'Z',buf);
24✔
292
        }
293
        return true;
786✔
294
}
295

296
const char* DEVICE_NONE_ID = "NONE";
297

298
const char* GetDeviceName() {
28✔
299
        return DeviceID ? DeviceID : DEVICE_NONE_ID;
28✔
300
}
301

302
std::vector<CDeviceDef*> DefDevices;
303

304
CDeviceDef::CDeviceDef(const char* name, aint slot_size, aint page_count)
8✔
305
        : SlotSize(slot_size), SlotsCount((0x10000 + slot_size - 1) / slot_size), PagesCount(page_count) {
8✔
306
        assert(name);
8✔
307
        ID = STRDUP(name);
8✔
308
}
8✔
309

310
CDeviceDef::~CDeviceDef() {
8✔
311
        free(ID);
8✔
312
}
8✔
313

314
CDevice::CDevice(const char *name, CDevice *parent)
663✔
315
        : Next(nullptr), SlotsCount(0), PagesCount(0), Memory(nullptr), ZxRamTop(0), CurrentSlot(0),
663✔
316
        previousSlotI(0), previousSlotOpt(CDeviceSlot::ESlotOptions::O_NONE), limitExceeded(false) {
663✔
317
        ID = STRDUP(name);
663✔
318
        if (parent) parent->Next = this;
663✔
319
        for (auto & slot : Slots) slot = nullptr;
170,391✔
320
        for (auto & page : Pages) page = nullptr;
679,575✔
321
}
663✔
322

323
CDevice::~CDevice() {
663✔
324
        for (auto & slot : Slots) if (slot) delete slot;
170,391✔
325
        for (auto & page : Pages) if (page) delete page;
679,575✔
326
        if (Memory) delete[] Memory;
663✔
327
        if (Next) delete Next;
663✔
328
        free(ID);
663✔
329
}
663✔
330

331
void CDevice::AddSlot(int32_t adr, int32_t size) {
3,820✔
332
        if (CDeviceDef::MAX_SLOT_N == SlotsCount) ErrorInt("Can't add more slots, already at max", CDeviceDef::MAX_SLOT_N, FATAL);
3,820✔
333
        Slots[SlotsCount++] = new CDeviceSlot(adr, size);
3,820✔
334
}
3,820✔
335

336
void CDevice::AddPage(byte* memory, int32_t size) {
34,556✔
337
        if (CDeviceDef::MAX_PAGE_N == PagesCount) ErrorInt("Can't add more pages, already at max", CDeviceDef::MAX_PAGE_N, FATAL);
34,556✔
338
        Pages[PagesCount] = new CDevicePage(memory, size, PagesCount);
34,556✔
339
        PagesCount++;
34,556✔
340
}
34,556✔
341

342
CDeviceSlot* CDevice::GetSlot(int num) {
350,206✔
343
        if (Slots[num]) return Slots[num];
350,206✔
344
        Error("Wrong slot number", lp);
1✔
345
        return Slots[0];
1✔
346
}
347

348
CDevicePage* CDevice::GetPage(int num) {
521,257✔
349
        if (Pages[num]) return Pages[num];
521,257✔
350
        Error("Wrong page number", lp);
1✔
351
        return Pages[0];
1✔
352
}
353

354
// returns slot belonging to the Z80-address (16bit)
355
int CDevice::GetSlotOfA16(int32_t address) {
1,181,209✔
356
        for (int i=SlotsCount; i--; ) {
3,844,081✔
357
                CDeviceSlot* const S = Slots[i];
3,844,037✔
358
                if (address < S->Address) continue;
3,844,037✔
359
                if (S->Address + S->Size <= address) return -1;                // outside of slot
1,181,165✔
360
                return i;
1,077,698✔
361
        }
362
        return -1;
44✔
363
}
364

365
// returns currently mapped page for the Z80-address (16bit)
366
page_t CDevice::GetPageOfA16(int32_t address) {
1,180,119✔
367
        int slotNum = GetSlotOfA16(address);
1,180,119✔
368
        if (-1 == slotNum) return LABEL_PAGE_OUT_OF_BOUNDS;
1,180,119✔
369
        if (nullptr == Slots[slotNum]->Page) return LABEL_PAGE_OUT_OF_BOUNDS;
1,076,610✔
370
        return Slots[slotNum]->Page->Number;
1,076,610✔
371
}
372

373
void CDevice::CheckPage(const ECheckPageLevel level) {
1,855,978✔
374
        // fake DISP address gets auto-wrapped FFFF->0 (with warning only)
375
        // only with "emit" mode, labels may get the value 0x10000 before the address gets truncated
376
        if (DISP_NONE != PseudoORG && CHECK_NO_EMIT != level && 0x10000 <= CurAddress) {
1,855,978✔
377
                if (LASTPASS == pass) {
9✔
378
                        char buf[64];
379
                        SPRINTF1(buf, 64, "RAM limit exceeded 0x%X by DISP", (unsigned int)CurAddress);
3✔
380
                        Warning(buf);
3✔
381
                }
382
                LabelTable.SizeBoundary(CLabelTable::BOUNDARY_FLOW);        // end of address space is hard SIZEOF-boundary
9✔
383
                CurAddress &= 0xFFFF;
9✔
384
        }
385
        // check the emit address for bytecode
386
        const int realAddr = DISP_NONE != PseudoORG ? adrdisp : CurAddress;
1,855,978✔
387
        // quicker check to avoid scanning whole slots array every byte
388
        if (CHECK_RESET != level
1,855,978✔
389
                && Slots[previousSlotI]->Address <= realAddr
1,851,799✔
390
                && realAddr < Slots[previousSlotI]->Address + Slots[previousSlotI]->Size) {
1,851,682✔
391
                // refresh MemoryPointer in case the CurAddress did move a bit without emit (negative BLOCK, etc)
392
                MemoryPointer = Slots[previousSlotI]->Page->RAM + (realAddr - Slots[previousSlotI]->Address);
1,850,224✔
393
                assert(        (Slots[previousSlotI]->Page->RAM <= MemoryPointer) &&
1,850,224✔
394
                                (MemoryPointer < Slots[previousSlotI]->Page->RAM + Slots[previousSlotI]->Size));
395
                return;
1,850,224✔
396
        }
397
        for (int i=SlotsCount; i--; ) {
35,075✔
398
                CDeviceSlot* const S = Slots[i];
35,075✔
399
                if (realAddr < S->Address) continue;
35,075✔
400
                Page = S->Page;
5,754✔
401
                MemoryPointer = Page->RAM + (realAddr - S->Address);
5,754✔
402
                 if (CHECK_RESET == level) {
5,754✔
403
                        previousSlotOpt = S->Option;
4,179✔
404
                        previousSlotI = i;
4,179✔
405
                        limitExceeded = false;
4,179✔
406
                        return;
4,179✔
407
                }
408
                // if still in the same slot and within boundaries, we are done
409
                if (i == previousSlotI && realAddr < S->Address + S->Size) return;
1,575✔
410
                // crossing into other slot, check options for special functionality of old slot
411
                if (S->Address + S->Size <= realAddr) MemoryPointer = nullptr; // you're not writing there
1,575✔
412
                switch (previousSlotOpt) {
1,575✔
413
                        case CDeviceSlot::O_ERROR:
24✔
414
                                if (LASTPASS == pass && CHECK_EMIT == level && !limitExceeded) {
24✔
415
                                        ErrorInt("Write outside of memory slot", realAddr, SUPPRESS);
4✔
416
                                        limitExceeded = true;
4✔
417
                                }
418
                                break;
24✔
419
                        case CDeviceSlot::O_WARNING:
9✔
420
                                if (LASTPASS == pass && CHECK_EMIT == level && !limitExceeded) {
9✔
421
                                        Warning("Write outside of memory slot");
2✔
422
                                        limitExceeded = true;
2✔
423
                                }
424
                                break;
9✔
425
                        case CDeviceSlot::O_NEXT:
90✔
426
                        {
427
                                LabelTable.SizeBoundary(CLabelTable::BOUNDARY_FLOW);        // stop *any* SIZEOF-tracking with warning
90✔
428
                                CDeviceSlot* const prevS = Slots[previousSlotI];
90✔
429
                                const page_t nextPageN = prevS->Page->Number + 1;
90✔
430
                                if (PagesCount <= nextPageN) {
90✔
431
                                        ErrorInt("No more memory pages to map next one into slot", previousSlotI, SUPPRESS);
6✔
432
                                        // disable the option on the overflowing slot
433
                                        prevS->Option = CDeviceSlot::O_NONE;
6✔
434
                                        // reset error reporting even when level is CHECK_NO_EMIT, one error is enough
435
                                        limitExceeded = false;
6✔
436
                                        previousSlotI = i;
6✔
437
                                        previousSlotOpt = S->Option;
6✔
438
                                        break;                // continue into next slot, don't wrap any more
6✔
439
                                }
440
                                if (realAddr != (prevS->Address + prevS->Size)) {        // should be equal
84✔
441
                                        ErrorInt("Write beyond memory slot in wrap-around slot caught too late by",
×
UNCOV
442
                                                                realAddr - prevS->Address - prevS->Size, FATAL);
×
UNCOV
443
                                        break;
×
444
                                }
445
                                prevS->Page = Pages[nextPageN];                // map next page into the guarded slot
84✔
446
                                Page = prevS->Page;
84✔
447
                                if (DISP_NONE != PseudoORG) adrdisp -= prevS->Size;
84✔
448
                                else CurAddress -= prevS->Size;
84✔
449
                                MemoryPointer = Page->RAM;
84✔
450
                                return;                // preserve current option status
84✔
451
                        }
452
                        default:
1,452✔
453
                                if (LASTPASS == pass && CHECK_EMIT == level && !limitExceeded && !MemoryPointer) {
1,452✔
454
                                        ErrorInt("Write outside of device memory at", realAddr, SUPPRESS);
19✔
455
                                        limitExceeded = true;
19✔
456
                                }
457
                                break;
1,452✔
458
                }
459
                // refresh check slot settings (only in CHECK_EMIT case, otherwise ParseLine will reset it with CHECK_NO_EMIT at BoL!)
460
                if (CHECK_EMIT == level) {
1,491✔
461
                        limitExceeded &= (previousSlotI == i);        // reset limit flag if slot changed (in non check_reset mode)
642✔
462
                        previousSlotI = i;
642✔
463
                        previousSlotOpt = S->Option;
642✔
464
                }
465
                return;
1,491✔
466
        }
UNCOV
467
        Error("CheckPage(..): please, contact the author of this program.", nullptr, FATAL);
×
468
}
469

470
bool CDevice::SetSlot(int slotNumber) {
999✔
471
        if (slotNumber < 0 || SlotsCount <= slotNumber || nullptr == Slots[slotNumber]) return false;
999✔
472
        CurrentSlot = slotNumber;
955✔
473
        return true;
955✔
474
}
475

476
CDeviceSlot* CDevice::GetCurrentSlot() {
334,153✔
477
        return GetSlot(CurrentSlot);
334,153✔
478
}
479

480
// Calling this with (PagesCount, 0) will return total memory size
481
int32_t CDevice::GetMemoryOffset(page_t page, int32_t offset) const {
1,035✔
482
        if (!Pages[0]) return 0;
1,035✔
483
        return offset + page * Pages[0]->Size;
1,035✔
484
}
485

486
void CDevice::Poke(aint z80adr, byte value) {
514,800✔
487
        // write byte into device memory with current page-mapping
488
        const page_t adrPage = GetPageOfA16(z80adr);
514,800✔
489
        if (LABEL_PAGE_OUT_OF_BOUNDS == adrPage) return;                // silently ignore invalid address
514,800✔
490
        CDevicePage* page = GetPage(adrPage);
514,800✔
491
        page->RAM[z80adr & (page->Size-1)] = value;
514,800✔
492
}
493

494
aint CDevice::SlotNumberFromPreciseAddress(aint address) {
1,176✔
495
        if (address < SlotsCount) return address;                // seems to be slot number, not address
1,176✔
496
        // check if the address (input value) does exactly match start-address of some slot
497
        int slotNum = GetSlotOfA16(address);
382✔
498
        if (-1 == slotNum) return address;                                // does not belong to any slot
382✔
499
        if (address != GetSlot(slotNum)->Address) return address;                // not exact match
382✔
500
        return slotNum;                                                                        // return address converted into slot number
318✔
501
}
502

503
CDevicePage::CDevicePage(byte* memory, int32_t size, page_t number)
34,556✔
504
        : Size(size), Number(number), RAM(memory) {
34,556✔
505
        if (nullptr == RAM) Error("No memory defined", nullptr, FATAL);
34,556✔
506
}
34,556✔
507

508
CDeviceSlot::CDeviceSlot(int32_t adr, int32_t size)
3,820✔
509
        : Address(adr), Size(size), Page(nullptr), InitialPage(-1), Option(O_NONE) {
3,820✔
510
}
3,820✔
511

512
CDeviceSlot::~CDeviceSlot() {
3,820✔
513
}
3,820✔
514

515
const unsigned char ZX_SYSVARS_DATA[] = {
516
        0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
517
        0x01, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x01, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00,
518
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
519
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x40, 0x00, 0xff, 0xcc, 0x01, 0x54, 0xff, 0x00,
520
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xcb, 0x5c, 0x00, 0x00, 0xb6,
521
        0x5c, 0xb6, 0x5c, 0xcb, 0x5c, 0x00, 0x00, 0xca, 0x5c, 0xcc, 0x5c, 0xcc, 0x5c, 0xcc, 0x5c, 0x00,
522
        0x00, 0xce, 0x5c, 0xce, 0x5c, 0xce, 0x5c, 0x00, 0x92, 0x5c, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,
523
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xff, 0x00, 0x00, 0x21,
524
        0x5b, 0x00, 0x21, 0x17, 0x00, 0x40, 0xe0, 0x50, 0x21, 0x18, 0x21, 0x17, 0x01, 0x38, 0x00, 0x38,
525
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
526
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
527
        0x00, 0x00, 0x57, 0xff, 0xff, 0xff, 0xf4, 0x09, 0xa8, 0x10, 0x4b, 0xf4, 0x09, 0xc4, 0x15, 0x53,
528
        0x81, 0x0f, 0xc4, 0x15, 0x52, 0xf4, 0x09, 0xc4, 0x15, 0x50, 0x80, 0x80, 0x0d, 0x80, 0x00, 0x00,
529
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
530
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
531
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
532
};
533

534
const unsigned char ZX_STACK_DATA[] = {
535
        0x03, 0x13, 0x00, 0x3e
536
};
537

538
const unsigned char ZX_UDG_DATA[168] = {
539
        0x00, 0x3c, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x00, 0x00, 0x7c, 0x42, 0x7c, 0x42, 0x42, 0x7c, 0x00,
540
        0x00, 0x3c, 0x42, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x44, 0x78, 0x00,
541
        0x00, 0x7e, 0x40, 0x7c, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x7e, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x00,
542
        0x00, 0x3c, 0x42, 0x40, 0x4e, 0x42, 0x3c, 0x00, 0x00, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x00,
543
        0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00,
544
        0x00, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00,
545
        0x00, 0x42, 0x66, 0x5a, 0x42, 0x42, 0x42, 0x00, 0x00, 0x42, 0x62, 0x52, 0x4a, 0x46, 0x42, 0x00,
546
        0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x00,
547
        0x00, 0x3c, 0x42, 0x42, 0x52, 0x4a, 0x3c, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x7c, 0x44, 0x42, 0x00,
548
        0x00, 0x3c, 0x40, 0x3c, 0x02, 0x42, 0x3c, 0x00, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00,
549
        0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00
550
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc