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 **************************************************************************/
23 static inline int checkByte (int addr
, uint8_t v
) {
25 return (z80
.mem_read(&z80
, addr
, ZYM_MEMIO_OTHER
) == v
);
29 static inline int checkWord (int addr
, uint16_t v
) {
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
) {
40 (z80
.mem_read(&z80
, addr
, ZYM_MEMIO_OTHER
)|(z80
.mem_read(&z80
, (addr
+1)&0xffff, ZYM_MEMIO_OTHER
)<<8));
44 ////////////////////////////////////////////////////////////////////////////////
46 * <0: new negative address offset
47 * 0: next is 0 too? exit, else new positive address offset
48 * >0xff && <0x8000: check swapped word
50 * -32666 -- skip this byte
52 static int is_pattern_ok (int addr
, const int16_t *pattern
) {
55 int16_t p
= *pattern
++;
56 if (p
<= 0 && p
> -32000) {
59 // positive offset or end
61 if (p
== 0) return 1; // end of data, ok
64 if (optDebugFlashLoad
) fprintf(stderr
, " pattern #%04X: #%04X (%d)\n", addr
, a
, p
);
65 } else if (p
!= -32666) {
66 if (p
== -32767) p
= 0;
68 if (z80
.mem_read(&z80
, a
, ZYM_MEMIO_OTHER
) != ((p
>>8)&0xff)) return 0;
70 if (z80
.mem_read(&z80
, a
, ZYM_MEMIO_OTHER
) != (p
&0xff)) return 0;
72 if (z80
.mem_read(&z80
, a
, ZYM_MEMIO_OTHER
) != p
) return 0;
82 ////////////////////////////////////////////////////////////////////////////////
85 const int16_t *pattern
;
86 int (*detectFn
) (void);
87 int (*accelFn
) (void);
88 int exitOfs
; // 0: detect
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");
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 ////////////////////////////////////////////////////////////////////////////////
117 static const fl_loader_info_t rom_loader_info
= {
121 .accelFn
=emuTapeDoROMLoad
,
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
;
135 if (optDebugFlashLoad
) dbgSetActive(1);
138 cprintf("block not found!\n");
140 if (optDebugFlashLoad
) dbgSetActive(1);
145 int emuTapeFlashLoad (void) {
147 if (addr
== 0x0564) {
148 if (zxModel
== ZX_MACHINE_PLUS2A
|| zxModel
== ZX_MACHINE_PLUS3
) {
149 if (zxLastPagedROM
== 3) return executeLoader(addr
, &rom_loader_info
);
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
);