From 3d01a3c90b47f8d27bd0caa70eb95613d889e11f Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Thu, 12 Dec 2024 04:53:48 +0100 Subject: [PATCH 1/5] simdis: fix undocumented opcode disassembly Wouldn't flag operand-less undocumented DD/FD opcodes. DD/FD followed by DD/FD is an undocumented NOP. Should now produce sensible output for every random byte stream. before: 0000 - DD 37 SCF 0002 - DD FD 0004 - DD NOP* 0005 - ED 45 RETN 0007 - DD 11 F1 0C LD* DE,0CF1 now: 0000 - DD 37 SCF* 0002 - DD NOP* 0003 - FD NOP* 0004 - DD NOP* 0005 - ED 45 RETN 0007 - DD 11 F1 0C LD* DE,0CF1 Bloody undocumented instructions... but who am I to complain, I started it... --- z80core/simdis.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/z80core/simdis.c b/z80core/simdis.c index 0b5018d3..b0be9a31 100644 --- a/z80core/simdis.c +++ b/z80core/simdis.c @@ -217,13 +217,13 @@ int disass(WORD addr) if ((op & 0xdf) == 0xdd) { ireg = 'X' + ((op >> 5) & 1); op = getmem(a++); - undoc_ireg = undoc_ddfd[op >> 3] & (1 << (op & 7)); + undoc_ireg = !!(undoc_ddfd[op >> 3] & (1 << (op & 7))); } reg1 = (op >> 3) & 7; reg2 = op & 7; if (op < 0x40) { tmpl = optab_01[op]; - if (ireg && reg1 == 6 && (reg2 >= 4 && reg2 <= 6)) + if (ireg && reg1 == 6 && (4 <= reg2 && reg2 <= 6)) displ = getmem(a++); } else if (op < 0x80) { if (op == 0x76) @@ -260,8 +260,9 @@ int disass(WORD addr) } } else if (op == 0xed) { if (ireg) { + /* DD/FD followed by ED is an undoc'd NOP */ + tmpl = "NOP"; a--; - tmpl = "NOP*"; } else { op = getmem(a++); if (0x40 <= op && op < 0x80) @@ -271,6 +272,10 @@ int disass(WORD addr) else tmpl = "NOP*"; } + } else if (ireg && (op & 0xdf) == 0xdd) { + /* DD/FD followed by DD/FD is an undocumented NOP */ + tmpl = "NOP"; + a--; } else tmpl = optab_67[op & 0x3f]; break; @@ -390,8 +395,10 @@ int disass(WORD addr) *p++ = '0' + bit; break; case '\t': - if (undoc_ireg) + if (undoc_ireg) { + undoc_ireg++; *p++ = '*'; + } #endif /* fall through */ /* should really be inside #if */ default: @@ -399,6 +406,10 @@ int disass(WORD addr) break; } } +#ifndef EXCLUDE_Z80 + if (undoc_ireg == 1) + *p++ = '*'; +#endif *p++ = '\n'; *p = '\0'; len = a - addr; From ebbf8cfe822b340671cc01c98f51181faeeb4b3d Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Thu, 12 Dec 2024 05:08:03 +0100 Subject: [PATCH 2/5] simdis: increase assemblability of output I needed to lookup that word online ;-) Output numbers in assembler hex notation to make it easier to convert disassembler output into something that the assembler accepts. --- z80core/simdis.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/z80core/simdis.c b/z80core/simdis.c index b0be9a31..a9982a56 100644 --- a/z80core/simdis.c +++ b/z80core/simdis.c @@ -52,21 +52,21 @@ static const char *const optab_45[8] = { static const char *const optab_67[64] = { /*C0*/ "RET\tNZ", "POP\tBC", "JP\tNZ,w", "JP\tw", - /*C4*/ "CALL\tNZ,w", "PUSH\tBC", "ADD\tA,b", "RST\t00", + /*C4*/ "CALL\tNZ,w", "PUSH\tBC", "ADD\tA,b", "RST\t00H", /*C8*/ "RET\tZ", "RET", "JP\tZ,w", "", - /*CC*/ "CALL\tZ,w", "CALL\tw", "ADC\tA,b", "RST\t08", + /*CC*/ "CALL\tZ,w", "CALL\tw", "ADC\tA,b", "RST\t08H", /*D0*/ "RET\tNC", "POP\tDE", "JP\tNC,w", "OUT\t(b),A", - /*D4*/ "CALL\tNC,w", "PUSH\tDE", "SUB\tb", "RST\t10", + /*D4*/ "CALL\tNC,w", "PUSH\tDE", "SUB\tb", "RST\t10H", /*D8*/ "RET\tC", "EXX", "JP\tC,w", "IN\tA,(b)", - /*DC*/ "CALL\tC,w", "", "SBC\tA,b", "RST\t18", + /*DC*/ "CALL\tC,w", "", "SBC\tA,b", "RST\t18H", /*E0*/ "RET\tPO", "POP\ti", "JP\tPO,w", "EX\t(SP),i", - /*E4*/ "CALL\tPO,w", "PUSH\ti", "AND\tb", "RST\t20", + /*E4*/ "CALL\tPO,w", "PUSH\ti", "AND\tb", "RST\t20H", /*E8*/ "RET\tPE", "JP\t(i)", "JP\tPE,w", "EX\tDE,HL", - /*EC*/ "CALL\tPE,w", "", "XOR\tb", "RST\t28", + /*EC*/ "CALL\tPE,w", "", "XOR\tb", "RST\t28H", /*F0*/ "RET\tP", "POP\tAF", "JP\tP,w", "DI", - /*F4*/ "CALL\tP,w", "PUSH\tAF", "OR\tb", "RST\t30", + /*F4*/ "CALL\tP,w", "PUSH\tAF", "OR\tb", "RST\t30H", /*F8*/ "RET\tM", "LD\tSP,i", "JP\tM,w", "EI", - /*FC*/ "CALL\tM,w", "", "CP\tb", "RST\t38" + /*FC*/ "CALL\tM,w", "", "CP\tb", "RST\t38H" }; static const char *const optab_ed_23[64] = { @@ -313,13 +313,19 @@ int disass(WORD addr) switch (*tmpl) { case 'b': /* byte */ b1 = getmem(a++); + if (b1 >= 0xa0) + *p++ = '0'; p = btoh(b1, p); + *p++ = 'H'; break; case 'w': /* word */ b1 = getmem(a++); b2 = getmem(a++); + if (b2 >= 0xa0) + *p++ = '0'; p = btoh(b2, p); p = btoh(b1, p); + *p++ = 'H'; break; case 'r': /* register */ switch (cpu) { @@ -353,6 +359,7 @@ int disass(WORD addr) displ = -displ; } p = btoh(displ, p); + *p++ = 'H'; } } else { *p++ = 'H'; @@ -388,8 +395,11 @@ int disass(WORD addr) case 'j': /* relative jump address */ b1 = getmem(a++); w = a + (SBYTE) b1; + if (w >= 0xa000) + *p++ = '0'; p = btoh(w >> 8, p); p = btoh(w & 0xff, p); + *p++ = 'H'; break; case 'n': /* bit number */ *p++ = '0' + bit; From 6ee2ec04da70df3baae40cb6204f8601f8b6d269 Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Thu, 12 Dec 2024 05:24:21 +0100 Subject: [PATCH 3/5] simdis: remove double space --- z80core/simdis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/z80core/simdis.c b/z80core/simdis.c index a9982a56..1d38b3d7 100644 --- a/z80core/simdis.c +++ b/z80core/simdis.c @@ -359,7 +359,7 @@ int disass(WORD addr) displ = -displ; } p = btoh(displ, p); - *p++ = 'H'; + *p++ = 'H'; } } else { *p++ = 'H'; From 5f85f59118033e1b430277a03479cde80a442066 Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Thu, 12 Dec 2024 06:59:33 +0100 Subject: [PATCH 4/5] simdis: produce assembler hex without multiple leading zeroes --- z80core/simdis.c | 50 +++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/z80core/simdis.c b/z80core/simdis.c index 1d38b3d7..82362aa7 100644 --- a/z80core/simdis.c +++ b/z80core/simdis.c @@ -23,6 +23,7 @@ * Forward declarations */ static char *btoh(BYTE b, char *p); +static char *wtoa(WORD w, char *p); #ifndef EXCLUDE_Z80 @@ -52,9 +53,9 @@ static const char *const optab_45[8] = { static const char *const optab_67[64] = { /*C0*/ "RET\tNZ", "POP\tBC", "JP\tNZ,w", "JP\tw", - /*C4*/ "CALL\tNZ,w", "PUSH\tBC", "ADD\tA,b", "RST\t00H", + /*C4*/ "CALL\tNZ,w", "PUSH\tBC", "ADD\tA,b", "RST\t0H", /*C8*/ "RET\tZ", "RET", "JP\tZ,w", "", - /*CC*/ "CALL\tZ,w", "CALL\tw", "ADC\tA,b", "RST\t08H", + /*CC*/ "CALL\tZ,w", "CALL\tw", "ADC\tA,b", "RST\t8H", /*D0*/ "RET\tNC", "POP\tDE", "JP\tNC,w", "OUT\t(b),A", /*D4*/ "CALL\tNC,w", "PUSH\tDE", "SUB\tb", "RST\t10H", /*D8*/ "RET\tC", "EXX", "JP\tC,w", "IN\tA,(b)", @@ -313,19 +314,12 @@ int disass(WORD addr) switch (*tmpl) { case 'b': /* byte */ b1 = getmem(a++); - if (b1 >= 0xa0) - *p++ = '0'; - p = btoh(b1, p); - *p++ = 'H'; + p = wtoa(b1, p); break; case 'w': /* word */ b1 = getmem(a++); b2 = getmem(a++); - if (b2 >= 0xa0) - *p++ = '0'; - p = btoh(b2, p); - p = btoh(b1, p); - *p++ = 'H'; + p = wtoa((b2 << 8) | b1, p); break; case 'r': /* register */ switch (cpu) { @@ -358,8 +352,7 @@ int disass(WORD addr) *p++ = '-'; displ = -displ; } - p = btoh(displ, p); - *p++ = 'H'; + p = wtoa(displ, p); } } else { *p++ = 'H'; @@ -395,11 +388,7 @@ int disass(WORD addr) case 'j': /* relative jump address */ b1 = getmem(a++); w = a + (SBYTE) b1; - if (w >= 0xa000) - *p++ = '0'; - p = btoh(w >> 8, p); - p = btoh(w & 0xff, p); - *p++ = 'H'; + p = wtoa(w, p); break; case 'n': /* bit number */ *p++ = '0' + bit; @@ -463,4 +452,29 @@ static char *btoh(BYTE b, char *p) return p; } +/* + * convert WORD into assembler hex and copy to string at p + * returns p increased by number of characters produced + */ +static char *wtoa(WORD w, char *p) +{ + register char c; + register int onlyz, shift; + + onlyz = 1; + for (shift = 12; shift >= 0; shift -= 4) { + c = (w >> shift) & 0xf; + if (onlyz && c > 9) + *p++ = '0'; + if (!onlyz || c) { + *p++ = c + (c < 10 ? '0' : '7'); + onlyz = 0; + } + } + if (onlyz) + *p++ = '0'; + *p++ = 'H'; + return p; +} + #endif /* WANT_ICE */ From 0c243af13dd58f60ea11821de6212bd1e1c9908e Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Thu, 12 Dec 2024 09:15:40 +0100 Subject: [PATCH 5/5] simice: use from,to arguments for dump and list Makes more sense. --- z80core/simice.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/z80core/simice.c b/z80core/simice.c index 823c8912..9e80322f 100644 --- a/z80core/simice.c +++ b/z80core/simice.c @@ -374,8 +374,11 @@ static void do_dump(char *s) wrk_addr = exatoi(s) & ~0xf; while (*s != ',' && *s != '\0') s++; - if (*s && isdigit((unsigned char) *++s)) - n = atoi(s); + if (*s && isxdigit((unsigned char) *++s)) { + n = ((exatoi(s) & ~0xf) - wrk_addr) / 16 + 1; + if (n <= 0) + n = 1; + } printf("Addr "); for (i = 0; i < 16; i++) printf("%02x ", i); @@ -399,7 +402,7 @@ static void do_dump(char *s) static void do_list(char *s) { register int i; - int n = 10; + register WORD a; while (isspace((unsigned char) *s)) s++; @@ -407,11 +410,19 @@ static void do_list(char *s) wrk_addr = exatoi(s); while (*s != ',' && *s != '\0') s++; - if (*s && isdigit((unsigned char) *++s)) - n = atoi(s); - for (i = 0; i < n; i++) { - printf("%04x - ", (unsigned int) wrk_addr); - wrk_addr += disass(wrk_addr); + if (*s && isxdigit((unsigned char) *++s)) { + a = exatoi(s); + if (a < wrk_addr) + a = wrk_addr; + while (wrk_addr <= a) { + printf("%04x - ", (unsigned int) wrk_addr); + wrk_addr += disass(wrk_addr); + } + } else { + for (i = 0; i < 10; i++) { + printf("%04x - ", (unsigned int) wrk_addr); + wrk_addr += disass(wrk_addr); + } } } @@ -1000,8 +1011,8 @@ static void do_show(void) */ static void do_help(void) { - puts("d [address][,count] dump memory"); - puts("l [address][,count] list memory"); + puts("d [from][,to] dump memory"); + puts("l [from][,to] list memory"); puts("m [address] modify memory"); puts("f address,count,value fill memory"); puts("v from,to,count move memory");