zymosis: renamed "SLL" to "SLS"
[zymosis.git] / src / ZXEmuT / tapeldrx.c
blobb1b43bb814c85ff3a4b2570538a256d366b427b8
1 /***************************************************************************
3 * ZXEmuT -- ZX Spectrum Emulator with Tcl scripting
5 * Copyright (C) 2012-2022 Ketmar Dark <ketmar@ketmar.no-ip.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
20 #include "debugger.h"
23 static inline int checkByte (int addr, uint8_t v) {
24 addr &= 0xffff;
25 return (z80.mem_read(&z80, addr, ZYM_MEMIO_OTHER) == v);
29 static inline int checkWord (int addr, uint16_t v) {
30 addr &= 0xffff;
31 return
32 (z80.mem_read(&z80, addr, ZYM_MEMIO_OTHER) == (v&0xff) &&
33 z80.mem_read(&z80, (addr+1)&0xffff, ZYM_MEMIO_OTHER) == ((v>>8)&0xff));
37 static inline uint16_t getWord (int addr) {
38 addr &= 0xffff;
39 return
40 (z80.mem_read(&z80, addr, ZYM_MEMIO_OTHER)|(z80.mem_read(&z80, (addr+1)&0xffff, ZYM_MEMIO_OTHER)<<8));
44 ////////////////////////////////////////////////////////////////////////////////
45 /* legend:
46 * <0: new negative address offset
47 * 0: next is 0 too? exit, else new positive address offset
48 * >0xff && <0x8000: check swapped word
49 * -32767 -- NOP
50 * -32666 -- skip this byte
52 static int is_pattern_ok (int addr, const int16_t *pattern) {
53 int a = addr;
54 for (;;) {
55 int16_t p = *pattern++;
56 if (p <= 0 && p > -32000) {
57 // new offset or end
58 if (p == 0) {
59 // positive offset or end
60 p = *pattern++;
61 if (p == 0) return 1; // end of data, ok
63 a = (addr+p)&0xffff;
64 if (optDebugFlashLoad) fprintf(stderr, " pattern #%04X: #%04X (%d)\n", addr, a, p);
65 } else if (p != -32666) {
66 if (p == -32767) p = 0;
67 if (p > 0xff) {
68 if (z80.mem_read(&z80, a, ZYM_MEMIO_OTHER) != ((p>>8)&0xff)) return 0;
69 a = (a+1)&0xffff;
70 if (z80.mem_read(&z80, a, ZYM_MEMIO_OTHER) != (p&0xff)) return 0;
71 } else {
72 if (z80.mem_read(&z80, a, ZYM_MEMIO_OTHER) != p) return 0;
74 a = (a+1)&0xffff;
75 } else {
76 a = (a+1)&0xffff;
82 ////////////////////////////////////////////////////////////////////////////////
83 typedef struct {
84 const char *name;
85 const int16_t *pattern;
86 int (*detectFn) (void);
87 int (*accelFn) (void);
88 int exitOfs; // 0: detect
89 } fl_loader_info_t;
92 ////////////////////////////////////////////////////////////////////////////////
93 #define MAX_DETECTORS (128)
94 static int detector_count = 0;
95 static const fl_loader_info_t *detectors[MAX_DETECTORS];
98 static void fl_register_loader (const fl_loader_info_t *nfo) {
99 if (detector_count >= MAX_DETECTORS) {
100 fprintf(stderr, "FATAL: too many FlashLoad(utm) loaders!\n");
101 abort();
103 detectors[detector_count++] = nfo;
107 #include "tapeldrx_ftl.c"
108 #include "tapeldrx_flashload.c"
109 #include "tapeldrx_uniloader.c"
110 #include "tapeldrx_hewson.c"
111 #include "tapeldrx_pl2.c"
112 #include "tapeldrx_edge.c"
115 ////////////////////////////////////////////////////////////////////////////////
116 // 0x564
117 static const fl_loader_info_t rom_loader_info = {
118 .name="ROM Loader",
119 .pattern=NULL,
120 .detectFn=NULL,
121 .accelFn=emuTapeDoROMLoad,
122 .exitOfs=123,
126 ////////////////////////////////////////////////////////////////////////////////
127 static int executeLoader (uint16_t addr, const fl_loader_info_t *li) {
128 if (optDebugFlashLoad) fprintf(stderr, "+++ LOADER: %s\n", li->name);
129 cprintf("detected loader: %s\n", li->name);
130 if (!optTapePlaying) emuStartTapeAuto();
131 if (li->accelFn() == 0) {
132 if (z80.hl.h) cprintf("\4tape loading error\n");
133 z80.pc = addr+li->exitOfs;
134 emuTapeAutoStop();
135 if (optDebugFlashLoad) dbgSetActive(1);
136 return 0;
138 cprintf("block not found!\n");
139 emuTapeAutoStop();
140 if (optDebugFlashLoad) dbgSetActive(1);
141 return -1;
145 int emuTapeFlashLoad (void) {
146 int addr = z80.pc;
147 if (addr == 0x0564) {
148 if (zxModel == ZX_MACHINE_PLUS2A || zxModel == ZX_MACHINE_PLUS3) {
149 if (zxLastPagedROM == 3) return executeLoader(addr, &rom_loader_info);
150 } else {
151 if (!zxTRDOSPagedIn && (zxModel == ZX_MACHINE_48K || zxLastPagedROM == 1)) return executeLoader(addr, &rom_loader_info);
154 if (addr < 0x4000) return -1; // ROM
155 //if ((z80.afx.f&ZYM_FLAG_C) == 0) return -1; // don't accelerate VERIFY mode
156 if (!checkByte(addr, 0x1F)) return -1; //RRA?
157 if (!checkWord(addr-4, 0xFED3) && // OUT (#FE),A?
158 !checkByte(addr-3, 0xE5)) return -1; // PUSH HL (elite loader)
159 //if (optDebugFlashLoad) { dbgSetActive(1); return -1; }
160 //fprintf(stderr, "trying to detect known loader at 0x%04x\n", addr);
161 for (int f = 0; f < detector_count; ++f) {
162 const fl_loader_info_t *li = detectors[f];
163 if (optDebugFlashLoad) fprintf(stderr, "*** trying loader #%u: %s (#%04X)\n", f, li->name, addr);
164 if (li->pattern == NULL && li->detectFn == NULL) continue;
165 if (li->pattern != NULL && !is_pattern_ok(addr, li->pattern)) continue;
166 if (optDebugFlashLoad) fprintf(stderr, " pattern ok\n");
167 if (li->detectFn != NULL && !li->detectFn()) continue;
168 return executeLoader(addr, li);
170 return -1;