ugBASIC 1.18
An isomorphic BASIC language compiler for retrocomputers
Loading...
Searching...
No Matches
sidreloc.c
Go to the documentation of this file.
1/*****************************************************************************
2 * ugBASIC - an isomorphic BASIC language compiler for retrocomputers *
3 *****************************************************************************
4 * Copyright 2021-2024 Marco Spedaletti (asimov@mclink.it)
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *----------------------------------------------------------------------------
18 * Concesso in licenza secondo i termini della Licenza Apache, versione 2.0
19 * (la "Licenza"); è proibito usare questo file se non in conformità alla
20 * Licenza. Una copia della Licenza è disponibile all'indirizzo:
21 *
22 * http://www.apache.org/licenses/LICENSE-2.0
23 *
24 * Se non richiesto dalla legislazione vigente o concordato per iscritto,
25 * il software distribuito nei termini della Licenza è distribuito
26 * "COSÌ COM'È", SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO, esplicite o
27 * implicite. Consultare la Licenza per il testo specifico che regola le
28 * autorizzazioni e le limitazioni previste dalla medesima.
29 ****************************************************************************/
30
31#include <stdint.h>
32#include <assert.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <getopt.h>
37#include <math.h>
38#include <assert.h>
39#include <stdarg.h>
40
41#ifdef HAVE_ERR_H
42#include <err.h>
43#endif
44
45#ifndef HAVE_ERR
46#include <errno.h>
47#endif
48
49#ifndef HAVE_CONFIG_H
50#define RELEASE "1.0"
51#endif
52
56
57/* Represent bytes as 8-bit values tagged with meta-information. */
58/* List nodes (struct source) are arena-allocated; no need to track the references. */
59
60struct source {
61 struct source *next;
62 uint16_t offset;
63 uint8_t used;
64};
65
66typedef struct {
67 uint8_t value;
68 struct source *src;
69} value_t;
70
71struct core {
73 uint8_t read[65536]; // These (read/written) are booleans, but
74 uint8_t written[65536]; // kept separate for performance reasons.
75};
76
77struct progbyte {
78 uint8_t flags;
79 uint8_t zpaddr[32]; // one bit per address, little-endian
81};
82
83#define PBF_DONT_RELOC 0x01
84#define PBF_RELOC 0x02
85#define PBF_USED_IN_ZP 0x04
86#define PBF_USED_IN_MSB 0x08
87
88enum {
103};
104
105enum {
111};
112
113// moved here:
114static int progsize;
115static struct progbyte *progbytes;
116static int add_constraints;
117
118static char lastErrorString[1024];
119
120#ifndef HAVE_ERRX
121/* Some posix has not this standard, function (for ex. Haiku)
122 so, we define a roughly equivalente */
123static void errx(int eval, const char *fmt, ...){
124 va_list argptr;
125 va_start(argptr,fmt);
126 vsprintf(lastErrorString, fmt, argptr);
127 va_end(argptr);
128}
129#endif
130
131#ifndef HAVE_ERR
132/* Some posix has not this standard, function (for ex. Haiku)
133 so, we define a roughly equivalente */
134static void err(int eval, const char *fmt, ...){
135 fprintf(stderr, " %s: ", "sidreloc");
136 va_list argptr;
137 va_start(argptr,fmt);
138 vfprintf(stderr, fmt, argptr);
139 va_end(argptr);
140 fprintf(stderr, ": %s\n", strerror(errno));
141}
142#endif
143
144static struct source *cons_src(uint16_t car, struct source *cdr);
145static void check_reloc_range(uint16_t addr, struct source *lsb1, struct source *lsb2, struct source *msb);
146static void reloc_alike(value_t v1, value_t v2);
147static void used_for_zp_addr(struct source *src1, struct source *src2, uint8_t zpaddr);
148static void init_progbytes(uint16_t loadaddr, uint16_t loadsize);
149static int trivially_inconsistent();
150static int solver();
151static void free_arena();
152static void gc_arena(struct core *core);
153static void reloc_map(struct core *oldcore, uint16_t reloc_offs);
154static int emulate(struct core *core, uint16_t start_addr, uint8_t acc, int max_cycles);
155static void finalise_constraints(struct core *core);
156static void prealloc_cons_cells();
157
158static inline void dont_reloc_at(uint16_t offset) {
159 assert(offset != 1);
160 assert(offset < progsize + 2);
161 progbytes[offset].flags |= PBF_DONT_RELOC;
162}
163
164static inline void dont_reloc(struct source *src) {
165 if(add_constraints) {
166 while(src) {
167 dont_reloc_at(src->offset);
168 assert(src);
169 src = src->next;
170 }
171 }
172}
173
177
178/* Copyright (c) 2012 Linus Akesson
179 *
180 * Permission is hereby granted, free of charge, to any person obtaining a
181 * copy of this software and associated documentation files (the
182 * "Software"), to deal in the Software without restriction, including
183 * without limitation the rights to use, copy, modify, merge, publish,
184 * distribute, sublicense, and/or sell copies of the Software, and to
185 * permit persons to whom the Software is furnished to do so, subject to
186 * the following conditions:
187 *
188 * The above copyright notice and this permission notice shall be included
189 * in all copies or substantial portions of the Software.
190 *
191 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
192 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
193 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
194 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
195 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
196 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
197 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
198 */
199
200struct sidheader {
201 uint8_t rsid;
202 uint8_t nsubtune;
203 uint8_t defsubtune;
204 uint16_t version;
205 uint16_t dataoffset;
206 uint16_t loadaddr;
207 uint16_t loadsize;
208 uint16_t initaddr;
209 uint16_t playaddr;
210 char title[32];
211 char author[32];
212 char released[32];
213};
214
215static struct zeropage {
216 uint8_t link;
217 uint8_t reloc;
218 uint8_t free;
219} zeropage[256];
220
221#define RETF_OUTOFBOUNDS 0x20
222#define RETF_TOLERANCE 0x40
223
224static int cycles_init = 1000000;
225static int cycles_play = 20000;
226static int play_calls = 100000;
227static int nmi_calls = 200;
228static int cycles_nmi = 1000;
229
230static int do_zp_reloc = 1;
231static int verbose = 0;
232static int quiet = 0;
233static int force = 0;
234
235static uint16_t reloc_start;
236static uint16_t reloc_end;
237
238static int exitbits;
239static int nmi_reported;
240
241static struct core oldcore, newcore;
242
246
247/* Specialized 6510 emulator by Marco Spedaletti.
248 *
249 * Based on heavily modified 6510 emulator by Linus Akesson and
250 * on a proper 6502 emulator by Ian Piumarta, with the original copyright
251 * notice below. My modifications to this file are hereby provided under the
252 * same license, and the integration with ugBASIC is provided under the
253 * Apache License 2.0.
254 */
255
256/* Copyright (c) 2005 Ian Piumarta
257 *
258 * All rights reserved.
259 *
260 * Permission is hereby granted, free of charge, to any person obtaining a
261 * copy of this software and associated documentation files (the 'Software'),
262 * to deal in the Software without restriction, including without limitation
263 * the rights to use, copy, modify, merge, publish, distribute, and/or sell
264 * copies of the Software, and to permit persons to whom the Software is
265 * furnished to do so, provided that the above copyright notice(s) and this
266 * permission notice appear in all copies of the Software and that both the
267 * above copyright notice(s) and this permission notice appear in supporting
268 * documentation.
269 *
270 * THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
271 */
272
273typedef uint8_t byte;
274typedef uint16_t word;
275
276enum {
277 flagN= (1<<7), /* negative */
278 flagV= (1<<6), /* overflow */
279 flagX= (1<<5), /* unused */
280 flagB= (1<<4), /* irq from brk */
281 flagD= (1<<3), /* decimal mode */
282 flagI= (1<<2), /* irq disable */
283 flagZ= (1<<1), /* zero */
284 flagC= (1<<0) /* carry */
285};
286
287char *emulate_err[] = {
288 "BRK instruction",
289 "Internal CPU emulator error",
290 "Illegal opcode",
291 "Max cycles exhausted (infinite loop?)",
292};
293
294#define getN() (P & flagN)
295#define getV() (P & flagV)
296#define getB() (P & flagB)
297#define getD() (P & flagD)
298#define getI() (P & flagI)
299#define getZ() (P & flagZ)
300#define getC() (P & flagC)
301
302#define setNVZC(N,V,Z,C) (P= (P & ~(flagN | flagV | flagZ | flagC)) | (N) | ((V)<<6) | ((Z)<<1) | (C))
303#define setNZC(N,Z,C) (P= (P & ~(flagN | flagZ | flagC)) | (N) | ((Z)<<1) | (C))
304#define setNZ(N,Z) (P= (P & ~(flagN | flagZ )) | (N) | ((Z)<<1) )
305#define setZ(Z) (P= (P & ~( flagZ )) | ((Z)<<1) )
306#define setC(C) (P= (P & ~( flagC)) | (C))
307
308#define tick(n) if(max_cycles < n) return ERR_CYCLES; max_cycles -= n
309#ifdef ACCURATE_TIMING
310#define tickIf(p) if(p) { tick(1); }
311#else
312#define tickIf(p)
313#endif
314
315/* memory access -- ARGUMENTS ARE EVALUATED MORE THAN ONCE! */
316
317#define putMemory(ADDR, VALUE) \
318 memory[ADDR] = (VALUE); \
319 core->written[ADDR] = 1;
320
321#define getMemory(ADDR) (core->read[ADDR] = 1, memory[ADDR])
322
323/* stack access (always direct) */
324
325#define push(VALUE) (memory[0x0100 + S--] = (VALUE))
326#define pop() (memory[++S + 0x0100])
327
328/* adressing modes (memory access direct) */
329
330#define implied(ticks) \
331 tick(ticks);
332
333#define immediate(ticks) \
334 tick(ticks); \
335 src_ea_msb = src_pc_msb; \
336 ea = PC++;
337
338#define abs(ticks) \
339 tick(ticks); \
340 core->read[PC] = 1; \
341 core->read[PC + 1] = 1; \
342 src_ea_msb = memory[PC + 1].src; \
343 ea = memory[PC].value + (memory[PC + 1].value << 8); \
344 check_reloc_range(ea, memory[PC].src, 0, src_ea_msb); \
345 PC += 2;
346
347#define relative(ticks) \
348 tick(ticks); \
349 core->read[PC] = 1; \
350 dont_reloc(memory[PC].src); \
351 src_ea_msb = src_pc_msb; \
352 ea = memory[PC++].value; \
353 if (ea & 0x80) ea -= 0x100; \
354 tickIf((ea >> 8) != (PC >> 8));
355
356#define indirect(ticks) \
357 tick(ticks); \
358 { \
359 word tmp; \
360 core->read[PC] = 1; \
361 core->read[PC + 1] = 1; \
362 tmp = memory[PC].value + (memory[PC + 1].value << 8); \
363 check_reloc_range(tmp, memory[PC].src, 0, memory[PC + 1].src); \
364 core->read[tmp] = 1; \
365 core->read[tmp + 1] = 1; \
366 src_ea_msb = memory[tmp + 1].src; \
367 ea = memory[tmp].value + (memory[tmp + 1].value << 8); \
368 check_reloc_range(ea, memory[tmp].src, 0, src_ea_msb); \
369 PC += 2; \
370 }
371
372#define absx(ticks) \
373 tick(ticks); \
374 core->read[PC] = 1; \
375 core->read[PC + 1] = 1; \
376 src_ea_msb = memory[PC + 1].src; \
377 ea = memory[PC].value + (memory[PC + 1].value << 8); \
378 tickIf((ticks == 4) && ((ea >> 8) != ((ea + X.value) >> 8))); \
379 ea += X.value; \
380 check_reloc_range(ea, memory[PC].src, X.src, src_ea_msb); \
381 PC += 2;
382
383#define absy(ticks) \
384 tick(ticks); \
385 core->read[PC] = 1; \
386 core->read[PC + 1] = 1; \
387 src_ea_msb = memory[PC + 1].src; \
388 ea = memory[PC].value + (memory[PC + 1].value << 8); \
389 tickIf((ticks == 4) && ((ea >> 8) != ((ea + Y.value) >> 8))); \
390 ea += Y.value; \
391 check_reloc_range(ea, memory[PC].src, Y.src, src_ea_msb); \
392 PC += 2;
393
394#define zp(ticks) \
395 tick(ticks); \
396 core->read[PC] = 1; \
397 src_ea_msb = 0; \
398 ea = memory[PC].value; \
399 used_for_zp_addr(memory[PC].src, 0, ea); \
400 PC++;
401
402#define zpx(ticks) \
403 tick(ticks); \
404 core->read[PC] = 1; \
405 src_ea_msb = 0; \
406 ea = memory[PC].value + X.value; \
407 ea &= 0x00ff; \
408 used_for_zp_addr(memory[PC].src, X.src, ea); \
409 PC++;
410
411#define zpy(ticks) \
412 tick(ticks); \
413 core->read[PC] = 1; \
414 src_ea_msb = 0; \
415 ea = memory[PC].value + Y.value; \
416 ea &= 0x00ff; \
417 used_for_zp_addr(memory[PC].src, Y.src, ea); \
418 PC++;
419
420#define indx(ticks) \
421 tick(ticks); \
422 { \
423 byte tmp = memory[PC].value + X.value; \
424 core->read[PC] = 1; \
425 used_for_zp_addr(memory[PC].src, X.src, tmp); \
426 used_for_zp_addr(memory[PC].src, X.src, tmp + 1); \
427 core->read[tmp] = 1; \
428 core->read[tmp + 1] = 1; \
429 src_ea_msb = memory[tmp + 1].src; \
430 ea = memory[tmp].value + (memory[tmp + 1].value << 8); \
431 check_reloc_range(ea, memory[tmp].src, 0, src_ea_msb); \
432 PC++; \
433 }
434
435#define indy(ticks) \
436 tick(ticks); \
437 { \
438 byte tmp = memory[PC].value; \
439 core->read[PC] = 1; \
440 used_for_zp_addr(memory[PC].src, 0, tmp); \
441 used_for_zp_addr(memory[PC].src, 0, tmp + 1); \
442 PC++; \
443 core->read[tmp] = 1; \
444 core->read[tmp + 1] = 1; \
445 src_ea_msb = memory[tmp + 1].src; \
446 ea = memory[tmp].value + (memory[tmp + 1].value << 8); \
447 tickIf((ticks == 5) && ((ea >> 8) != ((ea + Y.value) >> 8))); \
448 ea += Y.value; \
449 check_reloc_range(ea, memory[tmp].src, Y.src, src_ea_msb); \
450 }
451
452/* insns */
453
454#define adc(ticks, adrmode) \
455 adrmode(ticks); \
456 { \
457 value_t B = getMemory(ea); \
458 if (!getD()) \
459 { \
460 struct source *src; \
461 int c = A.value + B.value + getC(); \
462 int v = (int8_t) A.value + (int8_t) B.value + getC(); \
463 fetch(); \
464 A.value = c; \
465 for(src = B.src; src; src = src->next) A.src = cons_src(src->offset, A.src); \
466 setNVZC((A.value & 0x80), (((A.value & 0x80) > 0) ^ (v < 0)), (A.value == 0), ((c & 0x100) > 0)); \
467 goto_next(); \
468 } \
469 else \
470 { \
471 int l, h, s; \
472 /* inelegant & slow, but consistent with the hw for illegal digits */ \
473 l = (A.value & 0x0F) + (B.value & 0x0F) + getC(); \
474 h = (A.value & 0xF0) + (B.value & 0xF0); \
475 if (l >= 0x0A) { l -= 0x0A; h += 0x10; } \
476 if (h >= 0xA0) { h -= 0xA0; } \
477 fetch(); \
478 s = h | (l & 0x0F); \
479 /* only C is valid on NMOS 6502 */ \
480 setNVZC(s & 0x80, !(((A.value ^ B.value) & 0x80) && ((A.value ^ s) & 0x80)), !s, !!(h & 0x80)); \
481 A.value = s; \
482 A.src = 0; \
483 tick(1); \
484 goto_next(); \
485 } \
486 }
487
488#define sbc(ticks, adrmode) \
489 adrmode(ticks); \
490 { \
491 value_t B = getMemory(ea); \
492 if (!getD()) \
493 { \
494 int b = 1 - (P &0x01); \
495 int c = A.value - B.value - b; \
496 int v = (int8_t) A.value - (int8_t) B.value - b; \
497 fetch(); \
498 A.value = c; \
499 setNVZC(A.value & 0x80, ((A.value & 0x80) > 0) ^ ((v & 0x100) != 0), A.value == 0, c >= 0); \
500 goto_next(); \
501 } \
502 else \
503 { \
504 /* this is verbatim ADC, with a 10's complemented operand */ \
505 int l, h, s; \
506 B.value = 0x99 - B.value; \
507 l = (A.value & 0x0F) + (B.value & 0x0F) + getC(); \
508 h = (A.value & 0xF0) + (B.value & 0xF0); \
509 if (l >= 0x0A) { l -= 0x0A; h += 0x10; } \
510 if (h >= 0xA0) { h -= 0xA0; } \
511 fetch(); \
512 s = h | (l & 0x0F); \
513 /* only C is valid on NMOS 6502 */ \
514 setNVZC(s & 0x80, !(((A.value ^ B.value) & 0x80) && ((A.value ^ s) & 0x80)), !s, !!(h & 0x80)); \
515 A.value = s; \
516 A.src = 0; \
517 tick(1); \
518 goto_next(); \
519 } \
520 }
521
522#define cmpR(ticks, adrmode, R) \
523 adrmode(ticks); \
524 fetch(); \
525 { \
526 value_t B = getMemory(ea); \
527 byte d = R.value - B.value; \
528 reloc_alike(B, R); \
529 setNZC(d & 0x80, !d, R.value >= B.value); \
530 } \
531 goto_next();
532
533#define cmp(ticks, adrmode) cmpR(ticks, adrmode, A)
534#define cpx(ticks, adrmode) cmpR(ticks, adrmode, X)
535#define cpy(ticks, adrmode) cmpR(ticks, adrmode, Y)
536
537#define dec(ticks, adrmode) \
538 adrmode(ticks); \
539 fetch(); \
540 { \
541 value_t B = getMemory(ea); \
542 --B.value; \
543 putMemory(ea, B); \
544 setNZ(B.value & 0x80, !B.value); \
545 } \
546 goto_next();
547
548#define decR(ticks, adrmode, R) \
549 fetch(); \
550 tick(ticks); \
551 --R.value; \
552 setNZ(R.value & 0x80, !R.value); \
553 goto_next();
554
555#define dex(ticks, adrmode) decR(ticks, adrmode, X)
556#define dey(ticks, adrmode) decR(ticks, adrmode, Y)
557
558#define inc(ticks, adrmode) \
559 adrmode(ticks); \
560 fetch(); \
561 { \
562 value_t B = getMemory(ea); \
563 ++B.value; \
564 putMemory(ea, B); \
565 setNZ(B.value & 0x80, !B.value); \
566 } \
567 goto_next();
568
569#define incR(ticks, adrmode, R) \
570 fetch(); \
571 tick(ticks); \
572 ++R.value; \
573 setNZ(R.value & 0x80, !R.value); \
574 goto_next();
575
576#define inx(ticks, adrmode) incR(ticks, adrmode, X)
577#define iny(ticks, adrmode) incR(ticks, adrmode, Y)
578
579#define bit(ticks, adrmode) \
580 adrmode(ticks); \
581 fetch(); \
582 { \
583 value_t B = getMemory(ea); \
584 P = (P & ~(flagN | flagV | flagZ)) \
585 | (B.value & (0xC0)) | (((A.value & B.value) == 0) << 1); \
586 } \
587 goto_next();
588
589#define eor(ticks, adrmode) \
590 adrmode(ticks); \
591 fetch(); \
592 { \
593 value_t b = getMemory(ea); \
594 reloc_alike(A, b); \
595 A.value ^= b.value; \
596 A.src = 0; \
597 } \
598 setNZ(A.value & 0x80, !A.value); \
599 goto_next();
600
601#define bitwise(ticks, adrmode, op) \
602 adrmode(ticks); \
603 fetch(); \
604 { \
605 value_t b = getMemory(ea); \
606 A.value op##= b.value; \
607 A.src = 0; \
608 } \
609 setNZ(A.value & 0x80, !A.value); \
610 goto_next();
611
612#define and(ticks, adrmode) bitwise(ticks, adrmode, &)
613#define ora(ticks, adrmode) bitwise(ticks, adrmode, |)
614
615#define asl(ticks, adrmode) \
616 adrmode(ticks); \
617 { \
618 value_t b = getMemory(ea); \
619 unsigned int i = b.value << 1; \
620 b.value = i; \
621 b.src = 0; \
622 putMemory(ea, b); \
623 fetch(); \
624 setNZC(i & 0x80, !i, i >> 8); \
625 } \
626 goto_next();
627
628#define asla(ticks, adrmode) \
629 tick(ticks); \
630 fetch(); \
631 { \
632 int c = A.value >> 7; \
633 A.value <<= 1; \
634 A.src = 0; \
635 setNZC(A.value & 0x80, !A.value, c); \
636 } \
637 goto_next();
638
639#define lsr(ticks, adrmode) \
640 adrmode(ticks); \
641 { \
642 value_t b = getMemory(ea); \
643 int c= b.value & 1; \
644 fetch(); \
645 b.value >>= 1; \
646 b.src = 0; \
647 putMemory(ea, b); \
648 setNZC(0, !b.value, c); \
649 } \
650 goto_next();
651
652#define lsra(ticks, adrmode) \
653 tick(ticks); \
654 fetch(); \
655 { \
656 int c = A.value & 1; \
657 A.value >>= 1; \
658 A.src = 0; \
659 setNZC(0, !A.value, c); \
660 } \
661 goto_next();
662
663#define rol(ticks, adrmode) \
664 adrmode(ticks); \
665 { \
666 value_t v = getMemory(ea); \
667 word b = (v.value << 1) | getC(); \
668 v.value = b; \
669 v.src = 0; \
670 fetch(); \
671 putMemory(ea, v); \
672 setNZC(b & 0x80, !(b & 0xFF), b >> 8); \
673 } \
674 goto_next();
675
676#define rola(ticks, adrmode) \
677 tick(ticks); \
678 fetch(); \
679 { \
680 word b = (A.value << 1) | getC(); \
681 A.value = b; \
682 A.src = 0; \
683 setNZC(A.value & 0x80, !A.value, b >> 8); \
684 } \
685 goto_next();
686
687#define ror(ticks, adrmode) \
688 adrmode(ticks); \
689 { \
690 int c = getC(); \
691 value_t m = getMemory(ea); \
692 value_t n; \
693 byte b = (c << 7) | (m.value >> 1); \
694 fetch(); \
695 n.value = b; \
696 n.src = 0; \
697 putMemory(ea, n); \
698 setNZC(b & 0x80, !b, m.value & 1); \
699 } \
700 goto_next();
701
702#define rora(ticks, adrmode) \
703 adrmode(ticks); \
704 { \
705 int ci = getC(); \
706 int co = A.value & 1; \
707 fetch(); \
708 A.value = (ci << 7) | (A.value >> 1); \
709 A.src = 0; \
710 setNZC(A.value & 0x80, !A.value, co); \
711 } \
712 goto_next();
713
714#define tRS(ticks, adrmode, R1, R2) \
715 fetch(); \
716 tick(ticks); \
717 R2 = R1; \
718 setNZ(R2.value & 0x80, !R1.value); \
719 goto_next();
720
721#define tax(ticks, adrmode) tRS(ticks, adrmode, A, X)
722#define txa(ticks, adrmode) tRS(ticks, adrmode, X, A)
723#define tay(ticks, adrmode) tRS(ticks, adrmode, A, Y)
724#define tya(ticks, adrmode) tRS(ticks, adrmode, Y, A)
725
726#define tsx(ticks, adrmode) \
727 fetch(); \
728 tick(ticks); \
729 X.value = S; \
730 X.src = 0; \
731 setNZ(S & 0x80, !S); \
732 goto_next();
733
734#define txs(ticks, adrmode) \
735 fetch(); \
736 tick(ticks); \
737 dont_reloc(X.src); \
738 S = X.value; \
739 goto_next();
740
741#define ldR(ticks, adrmode, R) \
742 adrmode(ticks); \
743 fetch(); \
744 R = getMemory(ea); \
745 setNZ(R.value & 0x80, !R.value); \
746 goto_next();
747
748#define lda(ticks, adrmode) ldR(ticks, adrmode, A)
749#define ldx(ticks, adrmode) ldR(ticks, adrmode, X)
750#define ldy(ticks, adrmode) ldR(ticks, adrmode, Y)
751
752#define stR(ticks, adrmode, R) \
753 adrmode(ticks); \
754 fetch(); \
755 putMemory(ea, R); \
756 goto_next();
757
758#define sta(ticks, adrmode) stR(ticks, adrmode, A)
759#define stx(ticks, adrmode) stR(ticks, adrmode, X)
760#define sty(ticks, adrmode) stR(ticks, adrmode, Y)
761
762#define branch(ticks, adrmode, cond) \
763 if (cond) \
764 { \
765 adrmode(ticks); \
766 PC += ea; \
767 tick(1); \
768 } \
769 else \
770 { \
771 tick(ticks); \
772 PC++; \
773 } \
774 fetch(); \
775 goto_next();
776
777#define bcc(ticks, adrmode) branch(ticks, adrmode, !getC())
778#define bcs(ticks, adrmode) branch(ticks, adrmode, getC())
779#define bne(ticks, adrmode) branch(ticks, adrmode, !getZ())
780#define beq(ticks, adrmode) branch(ticks, adrmode, getZ())
781#define bpl(ticks, adrmode) branch(ticks, adrmode, !getN())
782#define bmi(ticks, adrmode) branch(ticks, adrmode, getN())
783#define bvc(ticks, adrmode) branch(ticks, adrmode, !getV())
784#define bvs(ticks, adrmode) branch(ticks, adrmode, getV())
785
786#define jmp(ticks, adrmode) \
787 adrmode(ticks); \
788 PC = ea; \
789 src_pc_msb = src_ea_msb; \
790 fetch(); \
791 goto_next();
792
793#define jsr(ticks, adrmode) \
794 PC++; \
795 { \
796 value_t v; \
797 v.src = src_pc_msb; \
798 v.value = PC >> 8; \
799 push(v); \
800 v.src = 0; \
801 v.value = PC & 0xff; \
802 push(v); \
803 } \
804 PC--; \
805 adrmode(ticks); \
806 PC = ea; \
807 src_pc_msb = src_ea_msb; \
808 fetch(); \
809 goto_next();
810
811#define rts(ticks, adrmode) \
812 tick(ticks); \
813 if(S >= 0xfe) return ERR_OK; \
814 { \
815 value_t lsb = pop(); \
816 value_t msb = pop(); \
817 PC = lsb.value | (msb.value << 8); \
818 src_pc_msb = msb.src; \
819 check_reloc_range(PC, lsb.src, 0, msb.src); \
820 } \
821 PC++; \
822 fetch(); \
823 goto_next();
824
825#define brk(ticks, adrmode) \
826 tick(ticks); \
827 return ERR_BRK;
828
829#define rti(ticks, adrmode) \
830 tick(ticks); \
831 if(S >= 0xfd) return ERR_OK; \
832 { \
833 value_t status = pop(); \
834 value_t lsb = pop(); \
835 value_t msb = pop(); \
836 P = status.value; \
837 PC = lsb.value | (msb.value << 8); \
838 src_pc_msb = msb.src; \
839 dont_reloc(status.src); \
840 check_reloc_range(PC, lsb.src, 0, msb.src); \
841 } \
842 fetch(); \
843 goto_next();
844
845#define nop(ticks, adrmode) \
846 adrmode(ticks); \
847 fetch(); \
848 goto_next();
849
850#define ill(ticks, adrmode) \
851 goto illegal_instr;
852
853#define pha(ticks, adrmode) \
854 fetch(); \
855 tick(ticks); \
856 push(A); \
857 goto_next();
858
859#define php(ticks, adrmode) \
860 fetch(); \
861 tick(ticks); \
862 { \
863 value_t v; \
864 v.value = P; \
865 v.src = 0; \
866 push(v); \
867 } \
868 goto_next();
869
870#define pla(ticks, adrmode) \
871 fetch(); \
872 tick(ticks); \
873 if(S >= 0xff) return ERR_OK; \
874 A = pop(); \
875 setNZ(A.value & 0x80, !A.value); \
876 goto_next();
877
878#define plp(ticks, adrmode) \
879 fetch(); \
880 tick(ticks); \
881 if(S >= 0xff) return ERR_OK; \
882 { \
883 value_t v = pop(); \
884 dont_reloc(v.src); \
885 P = v.value; \
886 } \
887 goto_next();
888
889#define clF(ticks, adrmode, F) \
890 fetch(); \
891 tick(ticks); \
892 P &= ~F; \
893 goto_next();
894
895#define clc(ticks, adrmode) clF(ticks, adrmode, flagC)
896#define cld(ticks, adrmode) clF(ticks, adrmode, flagD)
897#define cli(ticks, adrmode) clF(ticks, adrmode, flagI)
898#define clv(ticks, adrmode) clF(ticks, adrmode, flagV)
899
900#define seF(ticks, adrmode, F) \
901 fetch(); \
902 tick(ticks); \
903 P |= F; \
904 goto_next();
905
906#define sec(ticks, adrmode) seF(ticks, adrmode, flagC)
907#define sed(ticks, adrmode) seF(ticks, adrmode, flagD)
908#define sei(ticks, adrmode) seF(ticks, adrmode, flagI)
909
910/* Beware! Instruction timing is wrong for the undocumented nops. */
911
912#define do_insns(_) \
913 _(00, brk, implied, 7); _(01, ora, indx, 6); _(02, ill, implied, 2); _(03, ill, implied, 2); \
914 _(04, nop, zp, 3); _(05, ora, zp, 3); _(06, asl, zp, 5); _(07, ill, implied, 2); \
915 _(08, php, implied, 3); _(09, ora, immediate, 3); _(0a, asla,implied, 2); _(0b, ill, implied, 2); \
916 _(0c, nop, abs, 4); _(0d, ora, abs, 4); _(0e, asl, abs, 6); _(0f, ill, implied, 2); \
917 _(10, bpl, relative, 2); _(11, ora, indy, 5); _(12, ill, implied, 3); _(13, ill, implied, 2); \
918 _(14, nop, zpx, 3); _(15, ora, zpx, 4); _(16, asl, zpx, 6); _(17, ill, implied, 2); \
919 _(18, clc, implied, 2); _(19, ora, absy, 4); _(1a, nop, implied, 2); _(1b, ill, implied, 2); \
920 _(1c, nop, absx, 4); _(1d, ora, absx, 4); _(1e, asl, absx, 7); _(1f, ill, implied, 2); \
921 _(20, jsr, abs, 6); _(21, and, indx, 6); _(22, ill, implied, 2); _(23, ill, implied, 2); \
922 _(24, bit, zp, 3); _(25, and, zp, 3); _(26, rol, zp, 5); _(27, ill, implied, 2); \
923 _(28, plp, implied, 4); _(29, and, immediate, 3); _(2a, rola,implied, 2); _(2b, ill, implied, 2); \
924 _(2c, bit, abs, 4); _(2d, and, abs, 4); _(2e, rol, abs, 6); _(2f, ill, implied, 2); \
925 _(30, bmi, relative, 2); _(31, and, indy, 5); _(32, ill, implied, 3); _(33, ill, implied, 2); \
926 _(34, nop, zpx, 4); _(35, and, zpx, 4); _(36, rol, zpx, 6); _(37, ill, implied, 2); \
927 _(38, sec, implied, 2); _(39, and, absy, 4); _(3a, nop, implied, 2); _(3b, ill, implied, 2); \
928 _(3c, nop, absx, 4); _(3d, and, absx, 4); _(3e, rol, absx, 7); _(3f, ill, implied, 2); \
929 _(40, rti, implied, 6); _(41, eor, indx, 6); _(42, ill, implied, 2); _(43, ill, implied, 2); \
930 _(44, nop, zp, 2); _(45, eor, zp, 3); _(46, lsr, zp, 5); _(47, ill, implied, 2); \
931 _(48, pha, implied, 3); _(49, eor, immediate, 3); _(4a, lsra,implied, 2); _(4b, ill, implied, 2); \
932 _(4c, jmp, abs, 3); _(4d, eor, abs, 4); _(4e, lsr, abs, 6); _(4f, ill, implied, 2); \
933 _(50, bvc, relative, 2); _(51, eor, indy, 5); _(52, ill, implied, 3); _(53, ill, implied, 2); \
934 _(54, nop, zpx, 2); _(55, eor, zpx, 4); _(56, lsr, zpx, 6); _(57, ill, implied, 2); \
935 _(58, cli, implied, 2); _(59, eor, absy, 4); _(5a, nop, implied, 3); _(5b, ill, implied, 2); \
936 _(5c, nop, absx, 2); _(5d, eor, absx, 4); _(5e, lsr, absx, 7); _(5f, ill, implied, 2); \
937 _(60, rts, implied, 6); _(61, adc, indx, 6); _(62, ill, implied, 2); _(63, ill, implied, 2); \
938 _(64, nop, zp, 3); _(65, adc, zp, 3); _(66, ror, zp, 5); _(67, ill, implied, 2); \
939 _(68, pla, implied, 4); _(69, adc, immediate, 3); _(6a, rora,implied, 2); _(6b, ill, implied, 2); \
940 _(6c, jmp, indirect, 5); _(6d, adc, abs, 4); _(6e, ror, abs, 6); _(6f, ill, implied, 2); \
941 _(70, bvs, relative, 2); _(71, adc, indy, 5); _(72, ill, implied, 3); _(73, ill, implied, 2); \
942 _(74, nop, zpx, 4); _(75, adc, zpx, 4); _(76, ror, zpx, 6); _(77, ill, implied, 2); \
943 _(78, sei, implied, 2); _(79, adc, absy, 4); _(7a, nop, implied, 4); _(7b, ill, implied, 2); \
944 _(7c, nop, absx, 6); _(7d, adc, absx, 4); _(7e, ror, absx, 7); _(7f, ill, implied, 2); \
945 _(80, nop, immediate, 2); _(81, sta, indx, 6); _(82, nop, immediate, 2); _(83, ill, implied, 2); \
946 _(84, sty, zp, 2); _(85, sta, zp, 2); _(86, stx, zp, 2); _(87, ill, implied, 2); \
947 _(88, dey, implied, 2); _(89, nop, immediate, 2); _(8a, txa, implied, 2); _(8b, ill, implied, 2); \
948 _(8c, sty, abs, 4); _(8d, sta, abs, 4); _(8e, stx, abs, 4); _(8f, ill, implied, 2); \
949 _(90, bcc, relative, 2); _(91, sta, indy, 6); _(92, ill, implied, 3); _(93, ill, implied, 2); \
950 _(94, sty, zpx, 4); _(95, sta, zpx, 4); _(96, stx, zpy, 4); _(97, ill, implied, 2); \
951 _(98, tya, implied, 2); _(99, sta, absy, 5); _(9a, txs, implied, 2); _(9b, ill, implied, 2); \
952 _(9c, ill, implied, 4); _(9d, sta, absx, 5); _(9e, ill, implied, 5); _(9f, ill, implied, 2); \
953 _(a0, ldy, immediate, 3); _(a1, lda, indx, 6); _(a2, ldx, immediate, 3); _(a3, ill, implied, 2); \
954 _(a4, ldy, zp, 3); _(a5, lda, zp, 3); _(a6, ldx, zp, 3); _(a7, ill, implied, 2); \
955 _(a8, tay, implied, 2); _(a9, lda, immediate, 3); _(aa, tax, implied, 2); _(ab, ill, implied, 2); \
956 _(ac, ldy, abs, 4); _(ad, lda, abs, 4); _(ae, ldx, abs, 4); _(af, ill, implied, 2); \
957 _(b0, bcs, relative, 2); _(b1, lda, indy, 5); _(b2, ill, implied, 3); _(b3, ill, implied, 2); \
958 _(b4, ldy, zpx, 4); _(b5, lda, zpx, 4); _(b6, ldx, zpy, 4); _(b7, ill, implied, 2); \
959 _(b8, clv, implied, 2); _(b9, lda, absy, 4); _(ba, tsx, implied, 2); _(bb, ill, implied, 2); \
960 _(bc, ldy, absx, 4); _(bd, lda, absx, 4); _(be, ldx, absy, 4); _(bf, ill, implied, 2); \
961 _(c0, cpy, immediate, 3); _(c1, cmp, indx, 6); _(c2, nop, immediate, 2); _(c3, ill, implied, 2); \
962 _(c4, cpy, zp, 3); _(c5, cmp, zp, 3); _(c6, dec, zp, 5); _(c7, ill, implied, 2); \
963 _(c8, iny, implied, 2); _(c9, cmp, immediate, 3); _(ca, dex, implied, 2); _(cb, ill, implied, 2); \
964 _(cc, cpy, abs, 4); _(cd, cmp, abs, 4); _(ce, dec, abs, 6); _(cf, ill, implied, 2); \
965 _(d0, bne, relative, 2); _(d1, cmp, indy, 5); _(d2, ill, implied, 3); _(d3, ill, implied, 2); \
966 _(d4, nop, zpx, 2); _(d5, cmp, zpx, 4); _(d6, dec, zpx, 6); _(d7, ill, implied, 2); \
967 _(d8, cld, implied, 2); _(d9, cmp, absy, 4); _(da, nop, implied, 3); _(db, ill, implied, 2); \
968 _(dc, nop, absx, 2); _(dd, cmp, absx, 4); _(de, dec, absx, 7); _(df, ill, implied, 2); \
969 _(e0, cpx, immediate, 3); _(e1, sbc, indx, 6); _(e2, nop, immediate, 2); _(e3, ill, implied, 2); \
970 _(e4, cpx, zp, 3); _(e5, sbc, zp, 3); _(e6, inc, zp, 5); _(e7, ill, implied, 2); \
971 _(e8, inx, implied, 2); _(e9, sbc, immediate, 3); _(ea, nop, implied, 2); _(eb, ill, implied, 2); \
972 _(ec, cpx, abs, 4); _(ed, sbc, abs, 4); _(ee, inc, abs, 6); _(ef, ill, implied, 2); \
973 _(f0, beq, relative, 2); _(f1, sbc, indy, 5); _(f2, ill, implied, 3); _(f3, ill, implied, 2); \
974 _(f4, nop, zpx, 2); _(f5, sbc, zpx, 4); _(f6, inc, zpx, 6); _(f7, ill, implied, 2); \
975 _(f8, sed, implied, 2); _(f9, sbc, absy, 4); _(fa, nop, implied, 4); _(fb, ill, implied, 2); \
976 _(fc, nop, absx, 2); _(fd, sbc, absx, 4); _(fe, inc, absx, 7); _(ff, ill, implied, 2);
977
978static int emulate(struct core *core, uint16_t start_addr, uint8_t acc, int max_cycles)
979{
980 static void *itab[256] = {
981 &&_00, &&_01, &&_02, &&_03, &&_04, &&_05, &&_06, &&_07, &&_08, &&_09, &&_0a, &&_0b, &&_0c, &&_0d, &&_0e, &&_0f,
982 &&_10, &&_11, &&_12, &&_13, &&_14, &&_15, &&_16, &&_17, &&_18, &&_19, &&_1a, &&_1b, &&_1c, &&_1d, &&_1e, &&_1f,
983 &&_20, &&_21, &&_22, &&_23, &&_24, &&_25, &&_26, &&_27, &&_28, &&_29, &&_2a, &&_2b, &&_2c, &&_2d, &&_2e, &&_2f,
984 &&_30, &&_31, &&_32, &&_33, &&_34, &&_35, &&_36, &&_37, &&_38, &&_39, &&_3a, &&_3b, &&_3c, &&_3d, &&_3e, &&_3f,
985 &&_40, &&_41, &&_42, &&_43, &&_44, &&_45, &&_46, &&_47, &&_48, &&_49, &&_4a, &&_4b, &&_4c, &&_4d, &&_4e, &&_4f,
986 &&_50, &&_51, &&_52, &&_53, &&_54, &&_55, &&_56, &&_57, &&_58, &&_59, &&_5a, &&_5b, &&_5c, &&_5d, &&_5e, &&_5f,
987 &&_60, &&_61, &&_62, &&_63, &&_64, &&_65, &&_66, &&_67, &&_68, &&_69, &&_6a, &&_6b, &&_6c, &&_6d, &&_6e, &&_6f,
988 &&_70, &&_71, &&_72, &&_73, &&_74, &&_75, &&_76, &&_77, &&_78, &&_79, &&_7a, &&_7b, &&_7c, &&_7d, &&_7e, &&_7f,
989 &&_80, &&_81, &&_82, &&_83, &&_84, &&_85, &&_86, &&_87, &&_88, &&_89, &&_8a, &&_8b, &&_8c, &&_8d, &&_8e, &&_8f,
990 &&_90, &&_91, &&_92, &&_93, &&_94, &&_95, &&_96, &&_97, &&_98, &&_99, &&_9a, &&_9b, &&_9c, &&_9d, &&_9e, &&_9f,
991 &&_a0, &&_a1, &&_a2, &&_a3, &&_a4, &&_a5, &&_a6, &&_a7, &&_a8, &&_a9, &&_aa, &&_ab, &&_ac, &&_ad, &&_ae, &&_af,
992 &&_b0, &&_b1, &&_b2, &&_b3, &&_b4, &&_b5, &&_b6, &&_b7, &&_b8, &&_b9, &&_ba, &&_bb, &&_bc, &&_bd, &&_be, &&_bf,
993 &&_c0, &&_c1, &&_c2, &&_c3, &&_c4, &&_c5, &&_c6, &&_c7, &&_c8, &&_c9, &&_ca, &&_cb, &&_cc, &&_cd, &&_ce, &&_cf,
994 &&_d0, &&_d1, &&_d2, &&_d3, &&_d4, &&_d5, &&_d6, &&_d7, &&_d8, &&_d9, &&_da, &&_db, &&_dc, &&_dd, &&_de, &&_df,
995 &&_e0, &&_e1, &&_e2, &&_e3, &&_e4, &&_e5, &&_e6, &&_e7, &&_e8, &&_e9, &&_ea, &&_eb, &&_ec, &&_ed, &&_ee, &&_ef,
996 &&_f0, &&_f1, &&_f2, &&_f3, &&_f4, &&_f5, &&_f6, &&_f7, &&_f8, &&_f9, &&_fa, &&_fb, &&_fc, &&_fd, &&_fe, &&_ff
997 };
998
1000
1001 void **itabp = itab;
1002 void *tpc;
1003
1004#if 0
1005#define dump() if(dump_enabled) fprintf(stderr, "pc=%04x op=%02x\n", PC, v.value)
1006#else
1007#define dump()
1008#endif
1009
1010# define fetch() { value_t v = memory[PC]; core->read[PC] = 1; dump(); PC++; dont_reloc(v.src); opcode = v.value; tpc = itabp[opcode]; }
1011# define goto_next() goto *tpc
1012# define dispatch(num, name, mode, cycles) _##num: name(cycles, mode) return ERR_INTERNAL;
1013
1014 word PC;
1015 word ea;
1016 value_t A, X, Y;
1017 byte P, S;
1018 byte opcode;
1019
1020 struct source *src_pc_msb = cons_src(1, 0);
1021 struct source *src_ea_msb;
1022
1023 PC = start_addr;
1024 A.value = acc;
1025 A.src = 0;
1026 X.value = 0;
1027 X.src = 0;
1028 Y.value = 0;
1029 Y.src = 0;
1030 P = 0;
1031 S = 0xff;
1032
1033 fetch();
1034 goto_next();
1035
1037
1038illegal_instr:
1039 // fprintf(stderr, "Illegal opcode: $%02x (PC = $%04x)\n", opcode, PC);
1040 return ERR_ILLEGAL;
1041}
1042
1046
1047/* Copyright (c) 2012 Linus Akesson
1048 *
1049 * Permission is hereby granted, free of charge, to any person obtaining a
1050 * copy of this software and associated documentation files (the
1051 * "Software"), to deal in the Software without restriction, including
1052 * without limitation the rights to use, copy, modify, merge, publish,
1053 * distribute, sublicense, and/or sell copies of the Software, and to
1054 * permit persons to whom the Software is furnished to do so, subject to
1055 * the following conditions:
1056 *
1057 * The above copyright notice and this permission notice shall be included
1058 * in all copies or substantial portions of the Software.
1059 *
1060 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1061 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1062 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1063 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1064 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1065 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1066 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1067 */
1068
1069
1070#define HASHSIZE 8192
1071
1072#define C_EXACTLY_ONE 1
1073#define C_ALIKE 2
1074
1077 uint8_t kind;
1078 uint16_t n1, n2;
1079 uint16_t vars[];
1080};
1081
1084 struct constraint *c;
1085};
1086
1087// static struct progbyte *progbytes;
1088// static int progsize;
1089static uint16_t progbyte_org;
1090
1091// static int add_constraints;
1092
1093static struct constraintlist *hashconstr[HASHSIZE], *zpconstr[0x100];
1094
1095#define ARENASIZE 32768
1096static struct arena {
1097 struct arena *next;
1098 struct source data[ARENASIZE];
1099} *arena;
1100static int arena_index = ARENASIZE;
1101
1102static struct source prealloc[0x10000];
1103
1104static int cmp_offset(const void *avoid, const void *bvoid) {
1105 const uint16_t *a = (const uint16_t *) avoid;
1106 const uint16_t *b = (const uint16_t *) bvoid;
1107 return *a - *b;
1108}
1109
1110static void print_constraint(struct constraint *constr) {
1111 int i;
1112
1113 if(constr->kind == C_EXACTLY_ONE) {
1114 fprintf(stderr, "Exactly one reloc: {");
1115 for(i = 0; i < constr->n1; i++) {
1116 fprintf(stderr, "%s$%04x", (i? ", " : ""), constr->vars[i] + progbyte_org);
1117 }
1118 fprintf(stderr, "}\n");
1119 } else if(constr->kind == C_ALIKE) {
1120 fprintf(stderr, "Reloc alike: {");
1121 for(i = 0; i < constr->n1; i++) {
1122 fprintf(stderr, "%s$%04x", (i? ", " : ""), constr->vars[i] + progbyte_org);
1123 }
1124 fprintf(stderr, "}, {");
1125 for(i = 0; i < constr->n2; i++) {
1126 fprintf(stderr, "%s$%04x", (i? ", " : ""), constr->vars[constr->n1 + i] + progbyte_org);
1127 }
1128 fprintf(stderr, "}\n");
1129 } else {
1130 fprintf(stderr, "Unknown constraint!\n");
1131 }
1132}
1133
1134static void add_constraint_ref(uint16_t offset, struct constraint *c) {
1135 struct progbyte *pb = &progbytes[offset];
1136 struct constraintlist *cl = malloc(sizeof(struct constraintlist));
1137
1138 cl->c = c;
1139 cl->next = pb->constr;
1140 pb->constr = cl;
1141}
1142
1143static int constrainthash(struct constraint *c) {
1144 int i, h = 0;
1145
1146 for(i = 0; i < c->n1 + c->n2; i++) {
1147 h += c->vars[i];
1148 h %= HASHSIZE;
1149 }
1150 return h;
1151}
1152
1153static void add_or_free_constraint(struct constraintlist **list, struct constraint *constr) {
1154 struct constraintlist *cl;
1155 int for_real = 0;
1156 int h;
1157
1158 if(constr->n1 > 1) qsort(constr->vars, constr->n1, sizeof(uint16_t), cmp_offset);
1159 if(constr->n2 > 1) qsort(constr->vars + constr->n1, constr->n2, sizeof(uint16_t), cmp_offset);
1160
1161 if(!list) {
1162 h = constrainthash(constr);
1163 list = &hashconstr[h];
1164 for_real = 1;
1165 }
1166
1167 for(cl = *list; cl; cl = cl->next) {
1168 if(cl->c->kind == constr->kind
1169 && cl->c->n1 == constr->n1
1170 && cl->c->n2 == constr->n2) {
1171 if(!memcmp(
1172 cl->c,
1173 constr,
1174 sizeof(struct constraint) + sizeof(uint16_t) * (constr->n1 + constr->n2)))
1175 {
1176 free(constr);
1177 return;
1178 }
1179 }
1180 }
1181
1182 if(for_real && verbose >= 2) {
1183 fprintf(stderr, "Adding constraint: ");
1184 print_constraint(constr);
1185 }
1186
1187 cl = malloc(sizeof(struct constraintlist));
1188 cl->c = constr;
1189 cl->next = *list;
1190 *list = cl;
1191}
1192
1193static void finalise_constraints(struct core *core) {
1194 int i, zp, h;
1195 struct constraintlist *cl, *nextcl;
1196 struct constraint *constr;
1197
1198 for(zp = 0; zp < 0x100; zp++) {
1199 if(core->written[zp]) {
1200 for(cl = zpconstr[zp]; cl; cl = nextcl) {
1201 nextcl = cl->next;
1202 add_or_free_constraint(0, cl->c);
1203 free(cl);
1204 }
1205 } else {
1206 for(cl = zpconstr[zp]; cl; cl = nextcl) {
1207 nextcl = cl->next;
1208 free(cl->c);
1209 free(cl);
1210 }
1211 }
1212 }
1213
1214 for(h = 0; h < HASHSIZE; h++) {
1215 for(cl = hashconstr[h]; cl; cl = cl->next) {
1216 constr = cl->c;
1217 for(i = 0; i < constr->n1 + constr->n2; i++) {
1218 add_constraint_ref(constr->vars[i], constr);
1219 }
1220 }
1221 }
1222}
1223
1224static int enforce_dont(uint16_t offset) {
1225 struct constraintlist *cl;
1226
1227 if(progbytes[offset].flags & PBF_RELOC) {
1228 return 1;
1229 } else if(!(progbytes[offset].flags & PBF_DONT_RELOC)) {
1230 progbytes[offset].flags |= PBF_DONT_RELOC;
1231 for(cl = progbytes[offset].constr; cl; cl = cl->next) {
1232 cl->c->check_needed = 1;
1233 }
1234 }
1235 return 0;
1236}
1237
1238static int enforce_do(uint16_t offset) {
1239 struct constraintlist *cl;
1240
1241 if(progbytes[offset].flags & PBF_DONT_RELOC) {
1242 return 1;
1243 } else if(!(progbytes[offset].flags & PBF_RELOC)) {
1244 progbytes[offset].flags |= PBF_RELOC;
1245 for(cl = progbytes[offset].constr; cl; cl = cl->next) {
1246 cl->c->check_needed = 1;
1247 }
1248 }
1249 return 0;
1250}
1251
1252static int propagate(struct constraint *c) {
1253 c->check_needed = 0;
1254
1255 if(c->kind == C_EXACTLY_ONE) {
1256 int i, n_do = 0, n_dont = 0, n_unknown = 0;
1257 int last_do = 0, last_unknown = 0;
1258
1259 for(i = 0; i < c->n1; i++) {
1260 struct progbyte *pb = &progbytes[c->vars[i]];
1261
1262 if(pb->flags & PBF_RELOC) {
1263 n_do++;
1264 last_do = i;
1265 } else if(pb->flags & PBF_DONT_RELOC) {
1266 n_dont++;
1267 } else {
1268 n_unknown++;
1269 last_unknown = i;
1270 }
1271 }
1272
1273 if(n_do == 1) {
1274 for(i = 0; i < c->n1; i++) {
1275 if(i != last_do) {
1276 if(enforce_dont(c->vars[i])) return 1;
1277 }
1278 }
1279 return 0;
1280 } else if(n_do > 1) {
1281 return 1;
1282 } else {
1283 // n_do == 0, exactly one of the unknown vars must be reloced
1284 if(n_unknown == 0) {
1285 return 1;
1286 } else if(n_unknown == 1) {
1287 return enforce_do(c->vars[last_unknown]);
1288 } else {
1289 // We cannot propagate; leave the rest to search.
1290 return 0;
1291 }
1292 }
1293 } else if(c->kind == C_ALIKE) {
1294 int i, n1_do = 0, n2_do = 0;
1295
1296 for(i = 0; i < c->n1; i++) {
1297 struct progbyte *pb = &progbytes[c->vars[i]];
1298
1299 if(pb->flags & PBF_RELOC) {
1300 n1_do++;
1301 }
1302 }
1303
1304 for(i = 0; i < c->n2; i++) {
1305 struct progbyte *pb = &progbytes[c->vars[i]];
1306
1307 if(pb->flags & PBF_RELOC) {
1308 n2_do++;
1309 }
1310 }
1311
1312 if(n1_do > 1 || n2_do > 1) return 1;
1313 return n1_do != n2_do;
1314 } else {
1315 return 1;
1316 }
1317}
1318
1319static int trivially_inconsistent() {
1320 int i;
1321
1322 for(i = 0; i < progsize + 2; i++) {
1323 struct progbyte *pb = &progbytes[i];
1324
1326 // If a byte contributes to both a zero-page address and an msb, it cannot
1327 // be relocatable.
1328 pb->flags |= PBF_DONT_RELOC;
1329 }
1330
1331 if((pb->flags & (PBF_RELOC | PBF_DONT_RELOC)) == (PBF_RELOC | PBF_DONT_RELOC)) {
1332 fprintf(stderr,
1333 "Inconsistency detected! Byte at $%04x can't be both relocated and not relocated at the same time.\n",
1334 i + progbyte_org);
1335 return 1;
1336 }
1337 }
1338
1339 return 0;
1340}
1341
1342static int solver() {
1343 struct constraintlist *cl;
1344 struct constraint *c;
1345 int done;
1346 int h, i, j;
1347 struct progbyte *pb = 0;
1348 int pboffs = 0;
1349
1350 /* Propagate. */
1351
1352 do {
1353 done = 1;
1354 for(h = 0; h < HASHSIZE; h++) {
1355 for(cl = hashconstr[h]; cl; cl = cl->next) {
1356 c = cl->c;
1357 if(c->check_needed) {
1358 done = 0;
1359 if(propagate(c)) return 1;
1360 }
1361 }
1362 }
1363 } while(!done);
1364
1365 /* Search -- select a variable */
1366
1367 for(h = 0; h < HASHSIZE && !pb; h++) {
1368 for(cl = hashconstr[h]; cl && !pb; cl = cl->next) {
1369 c = cl->c;
1370 for(i = 0; i < c->n1 + c->n2; i++) {
1371 if(!(progbytes[c->vars[i]].flags & (PBF_RELOC | PBF_DONT_RELOC))) {
1372 pboffs = c->vars[i];
1373 pb = &progbytes[pboffs];
1374 break;
1375 }
1376 }
1377 }
1378 }
1379
1380 if(pb) {
1381 /* Search -- select a value */
1382
1383 int btsize = progsize + 2;
1384 uint8_t *backtrack = malloc(btsize);
1385
1386 for(j = 0; j < btsize; j++) {
1387 backtrack[j] = progbytes[j].flags;
1388 }
1389
1390 if(verbose >= 2) {
1391 fprintf(stderr,
1392 "Guessing that $%04x should not be relocated.\n",
1393 pboffs + progbyte_org);
1394 }
1395
1396 if(enforce_dont(pboffs) || solver()) {
1397 if(verbose >= 2) {
1398 fprintf(stderr, "Backtracking.\n");
1399 }
1400 for(j = 0; j < btsize; j++) {
1401 progbytes[j].flags = backtrack[j];
1402 }
1403 free(backtrack);
1404 if(verbose >= 2) {
1405 fprintf(stderr,
1406 "Assuming that $%04x should be relocated.\n",
1407 pboffs + progbyte_org);
1408 }
1409 return enforce_do(pboffs) || solver();
1410 } else {
1411 free(backtrack);
1412 return 0;
1413 }
1414 } else return 0;
1415}
1416
1417/* Fast routines that are called during analysis (emulation). Contradictions are not
1418 * checked at this stage. */
1419
1420#if 0
1421void dont_reloc_at(uint16_t offset) {
1422 assert(offset < progsize + 2);
1423 progbytes[offset].flags |= PBF_DONT_RELOC;
1424}
1425
1426void dont_reloc(struct source *src) {
1427 if(add_constraints) {
1428 while(src) {
1429 dont_reloc_at(src->offset);
1430 assert(src);
1431 src = src->next;
1432 }
1433 }
1434}
1435#endif
1436
1437static void do_reloc_at(uint16_t offset) {
1438 progbytes[offset].flags |= PBF_RELOC;
1439}
1440
1441static void progbyte_for_zp(uint16_t offset, uint8_t zpaddr) {
1442 progbytes[offset].flags |= PBF_USED_IN_ZP;
1443 progbytes[offset].zpaddr[zpaddr >> 3] |= 1 << (zpaddr & 7);
1444}
1445
1446static void progbyte_for_msb(uint16_t offset) {
1447 progbytes[offset].flags |= PBF_USED_IN_MSB;
1448}
1449
1450static void prealloc_cons_cells() {
1451 int i;
1452
1453 for(i = 0; i < 0x10000; i++) {
1454 prealloc[i].offset = i;
1455 prealloc[i].next = 0;
1456 }
1457}
1458
1459static struct source *cons_src(uint16_t offset, struct source *cdr) {
1460 struct source *s;
1461
1462 if(add_constraints) {
1463 if(progbytes[offset].flags & PBF_DONT_RELOC) {
1464 // This progbyte can't possibly be relocatable, so
1465 // there's no need to add it to the list.
1466 return cdr;
1467 }
1468
1469 if(!cdr) {
1470 return &prealloc[offset];
1471 }
1472
1473 for(s = cdr; s; s = s->next) {
1474 if(s->offset == offset) {
1475 for(s = s->next; s; s = s->next) {
1476 if(s->offset == offset) {
1477 // No need to add the same program byte more
1478 // than twice to a list.
1479 return cdr;
1480 }
1481 }
1482 break;
1483 }
1484 }
1485
1486 if(arena_index >= ARENASIZE) {
1487 struct arena *a = calloc(sizeof(struct arena), 1);
1488 a->next = arena;
1489 arena = a;
1490 arena_index = 0;
1491 }
1492 s = &arena->data[arena_index++];
1493
1494 s->offset = offset;
1495 s->next = cdr;
1496 return s;
1497 } else {
1498 return 0;
1499 }
1500}
1501
1502static void gc_arena(struct core *core) {
1503 struct arena *a, **aptr;
1504 struct source *s;
1505 int i, count = 0;
1506
1507 if(arena) {
1508 for(a = arena->next; a; a = a->next) {
1509 for(i = 0; i < ARENASIZE; i++) {
1510 a->data[i].used = 0;
1511 }
1512 }
1513
1514 for(i = 0; i < 65536; i++) {
1515 for(s = core->memory[i].src; s; s = s->next) {
1516 s->used = 1;
1517 }
1518 }
1519
1520 for(aptr = &arena->next; *aptr; ) {
1521 a = *aptr;
1522 for(i = 0; i < ARENASIZE; i++) {
1523 if(a->data[i].used) break;
1524 }
1525 if(i == ARENASIZE) {
1526 count++;
1527 *aptr = a->next;
1528 free(a);
1529 } else {
1530 aptr = &a->next;
1531 }
1532 }
1533 }
1534
1535 if(verbose >= 3) {
1536 fprintf(stderr, "Reclaimed %d arenas.\n", count);
1537 }
1538}
1539
1540static void free_arena() {
1541 struct arena *a;
1542 int count = 0;
1543
1544 while((a = arena)) {
1545 arena = a->next;
1546 free(a);
1547 count++;
1548 }
1549 arena_index = ARENASIZE;
1550 if(verbose >= 3) fprintf(stderr, "Freed %d arenas.\n", count);
1551}
1552
1553static void reloc_exactly_one(struct source *src, uint8_t zpaddr) {
1554 int n_unknown = 0, n_dont = 0, n_do = 0;
1555 struct source *s, *s2;
1556 uint16_t last_do = 0, last_unknown = 0;
1557
1558 for(s = src; s; s = s->next) {
1559 for(s2 = s->next; s2; s2 = s2->next) {
1560 if(s->offset == s2->offset) {
1561 // The same progbyte contributes more than
1562 // once. It cannot be relocated.
1563 if(verbose >= 2) {
1564 fprintf(stderr,
1565 "Byte at $%04x contributes more than once to a sum and won't be relocated.\n",
1566 s->offset + progbyte_org);
1567 }
1568 dont_reloc_at(s->offset);
1569 }
1570 }
1571 }
1572
1573 for(s = src; s; s = s->next) {
1574 if(progbytes[s->offset].flags & PBF_DONT_RELOC) {
1575 n_dont++;
1576 } else if(progbytes[s->offset].flags & PBF_RELOC) {
1577 n_do++;
1578 last_do = s->offset;
1579 } else {
1580 n_unknown++;
1581 last_unknown = s->offset;
1582 }
1583 }
1584
1585 if(zpaddr) {
1586 struct constraint *constr;
1587 int pos = 0;
1588
1589 constr = malloc(sizeof(struct constraint) + sizeof(uint16_t) * (n_do + n_unknown));
1590 constr->check_needed = 1;
1591 constr->kind = C_EXACTLY_ONE;
1592 constr->n1 = n_do + n_unknown;
1593 constr->n2 = 0;
1594 for(s = src; s; s = s->next) {
1595 if(!(progbytes[s->offset].flags & PBF_DONT_RELOC)) {
1596 constr->vars[pos++] = s->offset;
1597 }
1598 }
1599 assert(pos == n_do + n_unknown);
1600
1601 add_or_free_constraint(&zpconstr[zpaddr], constr);
1602 } else {
1603 if(n_do) {
1604 // n_do is typically 1 here.
1605 // If n_do > 1, this will introduce an inconsistency which we can detect later.
1606 for(s = src; s; s = s->next) {
1607 if(s->offset != last_do) dont_reloc_at(s->offset);
1608 }
1609 } else {
1610 // n_do is 0, so one of the unknown vars must be relocated.
1611 if(n_unknown == 1) {
1612 do_reloc_at(last_unknown);
1613 } else if(n_unknown == 0) {
1614 fprintf(stderr, "Inconsistency: Want to relocate one of {");
1615 for(s = src; s; s = s->next) {
1616 fprintf(stderr, "$%04x%s", s->offset + progbyte_org, s->next? ", " : "");
1617 }
1618 fprintf(stderr, "} but this would contradict other equations.\n");
1619 // exit(RET_CONSTR);
1620 } else {
1621 struct constraint *constr;
1622 int pos = 0;
1623
1624 constr = malloc(sizeof(struct constraint) + sizeof(uint16_t) * n_unknown);
1625 constr->check_needed = 1;
1626 constr->kind = C_EXACTLY_ONE;
1627 constr->n1 = n_unknown;
1628 constr->n2 = 0;
1629 for(s = src; s; s = s->next) {
1630 if(!(progbytes[s->offset].flags & (PBF_RELOC | PBF_DONT_RELOC))) {
1631 constr->vars[pos++] = s->offset;
1632 }
1633 }
1634 assert(pos == n_unknown);
1635
1636 add_or_free_constraint(0, constr);
1637 }
1638 }
1639 }
1640}
1641
1642static void reloc_alike(value_t v1, value_t v2) {
1643 struct source *s;
1644
1645 if(add_constraints) {
1646 if(v1.value >= (reloc_start >> 8) && v1.value <= (reloc_end >> 8)
1647 && v2.value >= (reloc_start >> 8) && v2.value <= (reloc_end >> 8)) {
1648 struct constraint *constr;
1649 int n1 = 0, n2 = 0;
1650 int pos = 0;
1651
1652 for(s = v1.src; s; s = s->next) n1++;
1653 for(s = v2.src; s; s = s->next) n2++;
1654 constr = malloc(sizeof(struct constraint) + sizeof(uint16_t) * (n1 + n2));
1655
1656 constr->check_needed = 1;
1657 constr->kind = C_ALIKE;
1658 constr->n1 = n1;
1659 constr->n2 = n2;
1660 for(s = v1.src; s; s = s->next) {
1661 constr->vars[pos++] = s->offset;
1662 }
1663 for(s = v2.src; s; s = s->next) {
1664 constr->vars[pos++] = s->offset;
1665 }
1666 assert(pos == n1 + n2);
1667
1668 add_or_free_constraint(0, constr);
1669 }
1670 }
1671}
1672
1673static void used_for_zp_addr(struct source *src1, struct source *src2, uint8_t zpaddr) {
1674 struct source *s, *list;
1675
1676 if(add_constraints) {
1677 for(s = src1; s; s = s->next) progbyte_for_zp(s->offset, zpaddr);
1678 for(s = src2; s; s = s->next) progbyte_for_zp(s->offset, zpaddr);
1679
1680 if(do_zp_reloc) {
1681 list = src1;
1682 for(s = src2; s; s = s->next) list = cons_src(s->offset, list);
1683 reloc_exactly_one(list, zpaddr);
1684 }
1685 }
1686}
1687
1688static void check_reloc_range(uint16_t addr, struct source *lsb1, struct source *lsb2, struct source *msb) {
1689 if(add_constraints) {
1690 struct source *s;
1691
1692 for(s = msb; s; s = s->next) {
1693 progbyte_for_msb(s->offset);
1694 }
1695 if(addr >= reloc_start && addr <= reloc_end) {
1696 dont_reloc(lsb1);
1697 if(lsb2) dont_reloc(lsb2);
1698 reloc_exactly_one(msb, 0);
1699 } else if(addr < 0x100) {
1700 dont_reloc(msb);
1701 used_for_zp_addr(lsb1, lsb2, addr);
1702 } else {
1703 dont_reloc(msb);
1704 dont_reloc(lsb1);
1705 if(lsb2) dont_reloc(lsb2);
1706 }
1707 }
1708}
1709
1710static void init_progbytes(uint16_t loadaddr, uint16_t loadsize) {
1711 progbyte_org = loadaddr - 2;
1712 progsize = loadsize;
1713 progbytes = calloc(sizeof(struct progbyte), progsize + 2);
1714 progbytes[0].flags = PBF_DONT_RELOC;
1715 progbytes[1].flags = PBF_RELOC | PBF_USED_IN_MSB;
1716}
1717
1718static void reloc_map(struct core *oldcore, uint16_t reloc_offs) {
1719 int n_reloc = 0, n_zp = 0, n_dont = 0, n_unused = 0, n_unknown = 0;
1720 int i;
1721 int addr;
1722 uint16_t org;
1723
1724 fprintf(stderr, "Program map:");
1725 org = progbyte_org + 2;
1726 for(addr = org & 0xffc0; addr <= ((org + progsize - 1) | 0x003f); addr++) {
1727 if(!(addr & 0x3f)) {
1728 fprintf(stderr, "\n%04x, %04x: ", addr, (addr + reloc_offs) & 0xffff);
1729 }
1730 if(addr < org || addr >= org + progsize) {
1731 fprintf(stderr, " ");
1732 } else {
1733 i = addr - progbyte_org;
1734 if(progbytes[i].flags & PBF_RELOC) {
1735 if(progbytes[i].flags & PBF_USED_IN_MSB) {
1736 fprintf(stderr, "R");
1737 n_reloc++;
1738 } else if(progbytes[i].flags & PBF_USED_IN_ZP) {
1739 fprintf(stderr, "Z");
1740 n_zp++;
1741 } else {
1742 fprintf(stderr, "e"); // internal error
1743 }
1744 } else if(progbytes[i].flags & PBF_DONT_RELOC) {
1745 fprintf(stderr, "=");
1746 n_dont++;
1747 } else if(!(oldcore->read[addr] | oldcore->written[addr])) {
1748 fprintf(stderr, ".");
1749 n_unused++;
1750 } else {
1751 fprintf(stderr, "?");
1752 n_unknown++;
1753 }
1754 }
1755 }
1756 fprintf(stderr, "\n");
1757 fprintf(stderr, "MSB relocations (R): %d\n", n_reloc);
1758 fprintf(stderr, "Zero-page relocations (Z): %d\n", n_zp);
1759 fprintf(stderr, "Static bytes (=): %d\n", n_dont);
1760 fprintf(stderr, "Status undetermined (?): %d\n", n_unknown);
1761 fprintf(stderr, "Unused bytes (.): %d\n", n_unused);
1762}
1763
1767
1768static int readheader(struct sidheader *head, uint8_t *data, int filesize) {
1769 if(filesize <= 0x80) return 1;
1770 if(data[0] == 'P') {
1771 head->rsid = 0;
1772 } else if(data[0] == 'R') {
1773 head->rsid = 1;
1774 } else return 1;
1775 if(data[1] != 'S') return 1;
1776 if(data[2] != 'I') return 1;
1777 if(data[3] != 'D') return 1;
1778 head->version = (data[4] << 8) | data[5];
1779 if(head->version < 1 || head->version > 2) return 1;
1780 head->dataoffset = (data[6] << 8) | data[7];
1781 if(head->version == 1 && head->dataoffset != 0x76) return 1;
1782 if(head->version == 2 && head->dataoffset != 0x7c) return 1;
1783 head->loadaddr = (data[8] << 8) | data[9];
1784 if(!head->loadaddr) {
1785 head->loadaddr = data[head->dataoffset] | (data[head->dataoffset + 1] << 8);
1786 head->dataoffset += 2;
1787 }
1788 head->loadsize = filesize - head->dataoffset;
1789 if(head->loadaddr < 0x7e8 && head->rsid) errx(RET_RSID, "RSID standard violation");
1790 head->initaddr = (data[0x0a] << 8) | data[0x0b];
1791 if(!head->initaddr) head->initaddr = head->loadaddr;
1792 head->playaddr = (data[0x0c] << 8) | data[0x0d];
1793 head->nsubtune = (data[0x0e] << 8) | data[0x0f];
1794 head->defsubtune = (data[0x10] << 8) | data[0x11];
1795 memcpy(head->title, &data[0x16], sizeof(head->title));
1796 memcpy(head->author, &data[0x36], sizeof(head->author));
1797 memcpy(head->released, &data[0x56], sizeof(head->released));
1798 head->title[31] = 0;
1799 head->author[31] = 0;
1800 head->released[31] = 0;
1801 if(head->version > 1) {
1802 uint16_t flags = (data[0x76] << 8) | data[0x77];
1803 if(flags & 1) errx(RET_MUS, "MUS format not supported");
1804 if(head->rsid && (flags & 2)) errx(RET_BASIC, "BASIC tunes not supported");
1805 if(!head->rsid && (flags & 2)) errx(RET_PSID, "PSID tunes not supported");
1806 }
1807 return 0;
1808}
1809
1810static void init_core(struct core *core, uint8_t *data, uint16_t loadaddr, uint16_t loadsize) {
1811 int i;
1812
1813 memset(core->memory, 0, sizeof(core->memory));
1814
1815 for(i = 0xea31; i <= 0xea86; i++) {
1816 core->memory[i].value = 0x68; // pla
1817 }
1818
1819 for(i = 0; i < loadsize; i++) {
1820 core->memory[loadaddr + i].value = data[i];
1821 core->memory[loadaddr + i].src = cons_src(i + 2, 0);
1822 }
1823}
1824
1825static uint16_t get_from_vector(struct core *core, uint16_t fallback, uint16_t vaddr) {
1826 uint16_t vector = core->memory[vaddr].value | (core->memory[vaddr + 1].value << 8);
1827 if(vector) {
1828 check_reloc_range(vector, core->memory[vaddr].src, 0, core->memory[vaddr + 1].src);
1829 return vector;
1830 } else return fallback;
1831}
1832
1833static void init_tune(struct core *core, uint16_t initaddr, int tune) {
1834 int errcode = emulate(core, initaddr, tune, cycles_init);
1835 if(errcode == ERR_CYCLES) errx(RET_CYCLES | exitbits, "Max cycles exhausted during init routine. Infinite loop?");
1836 if(errcode) fprintf(stderr, "%s\n", emulate_err[errcode - 1]);
1837}
1838
1839static int play_step(struct core *core, uint16_t playaddr, char *errprefix) {
1840 int errcode;
1841 uint16_t digiaddr;
1842 int i;
1843 int allow_digi = 1;
1844
1845 playaddr = get_from_vector(core, playaddr, 0x0314);
1846 playaddr = get_from_vector(core, playaddr, 0xfffe);
1847
1848 if(!playaddr) {
1849 playaddr = get_from_vector(core, playaddr, 0x0318);
1850 playaddr = get_from_vector(core, playaddr, 0xfffa);
1851 allow_digi = 0;
1852 }
1853
1854 if(!playaddr) errx(RET_PLAYADDR, "%sCouldn't determine address of playroutine.", errprefix);
1855
1856 errcode = emulate(core, playaddr, 0, cycles_play);
1857 if(errcode == ERR_CYCLES && !force) {
1858 errx(RET_CYCLES | exitbits, "Max cycles exhausted during playroutine. Infinite loop?");
1859 }
1860 if(errcode) {
1861 fprintf(stderr, "%s%s\n", errprefix, emulate_err[errcode - 1]);
1862 } else if(allow_digi) {
1863 digiaddr = get_from_vector(core, 0, 0x0318);
1864 digiaddr = get_from_vector(core, digiaddr, 0xfffa);
1865 if(digiaddr) {
1866 if(!nmi_reported) {
1867 fprintf(stderr, "Use of digis detected. NMI routine will also be relocated.\n");
1868 nmi_reported = 1;
1869 }
1870 for(i = 0; i < nmi_calls; i++) {
1871 errcode = emulate(core, digiaddr, 0, cycles_nmi);
1872 if(errcode == ERR_CYCLES && !force) {
1873 errx(RET_CYCLES | exitbits, "Max cycles exhausted during NMI routine. Infinite loop?");
1874 }
1875 if(errcode) break;
1876 }
1877 }
1878 }
1879
1880 return errcode;
1881}
1882
1883static int verify_sidstate(value_t *oldmem, value_t *newmem, int frame, int *n_badpitch, int *n_badpw) {
1884 int i;
1885 int badp[3] = {0, 0, 0}, badpw[3] = {0, 0, 0};
1886
1887 for(i = 0; i < 29; i++) {
1888 if(oldmem[0xd400 + i].value != newmem[0xd400 + i].value) {
1889 if(i < 21 && (i % 7) < 2) {
1890 badp[i / 7] = 1;
1891 } else if(i < 21 && (i % 7) < 4) {
1892 badpw[i / 7] = 1;
1893 } else {
1894 fprintf(stderr, "Wrong SID state! ");
1895 if(frame >= 0) {
1896 fprintf(stderr, "At time %d, ", frame);
1897 } else {
1898 fprintf(stderr, "After the init routine, ");
1899 }
1900 fprintf(stderr, "$d4%02x should be $%02x, but the relocated code has written $%02x.\n",
1901 i,
1902 oldmem[0xd400 + i].value,
1903 newmem[0xd400 + i].value);
1904 if(!force) {
1905 return 0;
1906 }
1907 }
1908 }
1909 }
1910 *n_badpitch += badp[0] + badp[1] + badp[2];
1911 *n_badpw += badpw[0] + badpw[1] + badpw[2];
1912 return 1;
1913}
1914
1915static void zeropage_map() {
1916 int i;
1917
1918 fprintf(stderr, "Old zero-page addresses: ");
1919 for(i = 2; i < 256; i++) {
1920 if(oldcore.written[i]) fprintf(stderr, " %02x", i);
1921 }
1922 fprintf(stderr, "\nNew zero-page addresses: ");
1923 for(i = 2; i < 256; i++) {
1924 if(oldcore.written[i]) fprintf(stderr, " %02x", (i + zeropage[i].reloc) & 0xff);
1925 }
1926 fprintf(stderr, "\n");
1927}
1928
1929static void version() {
1930 printf("sidreloc " RELEASE "\n");
1931 printf("Created in 2012 by Linus Akesson.\n");
1932 printf("Contains a 6510 emulator based on lib6502 by Ian Piumarta.\n");
1933 printf("Project homepage: http://www.linusakesson.net/software/sidreloc/\n");
1934}
1935
1936static void usage() {
1937 printf("sidreloc " RELEASE " by Linus Akesson\n");
1938 printf("\n");
1939 printf("Usage: sidreloc [OPTIONS] input.sid output.sid\n");
1940 printf("\n");
1941 printf("Options:\n");
1942 printf("Short name Long name Default Description\n");
1943 printf("\n");
1944 printf(" -p --page 10 First memory page (in hex) to be occupied by\n");
1945 printf(" the relocated SID.\n");
1946 printf(" -z --zp-reloc 80-ff Range of free zero-page addresses that the\n");
1947 printf(" relocated SID can use.\n");
1948 printf(" -k --no-zp-reloc Keep all zero-page addresses as they appear\n");
1949 printf(" in the original SID.\n");
1950 printf(" -r --reloc (from SID) Range to relocate, e.g. \"50-5f\" for a 4 kB\n");
1951 printf(" SID originally located at $5000. Must include\n");
1952 printf(" the entire loading range of the SID.\n");
1953 printf("\n");
1954 printf(" -t --tolerance 2 Tolerance (in percent) for wrong pitches.\n");
1955 printf(" -s --strict Verify pulse widths.\n");
1956 printf(" -f --force Write output file even if verification fails.\n");
1957 printf("\n");
1958 printf(" -v --verbose Output some statistics and a nice map of all\n");
1959 printf(" the relocations.\n");
1960 printf(" -q --quiet Don't whine about writing out of bounds.\n");
1961 printf("\n");
1962 printf(" --frames 100000 Number of times to call the playroutine of\n");
1963 printf(" each subtune. The default corresponds to\n");
1964 printf(" approximately 33 minutes of a PAL tune.\n");
1965 printf(" --nmi-calls 200 Number of times to call the NMI routine per\n");
1966 printf(" frame (the CIA2 timer setting is ignored).\n");
1967 printf(" --init-cycles 1000000 Max number of clock cycles for init routine.\n");
1968 printf(" --play-cycles 20000 Max number of clock cycles for playroutine.\n");
1969 printf(" --nmi-cycles 1000 Max number of clock cycles for NMI routine.\n");
1970 printf("\n");
1971 printf(" -h --help Display this information.\n");
1972 printf(" -V --version Display brief version information and credits.\n");
1973 printf("\n");
1974 printf("Project homepage: http://www.linusakesson.net/software/sidreloc/\n");
1975 exit(0);
1976}
1977
1978static int readfile(uint8_t *data, char *filename) {
1979 int filesize;
1980 FILE *f = fopen(filename, "rb");
1981 if(!f) err(RET_IO, "%s", filename);
1982 filesize = fread(data, 1, 65536, f);
1983 fclose(f);
1984 return filesize;
1985}
1986
1987static void writefile(uint8_t *data, char *filename, int filesize) {
1988 FILE *f = fopen(filename, "wb");
1989 if(!f) err(RET_IO | exitbits, "%s", filename);
1990 if(fwrite(data, 1, filesize, f) != filesize) err(RET_IO | exitbits, "fwrite");
1991 fclose(f);
1992}
1993
1994static void report_oob(uint16_t first, uint16_t last) {
1995 if(!quiet && first != 0xd400) {
1996 if(first == last) {
1997 if ( verbose > 0 ) {
1998 fprintf(stderr, "Warning: Write out of bounds at address $%04x\n", first);
1999 }
2000 } else {
2001 if ( verbose > 0 ) {
2002 fprintf(stderr, "Warning: Write out of bounds at address $%04x-$%04x\n", first, last);
2003 }
2004 }
2005 }
2006}
2007
2008enum {
2014};
2015
2016static int first_zp = 0x80, last_zp = 0xff;
2017static int given_reloc_start = -1, given_reloc_end = -1;
2018static int dest_page = 0x10;
2019static int tolerance = 2;
2020static int strictpw = 0;
2021
2023 return lastErrorString;
2024}
2025
2026int sidreloc_set_page( int _page ) {
2027 if ( _page >= 0x00 && dest_page <= 0xff) {
2028 dest_page = _page;
2029 return 1;
2030 } else {
2031 errx(RET_PARAM, "SID relocation: invalid page number (should be in the range $00-$ff, 0..255)");
2032 return 0;
2033 }
2034}
2035
2036int sidreloc_set_page0( int _first, int _last ) {
2037 if ( _first >= 0x02 && _first <= 0xff &&
2038 _last >= 0x02 && _last <= 0xff &&
2039 _first <= _last ) {
2040 first_zp = _first;
2041 last_zp = _last;
2042 return 1;
2043 } else {
2044 errx(RET_PARAM, "Invalid zero-page address range (should be in the range $02-$ff, 0..255)");
2045 return 0;
2046 }
2047}
2048
2050 do_zp_reloc = 0;
2051 return 1;
2052}
2053
2054int sidreloc_set_reloc( int _start, int _end ) {
2055 if( _start >= 0x01 && _start <= 0xff &&
2056 _end >= 0x01 && _end <= 0xff &&
2057 _start <= _end ) {
2058 given_reloc_start = _start;
2059 given_reloc_end = _end;
2060 return 1;
2061 } else {
2062 errx(RET_PARAM, "Invalid relocation range (should be in the range $01-$ff, 2..255)");
2063 return 0;
2064 }
2065}
2066
2067int sidreloc_set_tolerance( int _tolerance ) {
2068 if ( _tolerance >= 0 && _tolerance < 100) {
2069 tolerance = _tolerance;
2070 return 1;
2071 } else {
2072 errx(RET_PARAM, "Invalid tolerance percentage (should be in the range 0-100)");
2073 return 0;
2074 }
2075}
2076
2078 strictpw = 1;
2079 return 1;
2080}
2081
2083 force = 1;
2084 return 1;
2085}
2086
2087int sidreloc_set_verbosity( int _verbose ) {
2088 verbose = _verbose;
2089 return 1;
2090}
2091
2093 quiet = 1;
2094 return 1;
2095}
2096
2097int sidreloc_set_frames( int _frames ) {
2098 if ( _frames >= 0 ) {
2099 play_calls = _frames;
2100 return 1;
2101 } else {
2102 errx(RET_PARAM, "Invalid number of calls to the playroutine.");
2103 return 0;
2104 }
2105}
2106
2107int sidreloc_set_init_cycles( int _cycles ) {
2108 if ( _cycles >= 0 ) {
2109 cycles_init = _cycles;
2110 return 1;
2111 } else {
2112 errx(RET_PARAM, "Invalid cycle limit for the init routine.");
2113 return 0;
2114 }
2115}
2116
2117int sidreloc_set_play_cycles( int _cycles ) {
2118 if ( _cycles >= 0 ) {
2119 cycles_play = _cycles;
2120 return 1;
2121 } else {
2122 errx(RET_PARAM, "Invalid cycle limit for the playroutine.");
2123 return 0;
2124 }
2125}
2126
2127int sidreloc_set_nmi_cycles( int _cycles ) {
2128 if ( _cycles >= 0 ) {
2129 cycles_nmi = _cycles;
2130 return 1;
2131 } else {
2132 errx(RET_PARAM, "Invalid cycle limit for the NMI routine.");
2133 return 0;
2134 }
2135}
2136
2137int sidreloc_set_nmi_calls( int _cycles ) {
2138 if ( _cycles >= 0 ) {
2139 nmi_calls = _cycles;
2140 return 1;
2141 } else {
2142 errx(RET_PARAM, "Invalid number of calls to the NMI routine.");
2143 return 0;
2144 }
2145}
2146
2147static uint8_t * data;
2148static uint8_t * newdata;
2149static int filesize;
2150
2151int sidreloc_set_input_data( unsigned char * _data, int _size ) {
2152 data = _data;
2153 filesize = _size;
2154 return 0;
2155}
2156
2157int sidreloc_set_output_data( unsigned char * _data ) {
2158 newdata = _data;
2159 return 0;
2160}
2161
2163 int i, j, k, errcode, opt;
2164 struct sidheader head;
2165 uint16_t reloc_offset;
2166 uint8_t page_used[256];
2167 int n_check = 0, n_badpitch = 0, n_badpw = 0;
2168 int perc_badpitch, perc_badpw;
2169 uint16_t ooblast, oobchunk;
2170
2171 /* Read the SID file. */
2172
2173 // filesize = readfile(data, filename);
2174 if(readheader(&head, data, filesize)) {
2175 errx(RET_HEADER, "Bad SID file header");
2176 return 0;
2177 }
2178 if(verbose > 0) {
2179 fprintf(stdout, "%s, %s, %s, $%04x-$%04x, %d subtunes\n",
2180 head.title,
2181 head.author,
2182 head.released,
2183 head.loadaddr,
2184 head.loadaddr + head.loadsize - 1,
2185 head.nsubtune);
2186 }
2187
2188 /* Determine the relocation area. */
2189
2190 reloc_start = head.loadaddr & 0xff00;
2191 reloc_end = (head.loadaddr + head.loadsize - 1) | 0x00ff;
2192
2193 for(i = 0; i < 64 && reloc_end != 0xcfff && reloc_end != 0xffff; i++) {
2194 reloc_end += 0x100;
2195 }
2196
2197 if(given_reloc_start >= 0) {
2198 reloc_start = given_reloc_start << 8;
2199 reloc_end = (given_reloc_end << 8) | 0xff;
2200 if(reloc_start > head.loadaddr
2201 || reloc_end < (head.loadaddr + head.loadsize - 1)) {
2202 errx(RET_RANGE,
2203 "Relocation range (-r) must contain all the SID data! (SID loads at $%04x-$%04x)",
2204 head.loadaddr,
2205 head.loadaddr + head.loadsize - 1);
2206 return 0;
2207 }
2208 }
2209
2210 reloc_offset = (dest_page << 8) - reloc_start;
2211
2212 if ( verbose > 0 ) {
2213 fprintf(stdout, "Relocating from $%04x-$%04x to $%04x-$%04x\n",
2214 reloc_start,
2215 reloc_end,
2216 (reloc_start + reloc_offset) & 0xffff,
2217 (reloc_end + reloc_offset) & 0xffff);
2218 }
2219
2220 if(reloc_start < 0x100 || reloc_end < reloc_start
2221 || ((reloc_start + reloc_offset) & 0xffff) < 0x100
2222 || ((reloc_end + reloc_offset) & 0xffff) < ((reloc_start + reloc_offset) & 0xffff)) {
2223 errx(RET_RANGE, "Neither the source nor the destination relocation range may overlap with the zero-page.");
2224 return 0;
2225 }
2226
2227 prealloc_cons_cells();
2228
2229 /* Visit all subtunes. */
2230
2231 init_progbytes(head.loadaddr, head.loadsize);
2232 add_constraints = 1;
2233
2234 for(i = 0; i < head.nsubtune; i++) {
2235 if ( verbose > 0 ) {
2236 fprintf(stderr, "Analysing subtune %d\n", i + 1);
2237 }
2238 nmi_reported = 0;
2239 init_core(&oldcore, &data[head.dataoffset], head.loadaddr, head.loadsize);
2240 init_tune(&oldcore, head.initaddr, i);
2241 for(j = 0; j < play_calls; j++) {
2242 if(play_step(&oldcore, head.playaddr, "")) break;
2243 }
2244 gc_arena(&oldcore);
2245 }
2246
2247 /* Report bad memory accesses, possibly remove some zero-page addresses from the constraints. */
2248
2249 oobchunk = ooblast = 0xd400;
2250 for(i = 0; i < 65536; i++) {
2251 if(i >= head.loadaddr && i < head.loadaddr + head.loadsize) {
2252 /* Inside tune, ok */
2253 } else if(i >= 0xd400 && i <= 0xd41f) {
2254 /* SID register area, ok */
2255 } else if(i >= 2 && i < 0x100) {
2256 if(oldcore.read[i] && !oldcore.written[i]) {
2257 if(!quiet) {
2258 if ( verbose > 0 ) {
2259 fprintf(stderr,
2260 "Warning: Zero-page address $%02x read but never written.%s\n",
2261 i,
2262 (do_zp_reloc? " Not relocating it." : ""));
2263 }
2264 }
2265 for(j = 0; j < progsize; j++) {
2266 struct progbyte *pb = &progbytes[j + 2];
2267 if((pb->flags & PBF_USED_IN_ZP) && pb->zpaddr[i >> 3] & (1 << (i & 7))) {
2268 pb->zpaddr[i >> 3] &= ~(1 << (i & 7));
2269 for(k = 0; k < 32; k++) if(pb->zpaddr[k]) break;
2270 if(k == 32) pb->flags &= ~(PBF_RELOC | PBF_USED_IN_ZP);
2271 }
2272 }
2273 }
2274 } else {
2275 if(oldcore.written[i]) {
2276 exitbits |= RETF_OUTOFBOUNDS;
2277 if(ooblast != i - 1) {
2278 report_oob(oobchunk, ooblast);
2279 oobchunk = i;
2280 }
2281 ooblast = i;
2282 }
2283 }
2284 }
2285 report_oob(oobchunk, ooblast);
2286
2287 finalise_constraints(&oldcore);
2288
2289 /* Find a solution to the set of constraints. */
2290
2291 if(trivially_inconsistent() || solver()) {
2292 errx(RET_CONSTR | exitbits, "No solution found");
2293 return 0;
2294 }
2295
2296 /* Map the zero-page addresses to new locations. */
2297
2298 for(i = 0; i < 256; i++) {
2299 zeropage[i].link = i;
2300 zeropage[i].free = (i >= first_zp && i <= last_zp);
2301 }
2302
2303 for(i = 0; i < progsize; i++) {
2304 struct progbyte *pb = &progbytes[i + 2];
2305 if((pb->flags & (PBF_RELOC | PBF_USED_IN_ZP)) == (PBF_RELOC | PBF_USED_IN_ZP)) {
2306 int first = -1;
2307 for(j = 0; j < 256; j++) {
2308 if(pb->zpaddr[j >> 3] & (1 << (j & 7))) {
2309 if(first != -1) {
2310 // One relocated program byte contributes to
2311 // several zero-page addresses. Link them.
2312 if(zeropage[j].link > zeropage[first].link) {
2313 zeropage[j].link = zeropage[first].link;
2314 } else {
2315 zeropage[first].link = zeropage[j].link;
2316 }
2317 } else {
2318 first = j;
2319 }
2320 }
2321 }
2322 }
2323 }
2324
2325 for(i = 0; i < 256; i++) {
2326 if(zeropage[i].link != zeropage[zeropage[i].link].link) {
2327 zeropage[i].link = zeropage[zeropage[i].link].link;
2328 }
2329 }
2330
2331 if(do_zp_reloc) {
2332 int chunk, dest;
2333
2334 for(chunk = 2; chunk < 0x100; chunk++) {
2335 if(oldcore.written[chunk] && (zeropage[chunk].link == chunk)) {
2336 // We have a chunk to place somewhere.
2337 for(dest = first_zp; dest <= last_zp; dest++) {
2338 // Try to put it at dest.
2339 for(i = chunk; i < 0x100; i++) {
2340 if(zeropage[i].link == chunk) {
2341 if(!zeropage[(dest + i - chunk) & 0xff].free) {
2342 break;
2343 }
2344 }
2345 }
2346 if(i == 0x100) {
2347 // It fits!
2348 for(i = chunk; i < 0x100; i++) {
2349 if(zeropage[i].link == chunk) {
2350 zeropage[i].reloc = dest - chunk;
2351 zeropage[dest + i - chunk].free = 0;
2352 }
2353 }
2354 break;
2355 }
2356 }
2357 if(dest > last_zp) {
2358 errx(RET_ZPFULL | exitbits,
2359 "Can't fit all zero-page addresses into specified range ($%02x-$%02x).",
2360 first_zp,
2361 last_zp);
2362 return 0;
2363 }
2364 }
2365 }
2366 }
2367
2368 /* Draw a map. */
2369
2370 if(verbose >= 1) {
2371 reloc_map(&oldcore, reloc_offset);
2372 zeropage_map();
2373 }
2374
2375 /* Perform the relocation. */
2376
2377 memcpy(newdata, data, filesize);
2378 for(i = 0; i < progsize; i++) {
2379 struct progbyte *pb = &progbytes[i + 2];
2380 if(pb->flags & PBF_RELOC) {
2381 if(pb->flags & PBF_USED_IN_MSB) {
2382 newdata[head.dataoffset + i] += reloc_offset >> 8;
2383 } else {
2384 for(j = 2; j < 256; j++) {
2385 if(pb->zpaddr[j / 8] & (1 << (j & 7))) {
2386 break;
2387 }
2388 }
2389 if(j < 256) {
2390 newdata[head.dataoffset + i] += zeropage[j].reloc;
2391 }
2392 }
2393 }
2394 }
2395
2396 /* Verify the relocated subtunes. */
2397
2398 free_arena();
2399 free(progbytes);
2400 progbytes = 0;
2401 add_constraints = 0;
2402
2403 for(i = 0; i < head.nsubtune; i++) {
2404 if ( verbose > 0 ) {
2405 fprintf(stderr, "Verifying relocated subtune %d\n", i + 1);
2406 }
2407 init_core(&oldcore, &data[head.dataoffset], head.loadaddr, head.loadsize);
2408 init_core(&newcore, &newdata[head.dataoffset], (head.loadaddr + reloc_offset) & 0xffff, head.loadsize);
2409
2410 init_tune(&oldcore, head.initaddr, i);
2411
2412 reloc_start += reloc_offset;
2413 reloc_end += reloc_offset;
2414
2415 init_tune(&newcore, (head.initaddr + reloc_offset) & 0xffff, i);
2416
2417 n_check += 3;
2418 if ( !verify_sidstate(oldcore.memory, newcore.memory, -1, &n_badpitch, &n_badpw) ) {
2419 return 0;
2420 }
2421
2422 for(j = 0; j < play_calls; j++) {
2423 reloc_start -= reloc_offset;
2424 reloc_end -= reloc_offset;
2425
2426 errcode = play_step(&oldcore, head.playaddr, "Old version: ");
2427 if(errcode) break;
2428
2429 reloc_start += reloc_offset;
2430 reloc_end += reloc_offset;
2431
2432 errcode = play_step(&newcore, (head.playaddr? ((head.playaddr + reloc_offset) & 0xffff) : 0), "New version: ");
2433 if(errcode) {
2434 if(force) {
2435 break;
2436 } else {
2437 errx(RET_VERIFY | exitbits, "Verification failed");
2438 return 0;
2439 }
2440 }
2441
2442 n_check += 3;
2443 if ( ! verify_sidstate(oldcore.memory, newcore.memory, j, &n_badpitch, &n_badpw) ) {
2444 return 0;
2445 }
2446 }
2447
2448 reloc_start -= reloc_offset;
2449 reloc_end -= reloc_offset;
2450 }
2451
2452 if(!n_check) n_check = 1;
2453 perc_badpitch = round(n_badpitch * 100.0 / n_check);
2454 perc_badpw = round(n_badpw * 100.0 / n_check);
2455 if ( verbose > 0 ) {
2456 fprintf(stderr, "Bad pitches: %d, %d%%\n", n_badpitch, perc_badpitch);
2457 fprintf(stderr, "Bad pulse widths: %d, %d%%\n", n_badpw, perc_badpw);
2458 }
2459 if(n_badpitch || n_badpw) {
2460 exitbits |= RETF_TOLERANCE;
2461 if(!force) {
2462 if(n_badpitch && (!tolerance || (perc_badpitch > tolerance))) {
2463 errx(RET_VERIFY | exitbits, "Relocation failed; too many mismatching pitches.\n");
2464 return 0;
2465 } else if(n_badpw && strictpw) {
2466 errx(RET_VERIFY | exitbits, "Relocation failed; mismatching pulse widths and strict flag given.\n");
2467 return 0;
2468 }
2469 }
2470 }
2471 // if(n_badpitch) {
2472 // fprintf(stderr, "Relocation successful with some mismatching pitches.\n");
2473 // } else if(n_badpw) {
2474 // fprintf(stderr, "Relocation successful with some mismatching pulse widths.\n");
2475 // } else {
2476 // fprintf(stderr, "Relocation successful.\n");
2477 // }
2478
2479 /* Relocate all pointers in the header. */
2480
2481 if(newdata[0x08] | newdata[0x09]) {
2482 newdata[0x08] += reloc_offset >> 8;
2483 } else {
2484 newdata[head.dataoffset - 1] += reloc_offset >> 8;
2485 }
2486 if(newdata[0x0a] | newdata[0x0b]) {
2487 newdata[0x0a] += reloc_offset >> 8;
2488 }
2489 if(newdata[0x0c] | newdata[0x0d]) {
2490 newdata[0x0c] += reloc_offset >> 8;
2491 }
2492
2493 /* Determine where replayer code could go. */
2494
2495 memset(page_used, 0, sizeof(page_used));
2496 if(head.version > 1) {
2497 int best_start, best_n, curr_start, curr_n;
2498
2499 for(i = 0; i < 256; i++) {
2500 if((i >= 0x00 && i <= 0x03)
2501 || (i >= 0xa0 && i <= 0xbf)
2502 || (i >= 0xd0 && i <= 0xff)
2503 || (i >= (((head.loadaddr + reloc_offset) & 0xffff) >> 8)
2504 && i <= (((head.loadaddr + head.loadsize - 1 + reloc_offset) & 0xffff) >> 8))) {
2505 page_used[i] = 1;
2506 } else {
2507 for(j = 0; j < 256; j++) {
2508 if(newcore.read[(i << 8) | j]
2509 || newcore.written[(i << 8) | j]) {
2510 page_used[i] = 1;
2511 break;
2512 }
2513 }
2514 }
2515 }
2516 best_start = curr_start = 0;
2517 best_n = curr_n = 0;
2518 for(i = 0; i < 256; i++) {
2519 if(page_used[i]) {
2520 if(curr_n > best_n) {
2521 best_start = curr_start;
2522 best_n = curr_n;
2523 }
2524 curr_start = i + 1;
2525 curr_n = 0;
2526 } else {
2527 curr_n++;
2528 }
2529 }
2530 if(curr_n > best_n) {
2531 best_start = curr_start;
2532 best_n = curr_n;
2533 }
2534 if(best_n) {
2535 if(verbose >= 1) {
2536 fprintf(stdout,
2537 "Largest unused region: $%02x00-$%02xff\n",
2538 best_start,
2539 best_start + best_n - 1);
2540 }
2541 newdata[0x78] = best_start;
2542 newdata[0x79] = best_n;
2543 } else {
2544 if(verbose >= 1) {
2545 fprintf(stdout, "No space left for replay routine!\n");
2546 }
2547 newdata[0x78] = 0xff;
2548 newdata[0x79] = 0;
2549 }
2550 }
2551
2552 /* Write the relocated SID file. */
2553
2554 //writefile(newdata, outputname, filesize);
2555
2556 // return RET_SUCCESS | exitbits;
2557
2558 return 1;
2559
2560}
2561
2562// #ifndef HAVE_ERRX
2563// /* Some posix has not this standard, function (for ex. Haiku)
2564// so, we define a roughly equivalente */
2565// static void errx(int eval, const char *fmt, ...){
2566// fprintf(stderr,"%s: ", "sidreloc");
2567// fprintf(stderr,fmt, ...);
2568// fprintf(stderr,"\n");
2569// exit(eval);
2570// }
2571// #endif
2572
2573// #ifndef HAVE_ERR
2574// /* Some posix has not this standard, function (for ex. Haiku)
2575// so, we define a roughly equivalente */
2576// static void err(int eval, const char *fmt, ...){
2577// fprintf(stderr, " %s: ", "sidreloc");
2578// fprintf(stderr, fmt, ...);
2579// fprintf(stderr, ": %s\n", strerror(errno));
2580// exit(eval);
2581// }
2582// #endif
2583
int flags
Definition _optimizer.c:677
int offset
Definition _optimizer.c:681
#define goto_next()
#define C_ALIKE
Definition sidreloc.c:1073
@ flagZ
Definition sidreloc.c:283
@ flagX
Definition sidreloc.c:279
@ flagC
Definition sidreloc.c:284
@ flagB
Definition sidreloc.c:280
@ flagI
Definition sidreloc.c:282
@ flagD
Definition sidreloc.c:281
@ flagN
Definition sidreloc.c:277
@ flagV
Definition sidreloc.c:278
#define HASHSIZE
Definition sidreloc.c:1070
#define zp(ticks)
Definition sidreloc.c:394
int sidreloc_set_nmi_cycles(int _cycles)
Definition sidreloc.c:2127
#define ARENASIZE
Definition sidreloc.c:1095
int sidreloc_set_tolerance(int _tolerance)
Definition sidreloc.c:2067
char * sidreloc_get_lasterror_string()
Definition sidreloc.c:2022
#define RETF_TOLERANCE
Definition sidreloc.c:222
int sidreloc_set_nmi_calls(int _cycles)
Definition sidreloc.c:2137
#define PBF_DONT_RELOC
Definition sidreloc.c:83
#define C_EXACTLY_ONE
Definition sidreloc.c:1072
#define RELEASE
Definition sidreloc.c:50
int sidreloc_set_page0(int _first, int _last)
Definition sidreloc.c:2036
int sidreloc_set_play_cycles(int _cycles)
Definition sidreloc.c:2117
#define PBF_USED_IN_MSB
Definition sidreloc.c:86
#define PBF_USED_IN_ZP
Definition sidreloc.c:85
int sidreloc_set_input_data(unsigned char *_data, int _size)
Definition sidreloc.c:2151
int sidreloc_set_init_cycles(int _cycles)
Definition sidreloc.c:2107
int sidreloc_set_verbosity(int _verbose)
Definition sidreloc.c:2087
int sidreloc_set_page(int _page)
Definition sidreloc.c:2026
#define fetch()
int sidreloc_set_strict()
Definition sidreloc.c:2077
@ OPT_FRAMES
Definition sidreloc.c:2009
@ OPT_NMI_CYCLES
Definition sidreloc.c:2013
@ OPT_INIT_CYCLES
Definition sidreloc.c:2011
@ OPT_PLAY_CYCLES
Definition sidreloc.c:2012
@ OPT_NMI_CALLS
Definition sidreloc.c:2010
int sidreloc_set_force()
Definition sidreloc.c:2082
int sidreloc_set_nopage0()
Definition sidreloc.c:2049
uint16_t word
Definition sidreloc.c:274
int sidreloc_set_frames(int _frames)
Definition sidreloc.c:2097
int sidreloc_set_output_data(unsigned char *_data)
Definition sidreloc.c:2157
uint8_t byte
Definition sidreloc.c:273
#define RETF_OUTOFBOUNDS
Definition sidreloc.c:221
#define dispatch(num, name, mode, cycles)
char * emulate_err[]
Definition sidreloc.c:287
int sidreloc_main()
Definition sidreloc.c:2162
int sidreloc_set_reloc(int _start, int _end)
Definition sidreloc.c:2054
int sidreloc_set_quiet()
Definition sidreloc.c:2092
#define do_insns(_)
Definition sidreloc.c:912
#define PBF_RELOC
Definition sidreloc.c:84
@ RET_RANGE
Definition sidreloc.c:101
@ RET_CYCLES
Definition sidreloc.c:102
@ RET_PARAM
Definition sidreloc.c:95
@ RET_BASIC
Definition sidreloc.c:93
@ RET_RSID
Definition sidreloc.c:91
@ RET_ZPFULL
Definition sidreloc.c:98
@ RET_IO
Definition sidreloc.c:96
@ RET_MUS
Definition sidreloc.c:92
@ RET_SUCCESS
Definition sidreloc.c:89
@ RET_VERIFY
Definition sidreloc.c:99
@ RET_PSID
Definition sidreloc.c:94
@ RET_CONSTR
Definition sidreloc.c:97
@ RET_PLAYADDR
Definition sidreloc.c:100
@ RET_HEADER
Definition sidreloc.c:90
@ ERR_BRK
Definition sidreloc.c:107
@ ERR_CYCLES
Definition sidreloc.c:110
@ ERR_INTERNAL
Definition sidreloc.c:108
@ ERR_OK
Definition sidreloc.c:106
@ ERR_ILLEGAL
Definition sidreloc.c:109
uint16_t n1
Definition sidreloc.c:1078
uint8_t kind
Definition sidreloc.c:1077
uint8_t check_needed
Definition sidreloc.c:1076
uint16_t vars[]
Definition sidreloc.c:1079
uint16_t n2
Definition sidreloc.c:1078
struct constraintlist * next
Definition sidreloc.c:1083
struct constraint * c
Definition sidreloc.c:1084
uint8_t read[65536]
Definition sidreloc.c:73
value_t memory[65536]
Definition sidreloc.c:72
uint8_t written[65536]
Definition sidreloc.c:74
struct constraintlist * constr
Definition sidreloc.c:80
uint8_t zpaddr[32]
Definition sidreloc.c:79
uint8_t flags
Definition sidreloc.c:78
char released[32]
Definition sidreloc.c:212
uint8_t defsubtune
Definition sidreloc.c:203
uint16_t dataoffset
Definition sidreloc.c:205
uint16_t playaddr
Definition sidreloc.c:209
uint16_t initaddr
Definition sidreloc.c:208
char author[32]
Definition sidreloc.c:211
char title[32]
Definition sidreloc.c:210
uint8_t nsubtune
Definition sidreloc.c:202
uint16_t version
Definition sidreloc.c:204
uint16_t loadsize
Definition sidreloc.c:207
uint8_t rsid
Definition sidreloc.c:201
uint16_t loadaddr
Definition sidreloc.c:206
uint8_t used
Definition sidreloc.c:63
uint16_t offset
Definition sidreloc.c:62
struct source * next
Definition sidreloc.c:61
uint8_t value
Definition sidreloc.c:67
struct source * src
Definition sidreloc.c:68
void * malloc(YYSIZE_T)
void free(void *)
#define done()
Definition ugbc.h:4389
char version[MAX_TEMPORARY_STORAGE]
Definition ugbc.tab.c:53835
@ A
Definition ugbc.tab.h:93
@ Y
Definition ugbc.tab.h:959
@ X
Definition ugbc.tab.h:950
@ P
Definition ugbc.tab.h:623
@ S
Definition ugbc.tab.h:748