83#define PBF_DONT_RELOC 0x01
85#define PBF_USED_IN_ZP 0x04
86#define PBF_USED_IN_MSB 0x08
116static int add_constraints;
118static char lastErrorString[1024];
123static void errx(
int eval,
const char *fmt, ...){
125 va_start(argptr,fmt);
126 vsprintf(lastErrorString, fmt, argptr);
134static void err(
int eval,
const char *fmt, ...){
135 fprintf(stderr,
" %s: ",
"sidreloc");
137 va_start(argptr,fmt);
138 vfprintf(stderr, fmt, argptr);
140 fprintf(stderr,
": %s\n", strerror(errno));
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);
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();
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();
158static inline void dont_reloc_at(uint16_t
offset) {
160 assert(
offset < progsize + 2);
164static inline void dont_reloc(
struct source *src) {
165 if(add_constraints) {
167 dont_reloc_at(src->
offset);
215static struct zeropage {
221#define RETF_OUTOFBOUNDS 0x20
222#define RETF_TOLERANCE 0x40
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;
230static int do_zp_reloc = 1;
231static int verbose = 0;
235static uint16_t reloc_start;
236static uint16_t reloc_end;
239static int nmi_reported;
241static struct core oldcore, newcore;
289 "Internal CPU emulator error",
291 "Max cycles exhausted (infinite loop?)",
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)
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))
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); }
317#define putMemory(ADDR, VALUE) \
318 memory[ADDR] = (VALUE); \
319 core->written[ADDR] = 1;
321#define getMemory(ADDR) (core->read[ADDR] = 1, memory[ADDR])
325#define push(VALUE) (memory[0x0100 + S--] = (VALUE))
326#define pop() (memory[++S + 0x0100])
330#define implied(ticks) \
333#define immediate(ticks) \
335 src_ea_msb = src_pc_msb; \
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); \
347#define relative(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));
356#define indirect(ticks) \
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); \
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))); \
380 check_reloc_range(ea, memory[PC].src, X.src, src_ea_msb); \
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))); \
391 check_reloc_range(ea, memory[PC].src, Y.src, src_ea_msb); \
396 core->read[PC] = 1; \
398 ea = memory[PC].value; \
399 used_for_zp_addr(memory[PC].src, 0, ea); \
404 core->read[PC] = 1; \
406 ea = memory[PC].value + X.value; \
408 used_for_zp_addr(memory[PC].src, X.src, ea); \
413 core->read[PC] = 1; \
415 ea = memory[PC].value + Y.value; \
417 used_for_zp_addr(memory[PC].src, Y.src, ea); \
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); \
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); \
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))); \
449 check_reloc_range(ea, memory[tmp].src, Y.src, src_ea_msb); \
454#define adc(ticks, adrmode) \
457 value_t B = getMemory(ea); \
460 struct source *src; \
461 int c = A.value + B.value + getC(); \
462 int v = (int8_t) A.value + (int8_t) B.value + getC(); \
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)); \
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; } \
478 s = h | (l & 0x0F); \
480 setNVZC(s & 0x80, !(((A.value ^ B.value) & 0x80) && ((A.value ^ s) & 0x80)), !s, !!(h & 0x80)); \
488#define sbc(ticks, adrmode) \
491 value_t B = getMemory(ea); \
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; \
499 setNVZC(A.value & 0x80, ((A.value & 0x80) > 0) ^ ((v & 0x100) != 0), A.value == 0, c >= 0); \
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; } \
512 s = h | (l & 0x0F); \
514 setNVZC(s & 0x80, !(((A.value ^ B.value) & 0x80) && ((A.value ^ s) & 0x80)), !s, !!(h & 0x80)); \
522#define cmpR(ticks, adrmode, R) \
526 value_t B = getMemory(ea); \
527 byte d = R.value - B.value; \
529 setNZC(d & 0x80, !d, R.value >= B.value); \
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)
537#define dec(ticks, adrmode) \
541 value_t B = getMemory(ea); \
544 setNZ(B.value & 0x80, !B.value); \
548#define decR(ticks, adrmode, R) \
552 setNZ(R.value & 0x80, !R.value); \
555#define dex(ticks, adrmode) decR(ticks, adrmode, X)
556#define dey(ticks, adrmode) decR(ticks, adrmode, Y)
558#define inc(ticks, adrmode) \
562 value_t B = getMemory(ea); \
565 setNZ(B.value & 0x80, !B.value); \
569#define incR(ticks, adrmode, R) \
573 setNZ(R.value & 0x80, !R.value); \
576#define inx(ticks, adrmode) incR(ticks, adrmode, X)
577#define iny(ticks, adrmode) incR(ticks, adrmode, Y)
579#define bit(ticks, adrmode) \
583 value_t B = getMemory(ea); \
584 P = (P & ~(flagN | flagV | flagZ)) \
585 | (B.value & (0xC0)) | (((A.value & B.value) == 0) << 1); \
589#define eor(ticks, adrmode) \
593 value_t b = getMemory(ea); \
595 A.value ^= b.value; \
598 setNZ(A.value & 0x80, !A.value); \
601#define bitwise(ticks, adrmode, op) \
605 value_t b = getMemory(ea); \
606 A.value op##= b.value; \
609 setNZ(A.value & 0x80, !A.value); \
612#define and(ticks, adrmode) bitwise(ticks, adrmode, &)
613#define ora(ticks, adrmode) bitwise(ticks, adrmode, |)
615#define asl(ticks, adrmode) \
618 value_t b = getMemory(ea); \
619 unsigned int i = b.value << 1; \
624 setNZC(i & 0x80, !i, i >> 8); \
628#define asla(ticks, adrmode) \
632 int c = A.value >> 7; \
635 setNZC(A.value & 0x80, !A.value, c); \
639#define lsr(ticks, adrmode) \
642 value_t b = getMemory(ea); \
643 int c= b.value & 1; \
648 setNZC(0, !b.value, c); \
652#define lsra(ticks, adrmode) \
656 int c = A.value & 1; \
659 setNZC(0, !A.value, c); \
663#define rol(ticks, adrmode) \
666 value_t v = getMemory(ea); \
667 word b = (v.value << 1) | getC(); \
672 setNZC(b & 0x80, !(b & 0xFF), b >> 8); \
676#define rola(ticks, adrmode) \
680 word b = (A.value << 1) | getC(); \
683 setNZC(A.value & 0x80, !A.value, b >> 8); \
687#define ror(ticks, adrmode) \
691 value_t m = getMemory(ea); \
693 byte b = (c << 7) | (m.value >> 1); \
698 setNZC(b & 0x80, !b, m.value & 1); \
702#define rora(ticks, adrmode) \
706 int co = A.value & 1; \
708 A.value = (ci << 7) | (A.value >> 1); \
710 setNZC(A.value & 0x80, !A.value, co); \
714#define tRS(ticks, adrmode, R1, R2) \
718 setNZ(R2.value & 0x80, !R1.value); \
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)
726#define tsx(ticks, adrmode) \
731 setNZ(S & 0x80, !S); \
734#define txs(ticks, adrmode) \
741#define ldR(ticks, adrmode, R) \
745 setNZ(R.value & 0x80, !R.value); \
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)
752#define stR(ticks, adrmode, R) \
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)
762#define branch(ticks, adrmode, cond) \
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())
786#define jmp(ticks, adrmode) \
789 src_pc_msb = src_ea_msb; \
793#define jsr(ticks, adrmode) \
797 v.src = src_pc_msb; \
801 v.value = PC & 0xff; \
807 src_pc_msb = src_ea_msb; \
811#define rts(ticks, adrmode) \
813 if(S >= 0xfe) return ERR_OK; \
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); \
825#define brk(ticks, adrmode) \
829#define rti(ticks, adrmode) \
831 if(S >= 0xfd) return ERR_OK; \
833 value_t status = pop(); \
834 value_t lsb = pop(); \
835 value_t msb = pop(); \
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); \
845#define nop(ticks, adrmode) \
850#define ill(ticks, adrmode) \
853#define pha(ticks, adrmode) \
859#define php(ticks, adrmode) \
870#define pla(ticks, adrmode) \
873 if(S >= 0xff) return ERR_OK; \
875 setNZ(A.value & 0x80, !A.value); \
878#define plp(ticks, adrmode) \
881 if(S >= 0xff) return ERR_OK; \
889#define clF(ticks, adrmode, F) \
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)
900#define seF(ticks, adrmode, F) \
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)
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);
978static int emulate(
struct core *
core, uint16_t start_addr, uint8_t acc,
int max_cycles)
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
1001 void **itabp = itab;
1005#define dump() if(dump_enabled) fprintf(stderr, "pc=%04x op=%02x\n", PC, v.value)
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;
1020 struct source *src_pc_msb = cons_src(1, 0);
1021 struct source *src_ea_msb;
1070#define HASHSIZE 8192
1072#define C_EXACTLY_ONE 1
1089static uint16_t progbyte_org;
1095#define ARENASIZE 32768
1096static struct arena {
1102static struct source prealloc[0x10000];
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;
1110static void print_constraint(
struct constraint *constr) {
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);
1118 fprintf(stderr,
"}\n");
1120 fprintf(stderr,
"Reloc alike: {");
1121 for(i = 0; i < constr->
n1; i++) {
1122 fprintf(stderr,
"%s$%04x", (i?
", " :
""), constr->
vars[i] + progbyte_org);
1124 fprintf(stderr,
"}, {");
1125 for(i = 0; i < constr->
n2; i++) {
1126 fprintf(stderr,
"%s$%04x", (i?
", " :
""), constr->
vars[constr->
n1 + i] + progbyte_org);
1128 fprintf(stderr,
"}\n");
1130 fprintf(stderr,
"Unknown constraint!\n");
1146 for(i = 0; i <
c->
n1 +
c->
n2; i++) {
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);
1162 h = constrainthash(constr);
1163 list = &hashconstr[h];
1167 for(cl = *list; cl; cl = cl->
next) {
1169 && cl->
c->
n1 == constr->
n1
1170 && cl->
c->
n2 == constr->
n2) {
1174 sizeof(
struct constraint) +
sizeof(uint16_t) * (constr->
n1 + constr->
n2)))
1182 if(for_real && verbose >= 2) {
1183 fprintf(stderr,
"Adding constraint: ");
1184 print_constraint(constr);
1193static void finalise_constraints(
struct core *
core) {
1198 for(
zp = 0;
zp < 0x100;
zp++) {
1200 for(cl = zpconstr[
zp]; cl; cl = nextcl) {
1202 add_or_free_constraint(0, cl->
c);
1206 for(cl = zpconstr[
zp]; cl; cl = nextcl) {
1215 for(cl = hashconstr[h]; cl; cl = cl->
next) {
1217 for(i = 0; i < constr->
n1 + constr->
n2; i++) {
1218 add_constraint_ref(constr->
vars[i], constr);
1224static int enforce_dont(uint16_t
offset) {
1231 for(cl = progbytes[
offset].constr; cl; cl = cl->
next) {
1238static int enforce_do(uint16_t
offset) {
1245 for(cl = progbytes[
offset].constr; cl; cl = cl->
next) {
1256 int i, n_do = 0, n_dont = 0, n_unknown = 0;
1257 int last_do = 0, last_unknown = 0;
1259 for(i = 0; i <
c->
n1; i++) {
1274 for(i = 0; i < c->
n1; i++) {
1276 if(enforce_dont(c->
vars[i]))
return 1;
1280 }
else if(n_do > 1) {
1284 if(n_unknown == 0) {
1286 }
else if(n_unknown == 1) {
1287 return enforce_do(c->
vars[last_unknown]);
1294 int i, n1_do = 0, n2_do = 0;
1296 for(i = 0; i < c->
n1; i++) {
1304 for(i = 0; i < c->
n2; i++) {
1312 if(n1_do > 1 || n2_do > 1)
return 1;
1313 return n1_do != n2_do;
1319static int trivially_inconsistent() {
1322 for(i = 0; i < progsize + 2; i++) {
1323 struct progbyte *pb = &progbytes[i];
1333 "Inconsistency detected! Byte at $%04x can't be both relocated and not relocated at the same time.\n",
1342static int solver() {
1355 for(cl = hashconstr[h]; cl; cl = cl->
next) {
1359 if(propagate(c))
return 1;
1367 for(h = 0; h <
HASHSIZE && !pb; h++) {
1368 for(cl = hashconstr[h]; cl && !pb; cl = cl->
next) {
1370 for(i = 0; i < c->
n1 + c->
n2; i++) {
1372 pboffs = c->
vars[i];
1373 pb = &progbytes[pboffs];
1383 int btsize = progsize + 2;
1384 uint8_t *backtrack =
malloc(btsize);
1386 for(j = 0; j < btsize; j++) {
1387 backtrack[j] = progbytes[j].flags;
1392 "Guessing that $%04x should not be relocated.\n",
1393 pboffs + progbyte_org);
1396 if(enforce_dont(pboffs) || solver()) {
1398 fprintf(stderr,
"Backtracking.\n");
1400 for(j = 0; j < btsize; j++) {
1401 progbytes[j].flags = backtrack[j];
1406 "Assuming that $%04x should be relocated.\n",
1407 pboffs + progbyte_org);
1409 return enforce_do(pboffs) || solver();
1421void dont_reloc_at(uint16_t
offset) {
1422 assert(
offset < progsize + 2);
1426void dont_reloc(
struct source *src) {
1427 if(add_constraints) {
1429 dont_reloc_at(src->
offset);
1437static void do_reloc_at(uint16_t
offset) {
1441static void progbyte_for_zp(uint16_t
offset, uint8_t
zpaddr) {
1446static void progbyte_for_msb(uint16_t
offset) {
1450static void prealloc_cons_cells() {
1453 for(i = 0; i < 0x10000; i++) {
1454 prealloc[i].offset = i;
1455 prealloc[i].next = 0;
1462 if(add_constraints) {
1470 return &prealloc[
offset];
1473 for(s = cdr; s; s = s->
next) {
1487 struct arena *a = calloc(
sizeof(
struct arena), 1);
1492 s = &arena->data[arena_index++];
1502static void gc_arena(
struct core *
core) {
1503 struct arena *a, **aptr;
1508 for(a = arena->next; a; a = a->next) {
1510 a->data[i].
used = 0;
1514 for(i = 0; i < 65536; i++) {
1520 for(aptr = &arena->next; *aptr; ) {
1523 if(a->data[i].
used)
break;
1536 fprintf(stderr,
"Reclaimed %d arenas.\n", count);
1540static void free_arena() {
1544 while((a = arena)) {
1550 if(verbose >= 3) fprintf(stderr,
"Freed %d arenas.\n", count);
1553static void reloc_exactly_one(
struct source *src, uint8_t zpaddr) {
1554 int n_unknown = 0, n_dont = 0, n_do = 0;
1556 uint16_t last_do = 0, last_unknown = 0;
1558 for(s = src; s; s = s->
next) {
1559 for(s2 = s->
next; s2; s2 = s2->
next) {
1565 "Byte at $%04x contributes more than once to a sum and won't be relocated.\n",
1566 s->
offset + progbyte_org);
1568 dont_reloc_at(s->
offset);
1573 for(s = src; s; s = s->
next) {
1581 last_unknown = s->
offset;
1589 constr =
malloc(
sizeof(
struct constraint) +
sizeof(uint16_t) * (n_do + n_unknown));
1592 constr->
n1 = n_do + n_unknown;
1594 for(s = src; s; s = s->
next) {
1599 assert(pos == n_do + n_unknown);
1601 add_or_free_constraint(&zpconstr[zpaddr], constr);
1606 for(s = src; s; s = s->
next) {
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?
", " :
"");
1618 fprintf(stderr,
"} but this would contradict other equations.\n");
1627 constr->
n1 = n_unknown;
1629 for(s = src; s; s = s->
next) {
1634 assert(pos == n_unknown);
1636 add_or_free_constraint(0, constr);
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)) {
1660 for(s = v1.
src; s; s = s->
next) {
1663 for(s = v2.
src; s; s = s->
next) {
1666 assert(pos ==
n1 +
n2);
1668 add_or_free_constraint(0, constr);
1673static void used_for_zp_addr(
struct source *src1,
struct source *src2, uint8_t zpaddr) {
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);
1682 for(s = src2; s; s = s->
next) list = cons_src(s->
offset, list);
1683 reloc_exactly_one(list, zpaddr);
1688static void check_reloc_range(uint16_t addr,
struct source *lsb1,
struct source *lsb2,
struct source *msb) {
1689 if(add_constraints) {
1692 for(s = msb; s; s = s->
next) {
1693 progbyte_for_msb(s->
offset);
1695 if(addr >= reloc_start && addr <= reloc_end) {
1697 if(lsb2) dont_reloc(lsb2);
1698 reloc_exactly_one(msb, 0);
1699 }
else if(addr < 0x100) {
1701 used_for_zp_addr(lsb1, lsb2, addr);
1705 if(lsb2) dont_reloc(lsb2);
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);
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;
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);
1730 if(addr < org || addr >= org + progsize) {
1731 fprintf(stderr,
" ");
1733 i = addr - progbyte_org;
1736 fprintf(stderr,
"R");
1739 fprintf(stderr,
"Z");
1742 fprintf(stderr,
"e");
1745 fprintf(stderr,
"=");
1747 }
else if(!(oldcore->
read[addr] | oldcore->
written[addr])) {
1748 fprintf(stderr,
".");
1751 fprintf(stderr,
"?");
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);
1768static int readheader(
struct sidheader *head, uint8_t *data,
int filesize) {
1769 if(filesize <= 0x80)
return 1;
1770 if(data[0] ==
'P') {
1772 }
else if(data[0] ==
'R') {
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];
1783 head->
loadaddr = (data[8] << 8) | data[9];
1790 head->
initaddr = (data[0x0a] << 8) | data[0x0b];
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));
1798 head->
title[31] = 0;
1802 uint16_t
flags = (data[0x76] << 8) | data[0x77];
1803 if(
flags & 1) errx(
RET_MUS,
"MUS format not supported");
1810static void init_core(
struct core *
core, uint8_t *data, uint16_t loadaddr, uint16_t loadsize) {
1815 for(i = 0xea31; i <= 0xea86; i++) {
1819 for(i = 0; i < loadsize; i++) {
1825static uint16_t get_from_vector(
struct core *
core, uint16_t fallback, uint16_t vaddr) {
1830 }
else return fallback;
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]);
1839static int play_step(
struct core *
core, uint16_t playaddr,
char *errprefix) {
1845 playaddr = get_from_vector(
core, playaddr, 0x0314);
1846 playaddr = get_from_vector(
core, playaddr, 0xfffe);
1849 playaddr = get_from_vector(
core, playaddr, 0x0318);
1850 playaddr = get_from_vector(
core, playaddr, 0xfffa);
1854 if(!playaddr) errx(
RET_PLAYADDR,
"%sCouldn't determine address of playroutine.", errprefix);
1856 errcode = emulate(
core, playaddr, 0, cycles_play);
1858 errx(
RET_CYCLES | exitbits,
"Max cycles exhausted during playroutine. Infinite loop?");
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);
1867 fprintf(stderr,
"Use of digis detected. NMI routine will also be relocated.\n");
1870 for(i = 0; i < nmi_calls; i++) {
1871 errcode = emulate(
core, digiaddr, 0, cycles_nmi);
1873 errx(
RET_CYCLES | exitbits,
"Max cycles exhausted during NMI routine. Infinite loop?");
1883static int verify_sidstate(
value_t *oldmem,
value_t *newmem,
int frame,
int *n_badpitch,
int *n_badpw) {
1885 int badp[3] = {0, 0, 0}, badpw[3] = {0, 0, 0};
1887 for(i = 0; i < 29; i++) {
1888 if(oldmem[0xd400 + i].value != newmem[0xd400 + i].value) {
1889 if(i < 21 && (i % 7) < 2) {
1891 }
else if(i < 21 && (i % 7) < 4) {
1894 fprintf(stderr,
"Wrong SID state! ");
1896 fprintf(stderr,
"At time %d, ", frame);
1898 fprintf(stderr,
"After the init routine, ");
1900 fprintf(stderr,
"$d4%02x should be $%02x, but the relocated code has written $%02x.\n",
1902 oldmem[0xd400 + i].value,
1903 newmem[0xd400 + i].value);
1910 *n_badpitch += badp[0] + badp[1] + badp[2];
1911 *n_badpw += badpw[0] + badpw[1] + badpw[2];
1915static void zeropage_map() {
1918 fprintf(stderr,
"Old zero-page addresses: ");
1919 for(i = 2; i < 256; i++) {
1920 if(oldcore.
written[i]) fprintf(stderr,
" %02x", i);
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);
1926 fprintf(stderr,
"\n");
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");
1936static void usage() {
1937 printf(
"sidreloc " RELEASE " by Linus Akesson\n");
1939 printf(
"Usage: sidreloc [OPTIONS] input.sid output.sid\n");
1941 printf(
"Options:\n");
1942 printf(
"Short name Long name Default Description\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");
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");
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");
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");
1971 printf(
" -h --help Display this information.\n");
1972 printf(
" -V --version Display brief version information and credits.\n");
1974 printf(
"Project homepage: http://www.linusakesson.net/software/sidreloc/\n");
1978static int readfile(uint8_t *data,
char *filename) {
1980 FILE *f = fopen(filename,
"rb");
1981 if(!f) err(
RET_IO,
"%s", filename);
1982 filesize = fread(data, 1, 65536, f);
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");
1994static void report_oob(uint16_t first, uint16_t last) {
1995 if(!quiet && first != 0xd400) {
1997 if ( verbose > 0 ) {
1998 fprintf(stderr,
"Warning: Write out of bounds at address $%04x\n", first);
2001 if ( verbose > 0 ) {
2002 fprintf(stderr,
"Warning: Write out of bounds at address $%04x-$%04x\n", first, last);
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;
2023 return lastErrorString;
2027 if ( _page >= 0x00 && dest_page <= 0xff) {
2031 errx(
RET_PARAM,
"SID relocation: invalid page number (should be in the range $00-$ff, 0..255)");
2037 if ( _first >= 0x02 && _first <= 0xff &&
2038 _last >= 0x02 && _last <= 0xff &&
2044 errx(
RET_PARAM,
"Invalid zero-page address range (should be in the range $02-$ff, 0..255)");
2055 if( _start >= 0x01 && _start <= 0xff &&
2056 _end >= 0x01 && _end <= 0xff &&
2058 given_reloc_start = _start;
2059 given_reloc_end = _end;
2062 errx(
RET_PARAM,
"Invalid relocation range (should be in the range $01-$ff, 2..255)");
2068 if ( _tolerance >= 0 && _tolerance < 100) {
2069 tolerance = _tolerance;
2072 errx(
RET_PARAM,
"Invalid tolerance percentage (should be in the range 0-100)");
2098 if ( _frames >= 0 ) {
2099 play_calls = _frames;
2102 errx(
RET_PARAM,
"Invalid number of calls to the playroutine.");
2108 if ( _cycles >= 0 ) {
2109 cycles_init = _cycles;
2112 errx(
RET_PARAM,
"Invalid cycle limit for the init routine.");
2118 if ( _cycles >= 0 ) {
2119 cycles_play = _cycles;
2122 errx(
RET_PARAM,
"Invalid cycle limit for the playroutine.");
2128 if ( _cycles >= 0 ) {
2129 cycles_nmi = _cycles;
2132 errx(
RET_PARAM,
"Invalid cycle limit for the NMI routine.");
2138 if ( _cycles >= 0 ) {
2139 nmi_calls = _cycles;
2142 errx(
RET_PARAM,
"Invalid number of calls to the NMI routine.");
2147static uint8_t * data;
2148static uint8_t * newdata;
2163 int i, j, k, errcode, opt;
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;
2174 if(readheader(&head, data, filesize)) {
2179 fprintf(stdout,
"%s, %s, %s, $%04x-$%04x, %d subtunes\n",
2190 reloc_start = head.
loadaddr & 0xff00;
2193 for(i = 0; i < 64 && reloc_end != 0xcfff && reloc_end != 0xffff; i++) {
2197 if(given_reloc_start >= 0) {
2198 reloc_start = given_reloc_start << 8;
2199 reloc_end = (given_reloc_end << 8) | 0xff;
2203 "Relocation range (-r) must contain all the SID data! (SID loads at $%04x-$%04x)",
2210 reloc_offset = (dest_page << 8) - reloc_start;
2212 if ( verbose > 0 ) {
2213 fprintf(stdout,
"Relocating from $%04x-$%04x to $%04x-$%04x\n",
2216 (reloc_start + reloc_offset) & 0xffff,
2217 (reloc_end + reloc_offset) & 0xffff);
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.");
2227 prealloc_cons_cells();
2232 add_constraints = 1;
2234 for(i = 0; i < head.
nsubtune; i++) {
2235 if ( verbose > 0 ) {
2236 fprintf(stderr,
"Analysing subtune %d\n", i + 1);
2240 init_tune(&oldcore, head.
initaddr, i);
2241 for(j = 0; j < play_calls; j++) {
2242 if(play_step(&oldcore, head.
playaddr,
""))
break;
2249 oobchunk = ooblast = 0xd400;
2250 for(i = 0; i < 65536; i++) {
2253 }
else if(i >= 0xd400 && i <= 0xd41f) {
2255 }
else if(i >= 2 && i < 0x100) {
2258 if ( verbose > 0 ) {
2260 "Warning: Zero-page address $%02x read but never written.%s\n",
2262 (do_zp_reloc?
" Not relocating it." :
""));
2265 for(j = 0; j < progsize; j++) {
2266 struct progbyte *pb = &progbytes[j + 2];
2268 pb->
zpaddr[i >> 3] &= ~(1 << (i & 7));
2269 for(k = 0; k < 32; k++)
if(pb->
zpaddr[k])
break;
2277 if(ooblast != i - 1) {
2278 report_oob(oobchunk, ooblast);
2285 report_oob(oobchunk, ooblast);
2287 finalise_constraints(&oldcore);
2291 if(trivially_inconsistent() || solver()) {
2292 errx(
RET_CONSTR | exitbits,
"No solution found");
2298 for(i = 0; i < 256; i++) {
2299 zeropage[i].link = i;
2300 zeropage[i].free = (i >= first_zp && i <= last_zp);
2303 for(i = 0; i < progsize; i++) {
2304 struct progbyte *pb = &progbytes[i + 2];
2307 for(j = 0; j < 256; j++) {
2308 if(pb->
zpaddr[j >> 3] & (1 << (j & 7))) {
2312 if(zeropage[j].link > zeropage[first].link) {
2313 zeropage[j].link = zeropage[first].link;
2315 zeropage[first].link = zeropage[j].link;
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;
2334 for(chunk = 2; chunk < 0x100; chunk++) {
2335 if(oldcore.
written[chunk] && (zeropage[chunk].link == chunk)) {
2337 for(dest = first_zp; dest <= last_zp; dest++) {
2339 for(i = chunk; i < 0x100; i++) {
2340 if(zeropage[i].link == chunk) {
2341 if(!zeropage[(dest + i - chunk) & 0xff].
free) {
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;
2357 if(dest > last_zp) {
2359 "Can't fit all zero-page addresses into specified range ($%02x-$%02x).",
2371 reloc_map(&oldcore, reloc_offset);
2377 memcpy(newdata, data, filesize);
2378 for(i = 0; i < progsize; i++) {
2379 struct progbyte *pb = &progbytes[i + 2];
2382 newdata[head.
dataoffset + i] += reloc_offset >> 8;
2384 for(j = 2; j < 256; j++) {
2385 if(pb->
zpaddr[j / 8] & (1 << (j & 7))) {
2390 newdata[head.
dataoffset + i] += zeropage[j].reloc;
2401 add_constraints = 0;
2403 for(i = 0; i < head.
nsubtune; i++) {
2404 if ( verbose > 0 ) {
2405 fprintf(stderr,
"Verifying relocated subtune %d\n", i + 1);
2410 init_tune(&oldcore, head.
initaddr, i);
2412 reloc_start += reloc_offset;
2413 reloc_end += reloc_offset;
2415 init_tune(&newcore, (head.
initaddr + reloc_offset) & 0xffff, i);
2418 if ( !verify_sidstate(oldcore.
memory, newcore.memory, -1, &n_badpitch, &n_badpw) ) {
2422 for(j = 0; j < play_calls; j++) {
2423 reloc_start -= reloc_offset;
2424 reloc_end -= reloc_offset;
2426 errcode = play_step(&oldcore, head.
playaddr,
"Old version: ");
2429 reloc_start += reloc_offset;
2430 reloc_end += reloc_offset;
2432 errcode = play_step(&newcore, (head.
playaddr? ((head.
playaddr + reloc_offset) & 0xffff) : 0),
"New version: ");
2437 errx(
RET_VERIFY | exitbits,
"Verification failed");
2443 if ( ! verify_sidstate(oldcore.
memory, newcore.memory, j, &n_badpitch, &n_badpw) ) {
2448 reloc_start -= reloc_offset;
2449 reloc_end -= reloc_offset;
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);
2459 if(n_badpitch || n_badpw) {
2462 if(n_badpitch && (!tolerance || (perc_badpitch > tolerance))) {
2463 errx(
RET_VERIFY | exitbits,
"Relocation failed; too many mismatching pitches.\n");
2465 }
else if(n_badpw && strictpw) {
2466 errx(
RET_VERIFY | exitbits,
"Relocation failed; mismatching pulse widths and strict flag given.\n");
2481 if(newdata[0x08] | newdata[0x09]) {
2482 newdata[0x08] += reloc_offset >> 8;
2484 newdata[head.
dataoffset - 1] += reloc_offset >> 8;
2486 if(newdata[0x0a] | newdata[0x0b]) {
2487 newdata[0x0a] += reloc_offset >> 8;
2489 if(newdata[0x0c] | newdata[0x0d]) {
2490 newdata[0x0c] += reloc_offset >> 8;
2495 memset(page_used, 0,
sizeof(page_used));
2497 int best_start, best_n, curr_start, curr_n;
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))) {
2507 for(j = 0; j < 256; j++) {
2508 if(newcore.read[(i << 8) | j]
2509 || newcore.written[(i << 8) | j]) {
2516 best_start = curr_start = 0;
2517 best_n = curr_n = 0;
2518 for(i = 0; i < 256; i++) {
2520 if(curr_n > best_n) {
2521 best_start = curr_start;
2530 if(curr_n > best_n) {
2531 best_start = curr_start;
2537 "Largest unused region: $%02x00-$%02xff\n",
2539 best_start + best_n - 1);
2541 newdata[0x78] = best_start;
2542 newdata[0x79] = best_n;
2545 fprintf(stdout,
"No space left for replay routine!\n");
2547 newdata[0x78] = 0xff;
int sidreloc_set_nmi_cycles(int _cycles)
int sidreloc_set_tolerance(int _tolerance)
char * sidreloc_get_lasterror_string()
int sidreloc_set_nmi_calls(int _cycles)
int sidreloc_set_page0(int _first, int _last)
int sidreloc_set_play_cycles(int _cycles)
int sidreloc_set_input_data(unsigned char *_data, int _size)
int sidreloc_set_init_cycles(int _cycles)
int sidreloc_set_verbosity(int _verbose)
int sidreloc_set_page(int _page)
int sidreloc_set_strict()
int sidreloc_set_nopage0()
int sidreloc_set_frames(int _frames)
int sidreloc_set_output_data(unsigned char *_data)
#define dispatch(num, name, mode, cycles)
int sidreloc_set_reloc(int _start, int _end)
struct constraintlist * next
struct constraintlist * constr
char version[MAX_TEMPORARY_STORAGE]