]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
New debugger features, including assembler.
authorToni Wilen <twilen@winuae.net>
Sun, 2 Jul 2017 07:50:21 +0000 (10:50 +0300)
committerToni Wilen <twilen@winuae.net>
Sun, 2 Jul 2017 07:50:21 +0000 (10:50 +0300)
debug.cpp
include/newcpu.h
newcpu.cpp

index 77684d111e3f81c19c13cb7798b299469b612cbe..507ada06107911d1be7ac0220b641a08e4cac43a 100644 (file)
--- a/debug.cpp
+++ b/debug.cpp
@@ -44,6 +44,7 @@
 #include "uae/io.h"
 #include "uae/ppc.h"
 #include "drawing.h"
+#include "devices.h"
 
 int debugger_active;
 static uaecptr skipaddr_start, skipaddr_end;
@@ -117,6 +118,7 @@ static const TCHAR help[] = {
        _T("  r                     Dump state of the CPU.\n")
        _T("  r <reg> <value>       Modify CPU registers (Dx,Ax,USP,ISP,VBR,...).\n")
        _T("  m <address> [<lines>] Memory dump starting at <address>.\n")
+       _T("  a <address>           Assembler.\n")
        _T("  d <address> [<lines>] Disassembly starting at <address>.\n")
        _T("  t [instructions]      Step one or more instructions.\n")
        _T("  z                     Step through one instruction - useful for JSR, DBRA etc.\n")
@@ -146,11 +148,14 @@ static const TCHAR help[] = {
        _T("  Cl                    List currently found trainer addresses.\n")
        _T("  D[idxzs <[max diff]>] Deep trainer. i=new value must be larger, d=smaller,\n")
        _T("                        x = must be same, z = must be different, s = restart.\n")
-       _T("  W <address> <values[.x] separated by space> Write into Amiga memory.\n")
-       _T("  W <address> 'string' Write into Amiga memory.\n")
+       _T("  W <addr> <values[.x] separated by space> Write into Amiga memory.\n")
+       _T("  W <addr> 'string'     Write into Amiga memory.\n")
+       _T("  Wf <addr> <endaddr> <bytes or string like above>, fill memory.\n")
+       _T("  Wc <addr> <endaddr> <destaddr>, copy memory.\n")
        _T("  w <num> <address> <length> <R/W/I/F/C> [<value>[.x]] (read/write/opcode/freeze/mustchange).\n")
        _T("                        Add/remove memory watchpoints.\n")
        _T("  wd [<0-1>]            Enable illegal access logger. 1 = enable break.\n")
+       _T("  L <file> <addr> <n>   Load a block of Amiga memory.\n")
        _T("  S <file> <addr> <n>   Save a block of Amiga memory.\n")
        _T("  s \"<string>\"/<values> [<addr>] [<length>]\n")
        _T("                        Search for string/bytes.\n")
@@ -169,6 +174,7 @@ static const TCHAR help[] = {
        _T("  v <vpos> [<hpos>]     Show DMA data (accurate only in cycle-exact mode).\n")
        _T("                        v [-1 to -4] = enable visual DMA debugger.\n")
        _T("  vh [<ratio> <lines>]  \"Heat map\"\n")
+       _T("  I <custom event>      Send custom event string\n")
        _T("  ?<value>              Hex ($ and 0x)/Bin (%)/Dec (!) converter and calculator.\n")
 #ifdef _WIN32
        _T("  x                     Close debugger.\n")
@@ -2432,8 +2438,17 @@ struct breakpoint_node bpnodes[BREAKPOINT_TOTAL];
 static addrbank **debug_mem_banks;
 static addrbank *debug_mem_area;
 struct memwatch_node mwnodes[MEMWATCH_TOTAL];
+static int mwnodes_cnt;
 static struct memwatch_node mwhit;
 
+#define MUNGWALL_SLOTS 16
+struct mungwall_data
+{
+       int slots;
+       uae_u32 start[MUNGWALL_SLOTS], end[MUNGWALL_SLOTS];
+};
+static struct mungwall_data **mungwall;
+
 static uae_u8 *illgdebug, *illghdebug;
 static int illgdebug_break;
 
@@ -2746,11 +2761,28 @@ void restore_debug_memwatch_finish (void)
        }
 }
 
+static void mungwall_memwatch(uaecptr addr, int rwi, int size, uae_u32 valp)
+{
+       struct mungwall_data *mwd = mungwall[addr >> 16];
+       if (!mwd)
+               return;
+       for (int i = 0; i < mwd->slots; i++) {
+               if (!mwd->end[i])
+                       continue;
+               if (addr + size > mwd->start[i] && addr < mwd->end[i]) {
+
+               }
+       }
+}
+
 static int memwatch_func (uaecptr addr, int rwi, int size, uae_u32 *valp, uae_u32 accessmask, uae_u32 reg)
 {
        int i, brk;
        uae_u32 val = *valp;
 
+       if (mungwall)
+               mungwall_memwatch(addr, rwi, size, val);
+
        if (illgdebug)
                illg_debug_do (addr, rwi, size, val);
 
@@ -2760,7 +2792,7 @@ static int memwatch_func (uaecptr addr, int rwi, int size, uae_u32 *valp, uae_u3
        addr = munge24 (addr);
        if (smc_table && (rwi >= 2))
                smc_detector (addr, rwi, size, valp);
-       for (i = 0; i < MEMWATCH_TOTAL; i++) {
+       for (i = 0; i < mwnodes_cnt; i++) {
                struct memwatch_node *m = &mwnodes[i];
                uaecptr addr2 = m->addr;
                uaecptr addr3 = addr2 + m->size;
@@ -3184,11 +3216,13 @@ static void memwatch_remap (uaecptr addr)
 static void memwatch_setup (void)
 {
        memwatch_reset ();
+       mwnodes_cnt = 0;
        for (int i = 0; i < MEMWATCH_TOTAL; i++) {
                struct memwatch_node *m = &mwnodes[i];
                uae_u32 size = 0;
                if (!m->size)
                        continue;
+               mwnodes_cnt++;
                while (size < m->size) {
                        memwatch_remap (m->addr + size);
                        size += 65536;
@@ -3490,58 +3524,130 @@ static void memwatch (TCHAR **c)
        memwatch_dump (num);
 }
 
+static void copymem(TCHAR **c)
+{
+       uae_u32 addr = 0, eaddr = 0, dst = 0;
+
+       ignore_ws(c);
+       if (!more_params (c))
+               return;
+       addr = readhex (c);
+       ignore_ws (c);
+       if (!more_params (c))
+               return;
+       eaddr = readhex (c);
+       ignore_ws (c);
+       if (!more_params (c))
+               return;
+       dst = readhex (c);
+
+       if (addr >= eaddr)
+               return;
+       uae_u32 addrb = addr;
+       uae_u32 dstb = dst;
+       uae_u32 len = eaddr - addr;
+       if (dst <= addr) {
+               while (addr < eaddr) {
+                       put_byte(dst, get_byte(addr));
+                       addr++;
+                       dst++;
+               }
+       } else {
+               dst += eaddr - addr;
+               while (addr < eaddr) {
+                       dst--;
+                       eaddr--;
+                       put_byte(dst, get_byte(eaddr));
+               }
+       }
+       console_out_f(_T("Copied from %08x - %08x to %08x - %08x\n"), addrb, addrb + len - 1, dstb, dstb + len - 1);
+}
+
 static void writeintomem (TCHAR **c)
 {
        uae_u32 addr = 0;
+       uae_u32 eaddr = 0xffffffff;
        uae_u32 val = 0;
        TCHAR cc;
        int len = 1;
+       bool fillmode = false;
+
+       if (**c == 'f') {
+               fillmode = true;
+               (*c)++;
+       } else if (**c == 'c') {
+               (*c)++;
+               copymem(c);
+               return;
+       }
 
        ignore_ws(c);
        addr = readhex (c);
-
        ignore_ws (c);
+
+       if (fillmode) {
+               if (!more_params (c))
+                       return;
+               eaddr = readhex(c);
+               ignore_ws (c);
+       }
+
        if (!more_params (c))
                return;
+       TCHAR *cb = *c;
        cc = peekchar (c);
-       if (cc == '\'' || cc == '\"') {
-               next_char (c);
-               while (more_params (c)) {
-                       TCHAR str[2];
-                       char *astr;
-                       cc = next_char (c);
-                       if (cc == '\'' || cc == '\"')
-                               break;
-                       str[0] = cc;
-                       str[1] = 0;
-                       astr = ua (str);
-                       put_byte (addr, astr[0]);
-                       xfree (astr);
-                       addr++;
-               }
-       } else {
-               for (;;) {
-                       ignore_ws (c);
-                       if (!more_params (c))
-                               break;
-                       val = readhex (c, &len);
-               
-                       if (len == 4) {
-                               put_long (addr, val);
-                               cc = 'L';
-                       } else if (len == 2) {
-                               put_word (addr, val);
-                               cc = 'W';
-                       } else if (len == 1) {
-                               put_byte (addr, val);
-                               cc = 'B';
-                       } else {
-                               break;
+       uae_u32 addrc = addr;
+       for(;;) {
+               uae_u32 addrb = addr;
+               *c = cb;
+               if (cc == '\'' || cc == '\"') {
+                       next_char (c);
+                       while (more_params (c)) {
+                               TCHAR str[2];
+                               char *astr;
+                               cc = next_char (c);
+                               if (cc == '\'' || cc == '\"')
+                                       break;
+                               str[0] = cc;
+                               str[1] = 0;
+                               astr = ua (str);
+                               put_byte (addr, astr[0]);
+                               xfree (astr);
+                               addr++;
+                               if (addr >= eaddr)
+                                       break;
+                       }
+               } else {
+                       for (;;) {
+                               ignore_ws (c);
+                               if (!more_params (c))
+                                       break;
+                               val = readhex (c, &len);
+
+                               if (len == 4) {
+                                       put_long (addr, val);
+                                       cc = 'L';
+                               } else if (len == 2) {
+                                       put_word (addr, val);
+                                       cc = 'W';
+                               } else if (len == 1) {
+                                       put_byte (addr, val);
+                                       cc = 'B';
+                               } else {
+                                       break;
+                               }
+                               if (!fillmode)
+                                       console_out_f (_T("Wrote %X (%u) at %08X.%c\n"), val, val, addr, cc);
+                               addr += len;
+                               if (addr >= eaddr)
+                                       break;
                        }
-                       console_out_f (_T("Wrote %X (%u) at %08X.%c\n"), val, val, addr, cc);
-                       addr += len;
                }
+               if (eaddr == 0xffffffff || addr <= addrb || addr >= eaddr)
+                       break;
        }
+       if (eaddr != 0xffffffff)
+               console_out_f(_T("Wrote data to %08x - %08x\n"), addrc, addr);
 }
 
 static uae_u8 *dump_xlate (uae_u32 addr)
@@ -4368,7 +4474,7 @@ static int process_breakpoint (TCHAR **c)
        return 1;
 }
 
-static void savemem (TCHAR **cc)
+static void saveloadmem (TCHAR **cc, bool save)
 {
        uae_u8 b;
        uae_u32 src, src2, len, len2;
@@ -4397,19 +4503,34 @@ static void savemem (TCHAR **cc)
                console_out_f (_T("Couldn't open file '%s'\n"), name);
                return;
        }
-       while (len > 0) {
-               b = get_byte_debug (src);
-               src++;
-               len--;
-               if (fwrite (&b, 1, 1, fp) != 1) {
-                       console_out (_T("Error writing file\n"));
-                       break;
+       if (save) {
+               while (len > 0) {
+                       b = get_byte_debug (src);
+                       src++;
+                       len--;
+                       if (fwrite (&b, 1, 1, fp) != 1) {
+                               console_out (_T("Error writing file\n"));
+                               break;
+                       }
+               }
+               if (len == 0)
+                       console_out_f (_T("Wrote %08X - %08X (%d bytes) to '%s'\n"),
+                               src2, src2 + len2, len2, name);
+       } else {
+               while (len > 0) {
+                       if (fread(&b, 1, 1, fp) != 1) {
+                               console_out (_T("Error reading file\n"));
+                               break;
+                       }
+                       put_byte (src, b);
+                       src++;
+                       len--;
                }
+               if (len == 0)
+                       console_out_f (_T("Read %08X - %08X (%d bytes) to '%s'\n"),
+                               src2, src2 + len2, len2, name);
        }
        fclose (fp);
-       if (len == 0)
-               console_out_f (_T("Wrote %08X - %08X (%d bytes) to '%s'\n"),
-               src2, src2 + len2, len2, name);
        return;
 S_argh:
        console_out (_T("S-command needs more arguments!\n"));
@@ -4953,8 +5074,8 @@ static void dma_disasm(int frames, int vp, int hp, int frames_end, int vp_end, i
        }
 }
 
-static uaecptr nxdis, nxmem;
-static bool ppcmode;
+static uaecptr nxdis, nxmem, asmaddr;
+static bool ppcmode, asmmode;
 
 static bool debug_line (TCHAR *input)
 {
@@ -4962,10 +5083,45 @@ static bool debug_line (TCHAR *input)
        uaecptr addr;
 
        inptr = input;
+
+       if (asmmode) {
+               if (more_params(&inptr)) {
+                       if (!_tcsicmp(inptr, _T("x"))) {
+                               asmmode = false;
+                               return false;
+                       }
+                       uae_u16 asmout[16];
+                       int inss = m68k_asm(inptr, asmout, asmaddr);
+                       if (inss > 0) {
+                               for (int i = 0; i < inss; i++) {
+                                       put_word(asmaddr + i * 2, asmout[i]);
+                               }
+                               m68k_disasm(asmaddr, &nxdis, 1);
+                               asmaddr = nxdis;
+                       }
+                       console_out_f(_T("%08X "), asmaddr);
+                       return false;
+               } else {
+                       asmmode = false;
+                       return false;
+               }
+       }
+
        cmd = next_char (&inptr);
 
        switch (cmd)
        {
+               case 'I':
+               if (more_params (&inptr)) {
+                       static int recursive;
+                       if (!recursive) {
+                               recursive++;
+                               handle_custom_event(inptr, 0);
+                               device_check_config();
+                               recursive--;
+                       }
+               }
+               break;
                case 'c': dumpcia (); dumpdisk (_T("DEBUG")); dumpcustom (); break;
                case 'i':
                {
@@ -5004,7 +5160,8 @@ static bool debug_line (TCHAR *input)
                case 'C': cheatsearch (&inptr); break;
                case 'W': writeintomem (&inptr); break;
                case 'w': memwatch (&inptr); break;
-               case 'S': savemem (&inptr); break;
+               case 'S': saveloadmem (&inptr, true); break;
+               case 'L': saveloadmem (&inptr, false); break;
                case 's':
                        if (*inptr == 'c') {
                                screenshot (1, 1);
@@ -5024,6 +5181,26 @@ static bool debug_line (TCHAR *input)
                                searchmem (&inptr);
                        }
                        break;
+               case 'a':
+                       asmaddr = nxdis;
+                       if (more_params(&inptr)) {
+                               asmaddr = readhex(&inptr);
+                               if (more_params(&inptr)) {
+                                       uae_u16 asmout[16];
+                                       int inss = m68k_asm(inptr, asmout, asmaddr);
+                                       if (inss > 0) {
+                                               for (int i = 0; i < inss; i++) {
+                                                       put_word(asmaddr + i * 2, asmout[i]);
+                                               }
+                                               m68k_disasm(asmaddr, &nxdis, 1);
+                                               asmaddr = nxdis;
+                                               return false;
+                                       }
+                               }
+                       }
+                       asmmode = true;
+                       console_out_f(_T("%08X "), asmaddr);
+               break;
                case 'd':
                        {
                                if (*inptr == 'i') {
index 723f52baa97467bfe7394e47522f4c7d29b803aa..c3db99ab6f0ce9cf16accd9ef8474cec331a08b5 100644 (file)
@@ -547,6 +547,7 @@ extern void m68k_disasm_ea (uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *sea
 extern void m68k_disasm (uaecptr addr, uaecptr *nextpc, int cnt);
 extern void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, int safemode);
 extern void sm68k_disasm (TCHAR*, TCHAR*, uaecptr addr, uaecptr *nextpc);
+extern int m68k_asm(TCHAR *buf, uae_u16 *out, uaecptr pc);
 extern int get_cpu_model (void);
 
 extern void set_cpu_caches (bool flush);
index 29317bbdf826996a4fbfc9c37dddf7648d47d1a5..8635057fb996dd7ac60c1f8fd0f56d55a57c7dcd 100644 (file)
@@ -1795,7 +1795,7 @@ static uaecptr ShowEA (void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode
                break;
        case absw:
                addr = (uae_s32)(uae_s16)get_iword_debug (pc);
-               _stprintf (buffer, _T("$%08x"), addr);
+               _stprintf (buffer, _T("$%04x"), (uae_u16)addr);
                pc += 2;
                break;
        case absl:
@@ -1870,7 +1870,7 @@ static uaecptr ShowEA (void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode
                break;
        case immi:
                offset = (uae_s32)(uae_s8)(reg & 0xff);
-               _stprintf (buffer, _T("#$%08x"), (uae_u32)offset);
+               _stprintf (buffer, _T("#$%02x"), (uae_u8)offset);
                addr = pc + offset;
                break;
        default:
@@ -5985,6 +5985,621 @@ static void disasm_size (TCHAR *instrname, struct instr *dp)
        }
 }
 
+static void asm_add_extensions(uae_u16 *data, int *dcntp, int mode, uae_u32 v, uae_u16 *ext, uaecptr pc, int size)
+{
+       int dcnt = *dcntp;
+       if (mode < 0)
+               return;
+       if (mode == Ad16) {
+               data[dcnt++] = v;
+       }
+       if (mode == PC16) {
+               data[dcnt++] = v - (pc + 2);
+       }
+       if (mode == Ad8r || mode == PC8r) {
+               data[dcnt++] = ext[0];
+       }
+       if (mode == absw) {
+               data[dcnt++] = (uae_u16)v;
+       }
+       if (mode == absl) {
+               data[dcnt++] = (uae_u16)(v >> 16);
+               data[dcnt++] = (uae_u16)v;
+       }
+       if ((mode == imm && size == 0) || mode == imm0) {
+               data[dcnt++] = (uae_u8)v;
+       }
+       if ((mode == imm && size == 1) || mode == imm1) {
+               data[dcnt++] = (uae_u16)v;
+       }
+       if ((mode == imm && size == 2) || mode == imm2) {
+               data[dcnt++] = (uae_u16)(v >> 16);
+               data[dcnt++] = (uae_u16)v;
+       }
+       *dcntp = dcnt;
+}
+
+static int asm_isdreg(const TCHAR *s)
+{
+       if (s[0] == 'D' && s[1] >= '0' && s[1] <= '7')
+               return s[1] - '0';
+       return -1;
+}
+static int asm_isareg(const TCHAR *s)
+{
+       if (s[0] == 'A' && s[1] >= '0' && s[1] <= '7')
+               return s[1] - '0';
+       return -1;
+}
+static int asm_ispc(const TCHAR *s)
+{
+       if (s[0] == 'P' && s[1] == 'C')
+               return 1;
+       return 0;
+}
+
+static int asm_parse_mode(TCHAR *s, uae_u8 *reg, uae_u32 *v, uae_u16 *ext)
+{
+       TCHAR *ss = s;
+       *reg = -1;
+       *v = 0;
+       *ext = 0;
+       if (s[0] == 0)
+               return -1;
+       // Dn
+       if (asm_isdreg(s) >= 0 && s[2] == 0) {
+               *reg = asm_isdreg(s);
+               return Dreg;
+       }
+       // An
+       if (asm_isareg(s) >= 0 && s[2] == 0) {
+               *reg = asm_isareg(s);
+               return Areg;
+       }
+       // (An) and (An)+
+       if (s[0] == '(' && asm_isareg(s + 1) >= 0 && s[3] == ')') {
+               *reg = asm_isareg(s + 1);
+               if (s[4] == '+' && s[5] == 0)
+                       return Aipi;
+               if (s[4] == 0)
+                       return Aind;
+               return -1;
+       }
+       // -(An)
+       if (s[0] == '-' && s[1] == '(' && asm_isareg(s + 2) >= 0 && s[4] == ')' && s[5] == 0) {
+               *reg = asm_isareg(s + 2);
+               return Apdi;
+       }
+       // Immediate
+       if (s[0] == '#') {
+               if (s[1] == '!') {
+                       *v = _tstol(s + 2);
+               } else {
+                       TCHAR *endptr;
+                       *v = _tcstol(s + 1, &endptr, 16);
+               }
+               return imm;
+       }
+       // Value
+       if (s[0] == '!') {
+               *v = _tstol(s + 1);
+       } else {
+               TCHAR *endptr;
+               *v = _tcstol(s, &endptr, 16);
+       }
+       int dots = 0;
+       for (int i = 0; i < _tcslen(s); i++) {
+               if (s[i] == ',')
+                       dots++;
+       }
+       while (*s != 0) {
+               // d16(An)
+               if (dots == 0 && s[0] == '(' && asm_isareg(s + 1) >= 0 && s[3] == ')' && s[4] == 0) {
+                       *reg = asm_isareg(s + 1);
+                       return Ad16;
+               }
+               // d16(PC)
+               if (dots == 0 && s[0] == '(' && asm_ispc(s + 1) && s[3] == ')' && s[4] == 0) {
+                       *reg = 2;
+                       return PC16;
+               }
+               // (d16,An) / (d16,PC)
+               if (dots == 1 && s[0] == '(' && !asm_ispc(s + 1) && asm_isareg(s + 1) < 0 && asm_isdreg(s + 1) < 0) {
+                       TCHAR *startptr, *endptr;
+                       if (s[1] == '!') {
+                               startptr = s + 2;
+                               *v = _tcstol(startptr, &endptr, 10);
+                       } else {
+                               startptr = s + 1;
+                               *v = _tcstol(startptr, &endptr, 16);
+                       }
+                       if (endptr == startptr || endptr[0] != ',')
+                               return -1;
+                       if (asm_ispc(endptr + 1) && endptr[3] == ')') {
+                               *reg = 2;
+                               return PC16;
+                       }
+                       if (asm_isareg(endptr + 1) >= 0 && endptr[3] == ')') {
+                               *reg = asm_isareg(endptr + 1);
+                               return Ad16;
+                       }
+                       return -1;
+               }
+               // Ad8r PC8r
+               if (s[0] == '(') {
+                       TCHAR *s2 = s;
+                       if (!asm_ispc(s + 1) && asm_isareg(s + 1) < 0 && asm_isdreg(s + 1) < 0) {
+                               if (dots != 2)
+                                       return -1;
+                               TCHAR *startptr, *endptr;
+                               if (s[1] == '!') {
+                                       startptr = s + 2;
+                                       *v = _tcstol(startptr, &endptr, 10);
+                               } else {
+                                       startptr = s + 1;
+                                       *v = _tcstol(startptr, &endptr, 16);
+                               }
+                               if (endptr == startptr || endptr[0] != ',')
+                                       return -1;
+                               s2 = endptr + 1;
+                       } else if ((asm_isareg(s + 1) >= 0 || asm_ispc(s + 1)) && s[3] == ',' || (asm_isdreg(s + 4) >= 0 || asm_isareg(s + 4) >= 0)) {
+                               if (dots != 1)
+                                       return -1;
+                               s2 = s + 1;
+                       } else {
+                               return -1;
+                       }
+                       uae_u8 reg2;
+                       bool ispc = asm_ispc(s2);
+                       if (ispc) {
+                               *reg = 3;
+                       } else {
+                               *reg = asm_isareg(s2);
+                       }
+                       s2 += 2;
+                       if (*s2 != ',')
+                               return -1;
+                       s2++;
+                       if (asm_isdreg(s2) >= 0) {
+                               reg2 = asm_isdreg(s2);
+                       } else {
+                               reg2 = asm_isareg(s2);
+                               *ext |= 1 << 15;
+                       }
+                       s2 += 2;
+                       *ext |= reg2 << 12;
+                       *ext |= (*v) & 0xff;
+                       if (s2[0] == '.' && s2[1] == 'W') {
+                               s2 += 2;
+                       } else if (s2[0] == '.' && s2[1] == 'L') {
+                               *ext |= 1 << 11;
+                               s2 += 2;
+                       }
+                       if (s2[0] == '*') {
+                               TCHAR scale = s2[1];
+                               if (scale == '2')
+                                       *ext |= 1 << 9;
+                               else if (scale == '4')
+                                       *ext |= 2 << 9;
+                               else if (scale == '8')
+                                       *ext |= 3 << 9;
+                               else
+                                       return -1;
+                               s2 += 2;
+                       }
+                       if (s2[0] == ')' && s2[1] == 0) {
+                               return ispc ? PC8r : Ad8r;
+                       }
+                       return -1;
+               }
+               s++;
+       }
+       // abs.w
+       if (s - ss > 2 && s[-2] == '.' && s[-1] == 'W') {
+               *reg = 0;
+               return absw;
+       }
+       // abs.l
+       *reg = 1;
+       return absl;
+}
+
+static TCHAR *asm_parse_parm(TCHAR *parm, TCHAR *out)
+{
+       TCHAR *p = parm;
+       bool quote = false;
+
+       for (;;) {
+               if (*p == '(') {
+                       quote = true;
+               }
+               if (*p == ')') {
+                       if (!quote)
+                               return NULL;
+                       quote = false;
+               }
+               if ((*p == ',' || *p == 0) && !quote) {
+                       TCHAR c = *p;
+                       p[0] = 0;
+                       _tcscpy(out, parm);
+                       my_trim(out);
+                       if (c)
+                               p++;
+                       return p;
+               }
+               p++;
+       }
+}
+
+static bool m68k_asm_parse_movec(TCHAR *s, TCHAR *d)
+{
+       for (int i = 0; m2cregs[i].regname; i++) {
+               if (!_tcscmp(s, m2cregs[i].regname)) {
+                       uae_u16 v = m2cregs[i].regno;
+                       if (asm_isareg(d) >= 0)
+                               v |= 0x8000 | (asm_isareg(d) << 12);
+                       else if (asm_isdreg(d) >= 0)
+                               v |= (asm_isdreg(d) << 12);
+                       else
+                               return false;
+                       _stprintf(s, _T("#%X"), v);
+                       return true;
+               }
+       }
+       return false;
+}
+
+static bool m68k_asm_parse_movem(TCHAR *s, int dir)
+{
+       TCHAR *d = s;
+       uae_u16 regmask = 0;
+       uae_u16 mask = dir ? 0x8000 : 0x0001;
+       bool ret = false;
+       while(*s) {
+               int dreg = asm_isdreg(s);
+               int areg = asm_isareg(s);
+               if (dreg < 0 && areg < 0)
+                       break;
+               int reg = dreg >= 0 ? dreg : areg + 8;
+               regmask |= dir ? (mask >> reg) : (mask << reg);
+               s += 2;
+               if (*s == 0) {
+                       ret = true;
+                       break;
+               } else if (*s == '/') {
+                       s++;
+                       continue;
+               } else if (*s == '-') {
+                       s++;
+                       int dreg2 = asm_isdreg(s);
+                       int areg2 = asm_isareg(s);
+                       if (dreg2 < 0 && areg2 < 0)
+                               break;
+                       int reg2 = dreg2 >= 0 ? dreg2 : areg2 + 8;
+                       if (reg2 < reg)
+                               break;
+                       while (reg2 >= reg) {
+                               regmask |= dir ? (mask >> reg) : (mask << reg);
+                               reg++;
+                       }
+                       s += 2;
+                       if (*s == 0) {
+                               ret = true;
+                               break;
+                       }
+               } else {
+                       break;
+               }
+       }
+       if (ret)
+               _stprintf(d, _T("#%X"), regmask);
+       return ret;
+}
+
+int m68k_asm(TCHAR *sline, uae_u16 *out, uaecptr pc)
+{
+       TCHAR *p;
+       const TCHAR *cp1;
+       TCHAR ins[256], parms[256];
+       TCHAR line[256];
+       TCHAR srcea[256], dstea[256];
+       uae_u16 data[16], sexts[8], dexts[8];
+       int dcnt = 0;
+       int cc = -1;
+       int quick = 0;
+       bool immrelpc = false;
+
+       if (_tcslen(sline) > 100)
+               return -1;
+
+       srcea[0] = dstea[0] = 0;
+       parms[0] = 0;
+
+       // strip all white space except first space
+       p = line;
+       bool firstsp = true;
+       for (int i = 0; sline[i]; i++) {
+               TCHAR c = sline[i];
+               if (c == 32 && firstsp) {
+                       firstsp = false;
+                       *p++ = 32;
+               }
+               if (c <= 32)
+                       continue;
+               *p++ = c;
+       }
+       *p = 0;
+
+       to_upper(line, _tcslen(line));
+
+       p = line;
+       while (*p && *p != ' ')
+               p++;
+       if (*p == ' ') {
+               *p = 0;
+               _tcscpy(parms, p + 1);
+               my_trim(parms);
+       }
+       _tcscpy(ins, line);
+       
+       if (_tcslen(ins) == 0)
+               return 0;
+
+       int size = 1;
+       int inssize = -1;
+       cp1 = _tcschr(line, '.');
+       if (cp1) {
+               size = cp1[1];
+               if (size == 'W')
+                       size = 1;
+               else if (size == 'L')
+                       size = 2;
+               else if (size == 'B')
+                       size = 0;
+               else
+                       return 0;
+               inssize = size;
+               line[cp1 - line] = 0;
+               _tcscpy(ins, line);
+       }
+
+       TCHAR *parmp = parms;
+       parmp = asm_parse_parm(parmp, srcea);
+       if (!parmp)
+               return 0;
+       if (srcea[0]) {
+               parmp = asm_parse_parm(parmp, dstea);
+               if (!parmp)
+                       return 0;
+       }
+
+       int smode = -1;
+       int dmode = -1;
+       uae_u8 sreg = -1;
+       uae_u8 dreg = -1;
+       uae_u32 sval = 0;
+       uae_u32 dval = 0;
+       int ssize = -1;
+       int dsize = -1;
+
+       dmode = asm_parse_mode(dstea, &dreg, &dval, dexts);
+
+
+       // Common alias
+       if (!_tcscmp(ins, _T("BRA"))) {
+               _tcscpy(ins, _T("BT"));
+       } else if (!_tcscmp(ins, _T("MOVEM"))) {
+               if (dmode >= Aind && _tcschr(dstea, '-') == NULL && _tcschr(dstea, '/') == NULL) {
+                       _tcscpy(ins, _T("MVMLE"));
+                       if (!m68k_asm_parse_movem(srcea, dmode == Apdi))
+                               return -1;
+               } else {
+                       TCHAR tmp[256];
+                       _tcscpy(ins, _T("MVMEL"));
+                       _tcscpy(tmp, srcea);
+                       _tcscpy(srcea, dstea);
+                       _tcscpy(dstea, tmp);
+                       if (!m68k_asm_parse_movem(srcea, 0))
+                               return -1;
+                       dmode = asm_parse_mode(dstea, &dreg, &dval, dexts);
+               }
+       } else if (!_tcscmp(ins, _T("MOVEC"))) {
+               if (dmode == Dreg || dmode == Areg) {
+                       _tcscpy(ins, _T("MOVEC2"));
+                       if (!m68k_asm_parse_movec(srcea, dstea))
+                               return -1;
+               } else {
+                       TCHAR tmp[256];
+                       _tcscpy(ins, _T("MOVE2C"));
+                       _tcscpy(tmp, srcea);
+                       _tcscpy(srcea, dstea);
+                       dstea[0] = 0;
+                       if (!m68k_asm_parse_movec(srcea, tmp))
+                               return -1;
+               }
+               dmode = -1;
+       }
+       
+       if (dmode == Areg) {
+               int l = _tcslen(ins);
+               if (l <= 2)
+                       return -1;
+               TCHAR last = ins[l- 1];
+               if (last == 'Q') {
+                       last = ins[l - 2];
+                       if (last != 'A') {
+                               ins[l - 1] = 'A';
+                               ins[l] = 'Q';
+                               ins[l + 1] = 0;
+                       }
+               } else if (last != 'A') {
+                       _tcscat(ins, _T("A"));
+               }
+       }
+
+       if (ins[_tcslen(ins) - 1] == 'Q') {
+               quick = 1;
+               ins[_tcslen(ins) - 1] = 0;
+       }
+
+       struct mnemolookup *lookup;
+       for (lookup = lookuptab; lookup->name; lookup++) {
+               if (!_tcscmp(ins, lookup->name))
+                       break;
+       }
+       if (!lookup->name) {
+               // Check cc variants
+               bool fp = ins[0] == 'F';
+               for (lookup = lookuptab; lookup->name; lookup++) {
+                       const TCHAR *ccp = _tcsstr(lookup->name, _T("cc"));
+                       if (ccp) {
+                               TCHAR tmp[256];
+                               for (int i = 0; i < (fp ? 32 : 16); i++) {
+                                       const TCHAR *ccname = fp ? fpccnames[i] : ccnames[i];
+                                       _tcscpy(tmp, lookup->name);
+                                       _tcscpy(tmp + (ccp - lookup->name), ccname);
+                                       if (tmp[_tcslen(tmp) - 1] == ' ')
+                                               tmp[_tcslen(tmp) - 1] = 0;
+                                       if (!_tcscmp(tmp, ins)) {
+                                               _tcscpy(ins, lookup->name);
+                                               cc = i;
+                                               // Bcc.B uses same encoding mode as MOVEQ
+                                               if (size == 0) {
+                                                       quick = 2;
+                                               }
+                                               immrelpc = true;
+                                               break;
+                                       }
+                               }
+                       }
+                       if (cc >= 0)
+                               break;
+               }
+       }
+
+       if (!lookup->name)
+               return 0;
+
+       int mnemo = lookup->mnemo;
+
+       int found = 0;
+       int sizemask = 0;
+       int tsize = size;
+       int unsized = 0;
+
+       for (int round = 0; round < 9; round++) {
+
+               if (!found && round == 8)
+                       return 0;
+
+               if (round == 3) {
+                       // Q is always LONG sized
+                       if (quick == 1) {
+                               tsize = 2;
+                       }
+                       bool isimm = srcea[0] == '#';
+                       if (immrelpc && !isimm) {
+                               TCHAR tmp[256];
+                               _tcscpy(tmp, srcea);
+                               srcea[0] = '#';
+                               _tcscpy(srcea + 1, tmp);
+                       }
+                       smode = asm_parse_mode(srcea, &sreg, &sval, sexts);
+                       if (immrelpc && !isimm) {
+                               sval = sval - (pc + 2);
+                       }
+                       if (quick) {
+                               smode = immi;
+                               sreg = sval & 0xff;
+                       }
+               }
+
+               if (round == 1) {
+                       if (!quick && (sizemask == 1 || sizemask == 2 || sizemask == 4)) {
+                               tsize = 0;
+                               if (sizemask == 2)
+                                       tsize = 1;
+                               else if (sizemask == 4)
+                                       tsize = 2;
+                       } else {
+                               continue;
+                       }
+               }
+               if (round == 2 && !found) {
+                       unsized = 1;
+               }
+
+               if (round == 4 && smode == imm) {
+                       smode = imm0;
+               } else if (round == 5 && smode == imm0) {
+                       smode = imm1;
+               } else if (round == 6 && smode == imm1) {
+                       smode = imm2;
+               } else if (round == 7 && smode == imm2) {
+                       smode = immi;
+                       sreg = sval & 0xff;
+               } else if (round == 4) {
+                       round += 5 - 1;
+               }
+
+               for (int opcode = 0; opcode < 65536; opcode++) {
+                       struct instr *table = &table68k[opcode];
+                       if (table->mnemo != mnemo)
+                               continue;
+                       if (cc >= 0 && table->cc != cc)
+                               continue;
+
+#if 0
+                       if (round == 0) {
+                               console_out_f(_T("%s OP=%04x S=%d SR=%d SM=%d SU=%d SP=%d DR=%d DM=%d DU=%d DP=%d SDU=%d\n"), lookup->name, opcode, table->size,
+                                       table->sreg, table->smode, table->suse, table->spos,
+                                       table->dreg, table->dmode, table->duse, table->dpos,
+                                       table->sduse);
+                       }
+#endif
+
+                       if (table->duse && !(table->dmode == dmode || (dmode >= imm && dmode <= imm2 && table->dmode >= imm && table->dmode <= imm2)))
+                               continue;
+                       if (round == 0) {
+                               sizemask |= 1 << table->size;
+                       }
+                       if (unsized > 0 && !table->unsized) {
+                               continue;
+                       }
+
+                       found++;
+
+                       if (round >= 3) {
+
+                               if (
+                                       ((table->size == tsize || table->unsized)) &&
+                                       ((!table->suse && smode < 0) || (table->suse && table->smode == smode)) &&
+                                       ((!table->duse && dmode < 0) || (table->duse && (table->dmode == dmode || (dmode == imm && (table->dmode >= imm && table->dmode <= imm2))))) &&
+                                       ((table->sreg == sreg || (table->smode >= absw && table->smode != immi))) &&
+                                       ((table->dreg == dreg || table->dmode >= absw))
+                                       )
+                               {
+                                       if (inssize >= 0 && tsize != inssize)
+                                               continue;
+
+
+                                       data[dcnt++] = opcode;
+                                       asm_add_extensions(data, &dcnt, smode, sval, sexts, pc, tsize);
+                                       if (smode >= 0)
+                                               asm_add_extensions(data, &dcnt, dmode, dval, dexts, pc, tsize);
+                                       for (int i = 0; i < dcnt; i++) {
+                                               out[i] = data[i];
+                                       }
+                                       return dcnt;
+                               }
+
+                       }
+               }
+       }
+
+       return 0;
+}
+
 void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr pc, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, int safemode)
 {
        uae_u32 seaddr2;